An Introduction to bada: A Developer's Guide 047097401X, 9780470974018

An expert introduction to Samsung's new mobile platform Bada is a new platform that runs on mass market phones and

811 57 7MB

English Pages 506 Year 2010

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

An Introduction to bada: A Developer's Guide
 047097401X, 9780470974018

Citation preview

Ben Morris et al

Introduction to bada A Developer’s Guide

01_974018-ffirs.indd ii01_974018-ffirs.indd ii

8/31/10 12:21 AM8/31/10 12:21 AM

Introduction to bada

01_974018-ffirs.indd i01_974018-ffirs.indd i

8/31/10 12:21 AM8/31/10 12:21 AM

01_974018-ffirs.indd ii01_974018-ffirs.indd ii

8/31/10 12:21 AM8/31/10 12:21 AM

Introduction to bada A Developer’s Guide Ben Morris and Manfred Bortenschlager, Jon Lansdell, Cheng Luo, Michelle Somerville With review and input by:

Hyeyoung Jung, HoKyung Kim, Hyun Gyoo Yook . . . and many others on the Samsung bada Team

A John Wiley and Sons, Ltd, Publication

01_974018-ffirs.indd iii01_974018-ffirs.indd iii

8/31/10 12:21 AM8/31/10 12:21 AM

This edition first published 2010 © 2010 Samsung Electronics, Co., Ltd. Registered office John Wiley & Sons Ltd, The Atrium, Southern Gate, Chichester, West Sussex, PO19 8SQ, United Kingdom Editorial office John Wiley & Sons Ltd, The Atrium, Southern Gate, Chichester, West Sussex, PO19 8SQ, United Kingdom For details of our global editorial offices, for customer services and for information about how to apply for permission to reuse the copyright material in this book please see our website at www.wiley.com/wiley-blackwell. The right of the author to be identified as the author of this work has been asserted in accordance with the Copyright, Designs and Patents Act 1988. All rights reserved. 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 or otherwise, except as permitted by the UK Copyright, Designs and Patents Act 1988, without the prior permission of the publisher. Wiley also publishes its books in a variety of electronic formats. Some content that appears in print may not be available in electronic books. Designations used by companies to distinguish their products are often claimed as trademarks. All brand names and product names used in this book are trade names, service marks, trademarks or registered trademarks of their respective owners. The publisher is not associated with any product or vendor mentioned in this book. This publication is designed to provide accurate and authoritative information in regard to the subject matter covered. It is sold on the understanding that the publisher is not engaged in rendering professional services. If professional advice or other expert assistance is required, the services of a competent professional should be sought. Samsung logo/images are reproduced with permission from Samsung Electronics (UK) Limited, a company incorporated in England and Wales under registered number 03086621 and whose registered office is at Samsung House, 1000 Hillswood Drive, Chertsey, Surrey KT16 0PS, UK. If you wish to reproduce the Samsung trademark you must contact Samsung Electronics for permission. ISBN 978-0-470-97401-8 A catalogue record for this book is available from the British Library. Typeset in 10.5/13 Palatino LT Std by Wiley Publishing, Inc. Printed in Great Britain by TJ International, Padstow, Cornwall

01_974018-ffirs.indd iv01_974018-ffirs.indd iv

8/31/10 12:21 AM8/31/10 12:21 AM

Publisher’s Acknowledgments Some of the people who helped bring this book to market include the following: Editorial and Production VP Consumer and Technology Publishing Director: Michelle Leete Associate Director — Book Content Management: Martin Tribe Associate Publisher: Chris Webb Executive Commissioning Editor: Birgit Gruber Publishing Assistant: Ellie Scott Project Editor: Juliet Booker Copy Editor: Sarah Price Marketing Senior Marketing Manager: Louise Breinholt Marketing Executive: Kate Parrett Composition Services Compositor: Erin Zeltner Proofreader: Susan Hobbs Indexer: Potomac Indexing, LLC

01_974018-ffirs.indd v01_974018-ffirs.indd v

8/31/10 12:21 AM8/31/10 12:21 AM

01_974018-ffirs.indd vi01_974018-ffirs.indd vi

8/31/10 12:21 AM8/31/10 12:21 AM

Contents

Contents

vii

About this Publication

xvii

Acknowledgments

xix

Preface

xxi

Introduction Overview of the Book What bada Is – and Isn’t

1 1 2

Just the Facts

3

Part I

About bada

Chapter 1

The Mobile Difference 1.1 The Mobile Context 1.2 Characteristics of Mobile Software 1.2.1 1.2.2 1.2.3

1.3 Chapter 2

7

Technological Differences Differences Related to Usability and User Experiences Differences in the Ecosystem

Mobile App Development Best-Practices

bada Basics

2.1

9 9 11 11 12 13

14 19

What You Will Learn What You Will Need

19 20

Your First bada Application

20

2.1.1 2.1.2 2.1.3 2.1.4 2.1.5

21 23 24 25 28

A Skeleton App Project Structure App Metadata Build and Run Standard Output

vii

02_974018-ftoc.indd vii02_974018-ftoc.indd vii

8/31/10 12:29 AM8/31/10 12:29 AM

viii

Contents 2.2

The Application UI

29

2.2.1 2.2.2

30

2.2.3 2.2.4

2.3

2.4 2.5 2.6

2.7 Chapter 3

3.2

3.3

3.4

33

2.3.1 2.3.2 2.3.3

33 35 38

A Simple UI Form Properties The Buddy List

Hooking Up Your Forms to Your Code The App Icon Becoming Multilingual in Three Easy Steps

41 46 47

2.6.1 2.6.2 2.6.3

48 49 50

Add New Languages Add Text for Each Language Use String Resource IDs in Your Code

From Idea to Published App

63 63 63

Expanding the Application Skeleton

64

3.1.1 3.1.2 3.1.3

65 65 69

Being Event Driven The Runtime App Lifecycle A Note about Frameworks

Using the UI Framework

70

3.2.1 3.2.2 3.2.3 3.2.4

70 71 75 77

Control Hierarchy More about UI Controls More about Frame More about Form

Using Graphics

78

3.3.1 3.3.2 3.3.3 3.3.4

79 80 83 88

More about Canvas Graphics Primitives Bitmaps and Images Colours

The BuddyFix UI Revisited

89

3.4.1 3.4.2 3.4.3

90 93 94

Adding an OptionMenu Adding a Soft Key Populating a List

97

What You Will Learn What You Will Need

97 97

Architecture Overview

98

4.1.1 4.1.2 4.1.3

02_974018-ftoc.indd viii02_974018-ftoc.indd viii

50

What You Will Learn What You Will Need

bada Fundamentals

4.1

31 32 33

UI Builder

Beyond the Basics

3.1

Chapter 4

Frames, Forms, and Controls Standard Elements of a Form – Indicator Bar, Title Bar, Soft Keys, Option Menu Handling Events Summary

bada Features A Short bada History The Layered Model of the bada Platform

98 99 101

8/31/10 12:29 AM8/31/10 12:29 AM

Contents 4.2

4.3

4.4

Chapter 5

103 104 104 104 106

C++ and bada The Native System Alternatives to Native C++ Pitfalls Native Idioms and Types Tutorials

bada Basic Functionality

117

4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6

117 118 121 121 124 124

Native Types Using Strings, Characters, and Unicode Using Buffers Collection Classes Using Dates and Times Using Numbers

Security and the Privilege Model in bada

125

4.4.1 4.4.2

126 127

Privileges in bada In Practice

129

What You Will Learn What You Will Need

129 129

What are the Services?

130

5.1.1 5.1.2 5.1.3 5.1.4 5.1.5

130 130 131 132 132

5.2

5.3

Location Service Social Service Content Service Commerce Service Single Sign On

How It Works

132

5.2.1 5.2.2

132

Device-to-Server Interaction – bada APIs bada Server and Third-Party Server Interaction with Open APIs

133

Services in Detail

135

5.3.1 5.3.2 5.3.3 5.3.4 5.3.5

135 140 147 150 153

Location as a Service Social Network Service – All Connected Content Service – Content is King Commerce Service – Make Your Own Business Component Setup

bada Namespaces

6.1 6.2 6.3

02_974018-ftoc.indd ix02_974018-ftoc.indd ix

103

4.2.1 4.2.2 4.2.3 4.2.4 4.2.5

Exploring bada Services

5.1

Chapter 6

bada Coding Idioms

ix

157

What You Will Learn What You Will Need

157 158

using Directives and Declarations How This Chapter Is Organised Namespaces in Detail

158 159 160

8/31/10 12:29 AM8/31/10 12:29 AM

x

Contents Part II

Recipes

211

Group 1

Fundamentals Recipe 1.1: Save to and Restore from the Registry

213 213

Problem Description The Recipe Hints, Pitfalls and Related Topics

Recipe 1.2: Use Error Handling in bada Problem Description The Recipe

Recipe 1.3: Use Two-phase Construction and Leak-free Destruction

217 217

224 224 224 228

Recipe 1.4: Create an AppControl to Interact with a Base Application

228

Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

228 228 235 236

Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Recipe 1.6: Parse XML Content Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Recipe 1.7: Get Dates and Times Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

UI Basics Recipe 2.1: Add a Form to a Frame-based App Problem Description The Recipe Hints, Pitfalls, and Related Topics

Recipe 2.2: Add Soft Keys to a Form and Get Actions Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipes

02_974018-ftoc.indd x02_974018-ftoc.indd x

217

Problem Description The Recipe Hints, Pitfalls, and Related Topics

Recipe 1.5: Create and Use a Timer

Group 2

213 213 216

236 236 236 239 239

239 239 239 243 243

243 243 243 250 250

251 251 251 251 255

255 255 255 258 258

8/31/10 12:29 AM8/31/10 12:29 AM

Contents Recipe 2.3: Add an Options Menu to a Form and Get User Selections Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipes

Recipe 2.4: Add a Simple Button Control to a Form Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Recipe 2.5: Pop Up a Message Box with Dismiss Problem Description The Recipe Hints, Pitfalls, and Related Topics

Recipe 2.6: Pop Up a Keypad and Get Input from It Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Recipe 2.7: Get Touch Events Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Recipe 2.8: Get Multi-touch Events Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Recipe 2.9: Create a Custom List Control Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Recipe 2.10: Implement a Form Manager Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Recipe 2.11: Get Soft Key and Hard Key Events Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

02_974018-ftoc.indd xi02_974018-ftoc.indd xi

xi

258 258 258 263 263

263 263 264 268 269

269 269 269 270

272 272 272 279 279

280 280 280 285 286

286 286 286 290 290

291 291 291 298 298

298 298 298 309 309

309 309 309 312 313

8/31/10 12:29 AM8/31/10 12:29 AM

xii

Contents Recipe 2.12: Use a Web Control Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Group 3

Extended UI and Sensors Recipe 3.1: Use Gesture Input and Motion UI

313 313 319 319

321 321

Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

321 321 326 327

Recipe 3.2: Get Device Orientation from the Magnetometer (Compass)

327

Problem Description The Recipe Hints, Pitfalls, and Related Topics

327 327 331

Recipe 3.3: Get Readings from the Tilt Sensor Problem Description The Recipe Hints, Pitfalls, and Related Topics

Recipe 3.4: Detect a Face from Video Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Recipe 3.5: Recognise a Face Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipes

Group 4

313

Multimedia Content Recipe 4.1: Use Bitmaps and Images

332 332 332 336

337 337 337 341 342

342 342 342 346 346

347 347

Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

347 347 351 351

Recipe 4.2: Draw Graphics Primitives

352

Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

352 352 356 356

Recipe 4.3: Open the Camera and Get and Display Live Frames Problem Description The Recipe

02_974018-ftoc.indd xii02_974018-ftoc.indd xii

356 356 356

8/31/10 12:29 AM8/31/10 12:29 AM

Contents Hints, Pitfalls, and Related Topics Related Recipes

Recipe 4.4: Use an Overlay Panel Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

Recipe 4.5: Record Audio from the Microphone or Audio Input Device Problem Description The Recipe Hints, Pitfalls, and Related Topics

Recipe 4.6: Play a Sound Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipes

Group 5

Networking Recipe 5.1: Create a Network Connection

360 360 361 365 366

366 366 366 369

369 369 370 373 374

375 375 375 375

Recipe 5.2: Use Secure Sockets

379

Recipe 5.3: Establish Normal and Pipeline Connection Modes for HTTP Sessions Problem Description The Recipe Hints, Pitfalls, and Related Topics

Recipe 5.4: Use Bluetooth Profiles Problem Description The Recipe

Recipe 5.5: Use Non-blocking and Blocking TCP and UDP Sockets Problem Description The Recipe Hints, Pitfalls, and Related Topics

Recipe 5.6: Set Up an Ad Hoc Wi-Fi Network Problem Description The Recipe Hints, Pitfalls, and Related Topics

02_974018-ftoc.indd xiii02_974018-ftoc.indd xiii

360 360

Problem Description The Recipe Problem Description The Recipe Hints, Pitfalls, and Related Topics

xiii

379 379 383

383 383 383 387

388 388 388

395 395 395 401

401 401 401 406

Recipe 5.7: Query a DNS Server

406

Problem Description The Recipe

406 406

8/31/10 12:29 AM8/31/10 12:29 AM

xiv

Contents Group 6

Maps and Location 6.1 Get Geographic Data from a Provider and Show a Map Problem Description The Recipe Hints, Pitfalls, and Related Topics

6.2 React to Location Changes

Group 7

411 411 411 411 413

414

Problem Description The Recipe Hints, Pitfalls, and Related Topics

414 414 415

Services and Social Networking 7.1 Create Content on the bada Server

417 417

Problem Description The Recipe Hints, Pitfalls, and Related Topics

417 417 421

7.2 Use the bada SNS Gateway to Access a Social Network Service such as Facebook Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipes

7.3 Send a Tweet from Twitter Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipe

7.4 Upload a Photo to Facebook Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipes

7.5 Get Notes from Facebook using RESTful APIs

422 422 422 429 430

430 430 430 434 434

434 434 434 438 438

439

Problem Description The Recipe Hints, Pitfalls, and Related Topics Related Recipes

439 439 446 446

7.6 Use the BuddyService to Add a Buddy

446

Problem Description The Recipe Hints, Pitfalls, and Related Topics

446 447 450

02_974018-ftoc.indd xiv02_974018-ftoc.indd xiv

8/31/10 12:29 AM8/31/10 12:29 AM

Contents Part III

Appendices

451

Appendix A Downloading and Installing the bada SDK

453

Appendix B A UML Primer B.1 Class Diagrams B.2 Sequence Diagrams

459 459 460

Appendix C A Software Engineering Model for Mobile App Development Some Mobile Software Engineering Best-practices Phase 1: Feasibility and Economic Efficiency Analysis

463 464 465

Stage 1.1: Requirements Engineering Stage 1.2: Design Drafting Stage 1.3: Early Prototyping Stage 1.4: User Acceptance Testing

Phase 2: Software Product Realisation Stage 2.1: Requirements Reviewing Stage 2.2: Design Detailing Stage 2.3: Defining Test Cases Stage 2.4: Programming Stage 2.5: Testing Stage 2.6: User Acceptance Testing

Phase 3: Distribution Stage 3.1: Marketing Stage 3.2: Preparing for Deployment Stage 3.3: Product Maintainance

Index

02_974018-ftoc.indd xv02_974018-ftoc.indd xv

xv

465 466 466 466

467 467 467 467 468 468 468

469 469 469 469

471

8/31/10 12:29 AM8/31/10 12:29 AM

02_974018-ftoc.indd xvi02_974018-ftoc.indd xvi

8/31/10 12:29 AM8/31/10 12:29 AM

About this Publication

At the end of last year, Samsung announced the launch of bada (the Korean word for ‘Ocean’), our very own native platform for application development. From the outset we planned to produce a beginners’ guide to bada; to get you started as quickly as we could, we decided to publish this book in two phases: first as an ePublication, and later as a full print version. The bada platform is a significant engineering feat. Its open APIs provide a platform for innovation comparable (and in many areas superior) to other platforms. However, open APIs alone do not make an ecosystem flourish. Like other successful platforms, bada is only part of a much bigger picture of company-wide innovation. Many other groups in Samsung have been involved in creating the end-to-end model that will help this platform deliver its technological promise. This book is your introduction to the bada platform. It will give you the information you need to get developing great applications on our powerful and well-abstracted SDK, making the most of the bada server, and getting your app into the hands of the user. The ePub version of this book and further resources can be accessed on our website developer.bada.com. Good luck, and we look forward to creating the new wave of the smartphone story with you.

The bada Team

xvii

03_974018-flast.indd xvii03_974018-flast.indd xvii

8/31/10 12:30 AM8/31/10 12:30 AM

03_974018-flast.indd xviii03_974018-flast.indd xviii

8/31/10 12:30 AM8/31/10 12:30 AM

Acknowledgments

The authors would like to thank . . . All at SERI, and especially our colleagues in the developer programme: PN for making it happen, THR for footing the bill, KB and JS for their recipes, and everyone who put up with our waywardness while we got the job done. And of course, the book would never have happened without JSH and his bada team at HQ. More personally . . . BM: To the Home team, you know who you are. CL: To Mom, Dad, Tong and Niuniu, with love. MB: To Natasha.

xix

03_974018-flast.indd xix03_974018-flast.indd xix

8/31/10 12:30 AM8/31/10 12:30 AM

03_974018-flast.indd xx03_974018-flast.indd xx

8/31/10 12:30 AM8/31/10 12:30 AM

Preface

Samsung announced its bada platform for mobile phones towards the end of 2009. New mobile platforms don’t come along every day, but 2009 was a busy year in mobile, and most attention remained with the existing platforms. Some avid Samsung watchers paid a little more attention and when the first bada phone, the Samsung Wave, previewed at Mobile World Congress in February 2010, you could begin to detect a little excitement. The bada SDK became publicly available for the first time in May 2010, and at the same time Samsung announced its Global Developer Challenge for bada apps, running until December 2010 with a prize pot of more than US$2.7 million, and a Grand Prize of US$300,000. That’s impressive! Even so, you could be forgiven for thinking that the mobile industry still does not really get bada. After all, who needs another smartphone OS? This book, we hope, will help put you in the company of those who do get bada. The rolling programme of Developer Days through the spring and early summer of 2010 has seen 3000 and more developers pick up tools, pick up phones, and get stuck in – from Paris to Peking to St Petersburg, Dublin to Seoul, Budapest to London, Jo’burg to Istanbul, not forgetting Munich, Madrid, and Milan. They get it. Less publicly, Samsung has been working with the kind of companies you’ve heard of – and probably a few you haven’t – to put their games, services, and cool apps onto bada phones and into SamsungApps, the brand new Samsung mobile app store. They get it too.

xxi

03_974018-flast.indd xxi03_974018-flast.indd xxi

8/31/10 12:30 AM8/31/10 12:30 AM

xxii

Preface

Wave is now in the shops, pitched squarely at the middle price-band – free on mid-priced contracts in UK and European markets, sub-£300 SIM-free in the UK – that’s less than US$500 USD. After Wave, the promise is that bada devices will push down below the US$200 price point. The real test now for bada is whether the market gets it. We’re betting it will. And we hope this book will inspire you to download the SDK, fire up your favourite editor, and start following along. Note: This publication refers to and is correct for the 1.0.0b3 SDK/IDE version.

The Authors

03_974018-flast.indd xxii03_974018-flast.indd xxii

8/31/10 12:30 AM8/31/10 12:30 AM

Introduction

This book is for developers. It will get you up and running with your first bada app, quickly. Looking beyond your first app, we hope this book will find a permanent place on your desk as a bada companion, with its overviews of the platform, the bada architecture, bada namespaces, application programming interfaces (APIs), and services – and above all with its recipes. These have been written by Samsung’s bada development team to give you more than 45 bestpractice examples of common bada APIs in use. You can learn from this code, and you can reuse this code. As for the goal of this book, we hope it’s clear – to introduce you to bada, and to make it as easy as possible to develop cool apps for bada phones.

Overview of the Book Developing for mobile is never trivial, whatever the platform. In Part 1 of the book, Chapter 1 runs through the issues that can bite you in mobile development. If you are a seasoned mobile developer, you may know the issues already. However, the boom in mobile app development has brought thousands of new developers into what used to be a niche market. If you are not one of those grizzled types who cut their baby teeth on embedded, eating ARM1 assembler for breakfast way back at the dawn of mobile, then this could be for you. Understanding the mobile difference, and becoming comfortable with it, is the essential starting point for doing mobile development. And if it helps, Chapter 1 also summarises some agile best-practice. Rules are good for breaking, as well as following, but in either case it’s good to know what they are. 1

The ARM RISC processor architecture, from UK company ARM Ltd, is overwhelmingly the most popular CPU choice for mobile hardware.

1

04_974018-intro.indd 104_974018-intro.indd 1

8/31/10 12:30 AM8/31/10 12:30 AM

2

Introduction

Chapter 2 and Chapter 3 show you just how easy it is to get started with bada, introducing the Eclipse-based development environment (IDE) and its Application Wizard to work up an example from bare-bones to first demo user interface (UI). Other topics covered include app deployment, and the bada developer portal, which provides the interface to app publishing through the Samsung Apps mobile store. Chapter 4 moves on to explore the bada platform architecture, and to introduce some important bada concepts – including bada’s C++ namespaces, class library, security/protection model, and programming idioms. Chapter 5 introduces bada services, one of bada’s exciting innovations, which integrate APIs for commerce, social networking, and other servicecentric features, with the platform APIs. This makes it easy to integrate services into your apps to stretch the boundaries of what users can do on mobile. NOTE: At the time of writing, some of these services are still restricted to partner developers, so keep an eye on breaking news on developer.bada.com as the developer story continues to unfold. To conclude Part 1 of the book, Chapter 6 provides an overview of each of the bada namespaces, highlighting the most important classes. Part 2 of the book presents a collection of recipes, organised into groups that show off the main bada features and provide you with ready-made code solutions to integrate into your own projects.

What bada Is – and Isn’t bada (with a small b) is a new open smartphone platform for Samsung massmarket mobile phones. ‘Open’ means that phones that ship with the bada platform are open to third-party developers, to create and publish native applications to phone users through the Samsung Apps application store. The vision of bada is that it is a ‘Smartphone for Everyone’. bada was created to provide a smartphone experience for more people. So, the major target customers for bada phones are not only techy early adopters, but also high school students. In a similar way, bada is not just targeted at existing geographical markets for smartphones but at developing markets too. To achieve this, bada is designed to provide powerful features while it supports a high level of configurability for a variety of hardware – from affordable to expensive and powerful. bada’s origins are in Samsung’s proprietary platform, which was first used in 2004. Since then, it has been adopted widely for handsets and is used by

04_974018-intro.indd 204_974018-intro.indd 2

8/31/10 12:30 AM8/31/10 12:30 AM

Introduction

3

numerous customers. For this reason, the proprietary platform has been successfully customised for a wide range of hardware as well as kernels. bada exploits the experience and knowledge gained throughout the history of Samsung’s mobile platform. Well-proven concepts are re-used supplemented with new insights and improvements. bada is highly configurable over various hardware configurations and kernels. For example, the first bada phone, Wave, is very high end with a 1 GHz CPU and a variety of sensors, while some of the later phones use less powerful hardware but are affordable to the mass market. Such configurability for a wide range of devices will make bada the best platform for mass-market phones. Another noteworthy bada feature is the integration of service APIs into the platform. Services include social networking, buddy lists that allow users to share real-time information with their friends, shopping and commerce APIs, location and points of interest, and even weather services. All are included out-of-the box and can be integrated into any third-party application (but note the current restrictions on access to non-partner developers). It’s worth emphasising that while bada is a new platform, much of the system underneath it (middleware and below) effectively re-uses enhanced version of components of Samsung’s proprietary platform. If the significance of that fact escapes you, think of it like this – Samsung shipped some 40 million phones a year in the touch-phone category in 2009. These are the phones that have made Samsung the global number-two handset vendor, pushing strongly to become global number-one. While bada won’t open the box on previously shipped phones, it opens the box on the next tensof-millions of phones that Samsung will ship in this category this year, extending to perhaps hundreds-of-millions over the next few years.2 This means that bada brings the mid-range, touch-phone category into your reach as an app developer, with a ready-made global audience, a proven middleware architecture, the proven touch-based UI, and potentially huge device numbers. And if you want to get a hands-on feel for what you can do with that, go into your local phone shop and play with the Samsung Wave (the first bada phone to ship). It makes for a compelling story.

Just the Facts bada is designed for simplicity. bada offers a small but carefully chosen set of APIs that enable app developers to create simple but powerful applications. Remember, bada apps are not aimed at power users, but at the mass market of ordinary users, using their phones to get everyday tasks done, to keep in touch with friends, and to browse, buy, and have fun in between. 2

For example, see web reports that quote Samsung estimates of 15 million bada phones shipping in 2010, and over 50 million in 2011, available from http://bit.ly/bNYBkG.

04_974018-intro.indd 304_974018-intro.indd 3

8/31/10 12:30 AM8/31/10 12:30 AM

4

Introduction

bada is More Than Just Another Smartphone OS bada contains a C++ class library as a framework layer, two more layers that provide features for controlling the device and accessing services, and a mobile operating system (OS) kernel. The bada API nicely abstracts from these layers and opens up the various functionalities to developers. bada is therefore (strictly speaking) not a mobile OS at all. Rather, it is a platform that includes the enhanced version of selected components of Samsung’s proprietary (and proven) middleware with a clean and well-structured C++ class library, supported by a commercial, mobile RTOS kernel.

bada is Open bada APIs are open to all. bada ships a free SDK, with open and free developer sign-up, and with publishing that is open to all via the Samsung Apps store. No, that doesn’t mean that bada is open-source – it just means that bada phones are open to third-party software, and any developer can be a third-party. At the time of writing, not every bada API is open to third-party developers; and in fact, some of the most interesting APIs are open only to partner developers. But this is an evolving position. In time, restrictions will be relaxed to make bada even more open when compared to other mobile platforms.

bada is Native bada is written in C++ on top of C/C++ middleware, and bada apps are written in C++. bada apps run in a native OS process, with access to native OS threading. bada also supports Flash and WebKit runtimes, and integrates Flash and WebKit support into its native APIs allowing inter-operation and multiple language code.

bada is Neat bada introduces some new, cool, network-based service APIs and integrates them seamlessly into the platform. These include buddy and social networking, location, and commerce and store APIs, which all interact with the bada Server to enable your app to track and exchange – for example – location data, including retrieving landmarks based on mobile location, and to swap instant messages and location data with the user’s buddies. You can set up an online store and use bada’s commerce APIs to interface your app with your store.

04_974018-intro.indd 404_974018-intro.indd 4

8/31/10 12:30 AM8/31/10 12:30 AM

Introduction

5

Note: At the time of writing, these APIs are restricted to partner developers.

bada is Easy Within reason. Native bada development is in C++, and arguably C++ is never easy. But bada does a good job of abstracting most of the complexity into its frameworks, where developers are insulated from it. bada makes good use of namespaces, is well-organised, and avoids the temptation of some complex features of C++. For example, templates are used very sparingly, and where they are used, they are used to good effect.

bada is Buzzword Compliant bada supports more buzzwords than we even want to try to list! Check out developer.bada.com.

04_974018-intro.indd 504_974018-intro.indd 5

8/31/10 12:30 AM8/31/10 12:30 AM

04_974018-intro.indd 604_974018-intro.indd 6

8/31/10 12:30 AM8/31/10 12:30 AM

PART

I About bada

05_974018-pp01.indd 705_974018-pp01.indd 7

8/31/10 12:32 AM8/31/10 12:32 AM

05_974018-pp01.indd 805_974018-pp01.indd 8

8/31/10 12:32 AM8/31/10 12:32 AM

CHAPTER

1 The Mobile Difference

Mobile is different. This chapter summarises what makes mobile software and development different from developing ‘conventional’ fixed software for desktops or web applications. We also suggest some software development best-practices that are particularly appropriate for mobile, and that can help you stay in control of your project.

1.1 The Mobile Context Some 20 years on from the birth of mobile, hardware and telecoms have changed out of all recognition. In all sorts of ways, mobile usage has also changed the way that people behave. Even so, the exploitation of mobile services has hardly begun. The apps revolution of the last several years, dominated by iPhone but certainly not limited to it, is a clear indicator of things to come. The real revolution, however, will be the arrival of apps and services for the mass market – and that’s what makes bada a potential game changer. From a practical perspective, the bada platform and accompanying ecosystem provide a great foundation for mobile development. So what makes mobile different? First, mobile hardware is different from desktop hardware. It’s not just that mobile phones fit in your pocket. The relentless drive to fit more and more functionality into smaller and smaller physical packages has led to almost 9

06_974018-ch01.indd 906_974018-ch01.indd 9

8/31/10 12:33 AM8/31/10 12:33 AM

10

Part I



About bada

continuous innovation. In consequence, mobile storage, mobile display, and mobile power technologies are different from their big brothers on the desktop. When you are developing for mobile, it is essential to understand how these differences can impact the way you design your apps and the way you write your code. Second, mobile usage is different. Users use mobile differently from the way they use fixed desktop devices, and they consume mobile services differently. Even the way that users buy and pay for their mobiles and mobile software is quite different from what happens on the desktop. In fact this is a crucial difference, because without the willingness of users to casually buy mobile software, there would be no apps revolution! Again, these are differences that will impact the way you design your apps and write your code. Above all, however, the mobile opportunity is different. Let’s illustrate that difference with an example – mobile services. We can divide these into two groups: new services that are only meaningful in a mobile context, and others that are traditionally used in fixed or web browser-based environments but that can now be extended to the mobile dimension. Location-based or map services are good examples of the first group. The idea of location-based services (LBS) has been around for over a decade now. Few would doubt the potential of such services to add unique value on mobile, where services and information can be delivered filtered for specific locations, providing information that is related to a user’s current position and that addresses an immediate need. However, only a few such services have turned out to be really big hits, and the most obviously successful example – in-car navigation – isn’t network based at all, and so delivers almost nothing of the real promise of LBS. The reason is simple. In the past, the technologies and ecosystem just were not ready. Today, however, everything is in place for LBS finally to deliver its promise. Examples of the second group are the booming social network services (SNS) stemming from the Web 2.0 movement that gave birth to blogs, Facebook, MySpace, YouTube, Twitter – you name it. Such applications and social networks can now increasingly be invoked and used from mobile handsets, either through web sites customised for mobile browsers or through standalone apps. But in these cases too the new dimensions that mobile brings have barely begun to be exploited. These examples also point to another difference between mobile apps and desktop applications. On the desktop, your word-processor or spreadsheet or database application, and your first-person shooter or adventure game, are big and complex, and the bigger they are, the better; they do everything, integrate with everything, and each would be very happy if it was the only application you ever needed. Mobile apps are almost exactly the opposite of this – they are small and focused pieces of software, designed to do one thing, and do it well.

06_974018-ch01.indd 1006_974018-ch01.indd 10

8/31/10 12:33 AM8/31/10 12:33 AM

Chapter 1



The Mobile Difference

11

The most successful mobile software respects the specific characteristics of mobile, including hardware constraints, different ecosystem structures (for example, shorter product lifetimes, but also shorter time to market), and the different usage context that dictates a different style of user experience. Ideally, whatever its application area, mobile software adds value by directly addressing a specific user need or by improving the mobile experience for the user – in terms of cost, effort, or time savings, increased flexibility, improved means of communication, or just more fun.

1.2 Characteristics of Mobile Software Mobile software has a number of characteristics that make it very different from desktop or web-based software, the most important being: 1. technological differences; 2. differences related to usability and user experiences; 3. differences in the ecosystem. In the following sections we touch on each of these topics in more detail.

1.2.1 Technological Differences Mobile handsets are getting steadily more powerful, with processor speeds of up to 1  GHz, multi-gigabyte memory and removeable memory of 32  GB or more now becoming common on high-end devices. Advances in display technology have also enhanced the user experience. The latest display technologies such as Samsung’s Super AMOLED1 deliver vastly better contrast, more efficient energy consumption and less sunlight reflection than older mobile displays. As network connections get faster, the services available to users have grown to include rich multimedia streaming and games, while user confidence in increased connection security has led to an explosion in mobile eCommerce and eTicketing apps. But it’s the advances in positioning technologies that have led to the biggest revolution in mobile apps. GPS2 is now standard even in low-end devices and bada offers developers an easy and powerful way to develop location-aware apps through its APIs for location services.

1

AMOLED stands for active-matrix organic light-emitting diode.

2

GPS stands for Global Positioning System, which enables ground positions to be calculated from satellite signals. GPS was originally developed by the US military and is maintained for civilian use by the US Government.

06_974018-ch01.indd 1106_974018-ch01.indd 11

8/31/10 12:33 AM8/31/10 12:33 AM

12

Part I



About bada

Advances in hardware provide new development possibilities. For example, sensor hardware has become commonplace on phones, which now include accelerometers, electronic compasses, and light sensors. Sensors provide functionality not available to fixed, desktop applications, for example tilt and shake user interaction with apps. Developing for mobile devices also provides some challenges to those used to creating desktop or web applications. Mobile hardware is improving rapidly, but compared to the desktop or to a typical server, phones are much less powerful with much less storage. On mobile, network connection is intermittent by design, compared to always-on Internet connections on the desktop. The way that the user interacts with a mobile device is also different; a smaller, touch screen and virtual keyboard input cannot offer the same experience as a full-sized keyboard and mouse. The most important, and often overlooked, difference in mobile compared to desktop development is energy consumption and the dependence on the battery. Battery capacity on mobile devices has increased, but so have the range of technologies that consume a lot of energy: GPS, Wi-Fi, Bluetooth, 3G, and multimedia support are prime examples, and some currently successful phones do not even make it through the day without needing recharging, and battery life is a frequent user complaint. Device manufacturers are doing their best to improve battery life, but software developers have their part to play through careful use of resources. Because mobile phones typically run for days or weeks or longer without being switched off, memory leaks, for instance, can seriously compromise the phone’s performance.

1.2.2 Differences Related to Usability and User Experiences New mobile technologies such as sensors and touch screens allow us to build better UIs and to represent information in more user-friendly and usable ways. In particular, Web 2.0 applications such as Facebook and Twitter can all now be accessed easily by mobile users using web pages designed for access onthe-go or by applications. Users may be able to do more with their devices, but they are still confronted with a huge range of different screen sizes, input methods, and UI ‘look and feel’ approaches that can make using mobile applications a frustrating experience. Developers who follow user interface guidelines, such as those provided by bada, will create easy-to-use, consistent applications on a particular platform, but there are still many platforms available. Several initiatives such as bada, the LiMo foundation, the Open Handset Alliance, and the Symbian Foundation show a trend towards open systems to facilitate harmonisation and the easing of application development and deployment. However, mobile developers will have to deal with the problem of incompatible platforms for some time to come.

06_974018-ch01.indd 1206_974018-ch01.indd 12

8/31/10 12:33 AM8/31/10 12:33 AM

Chapter 1



The Mobile Difference

13

Mobile applications are also used differently from their desktop equivalents. If you are mobile and want to find information about what is showing at the local cinema, or a review of a particular restaurant, you want to find that specific information quickly and don’t want to spend time searching through information you don’t need. Your attention span for using the application is limited, so you want to be presented with location-specific information. You might also be trying to find directions, using the mobile in sunlight, or somewhere with a lot of background noise, all environmental factors that need to be considered.

1.2.3 Differences in the Ecosystem Users expect to be able to find and download the software they want using their device when they’re on the move. Users should be served following a wish and use notion. When users wish to satisfy a current need they should be able to get and use corresponding information or services as fast and simply as possible. They want the purchasing and installation process to be simple, which is where a central one-stop-shop such as the Samsung Apps store comes in. Developers distribute their applications via Samsung Apps, one central location from which users of bada devices can purchase and download apps and make in-app purchases. One side-effect of this approach is that the network operator no longer plays the ‘gatekeeper’ role to their devices; the user can freely decide which apps to install. The lifetime and the time to market of a mobile app are substantially shorter than traditional software products and developers need to adapt. By having a central distribution system such as Samsung Apps, the developer can concentrate on creating and marketing their application in the knowledge that the distribution, purchasing, and revenue sharing model will be taken care of by the Samsung Apps store. This simplified model of application distribution also has other advantages. Users can be sure that applications will be independently tested and comply with a certain quality standard, will respect the integrity of the user’s data, and won’t spend their money on phone and data calls without asking. A further positive side-effect of the app store model is that costs for users become much more transparent. Network operators have recognised this trend and come up with contract bundles with flat data rates or volume packages in order to encourage the download of apps from stores. In the past, complex and non-transparent cost models discouraged users from using mobile services or downloading mobile apps because they feared exaggerated costs. With new all-inclusive pricing, downloading apps and invoking mobile services has become much more user-friendly and thus accepted. The bada platform in combination with Samsung Apps represents an ecosystem that addresses, exploits, and, in fact, shapes some of the differences that we have outlined in this chapter. Figure 1.1 summarises what the bada ecosystem stands for.

06_974018-ch01.indd 1306_974018-ch01.indd 13

8/31/10 12:33 AM8/31/10 12:33 AM

14

Part I



About bada

Figure 1.1 The bada ecosystem.

At one end of the chain are the developers or application providers who want to develop applications. At the other end are the users or customers who want to use mobile apps. Along this chain Samsung provides three core building blocks that foster the bada ecosystem. Central to it is the bada platform, which is the execution environment deployed on mobile handsets. This platform not only covers the mobile part but also allows seamless access to the bada Server as you will find out later in Chapter 5. Powerful and well-abstracted APIs are exposed as an open SDK to developers. In addition to that, the left block in Figure 1.1 covers a large number and variety of technical support resources, such as training material, tutorials, sample code, tech blogs, videos, and the API reference documentation. The right block is the application store Samsung Apps that allows you to certify and publish your apps. Once your app is ready for publication, you can decide if – via the store – you want to sell your app or give it away for free, or however else you want to become rich and famous.

1.3 Mobile App Development Best-Practices We argued that mobile apps have some specific characteristics that make them different from conventional software. Mobile markets are also different and develop at a faster pace. Hence, in order to create successful mobile solutions or applications, we recommend deploying some best-practices during development. In the appendix we provide an example of a full software engineering process for mobile applications. Of course, you can follow any process you prefer or develop your software without following any process at all. There is a range, from strict waterfall model to cowboy coding. As a rule of thumb the more complex a project is and the more coordination it requires, the more formalisation is advisable in terms

06_974018-ch01.indd 1406_974018-ch01.indd 14

8/31/10 12:33 AM8/31/10 12:33 AM

Chapter 1



The Mobile Difference

15

of processes. Experience has shown that so-called agile software development processes are very appropriate for fast-paced software, which mobile apps definitely are. In the agile manifesto3 software engineering experts have summarised the key factors that should help to produce better software faster and more reliably. They state that agile development is about focus on result. This means executable software should be built as soon as possible, which is the primary measure of progress. Software should be built incrementally starting from its core functions over various iterations. Tool and process support is relevant but must be appropriate to the solution in order to avoid unnecessary overhead. Finally software engineering is about people working together. Hence, communication – ideally in a face-to-face and spoken way – is at the core of agile development. This not only refers to the project team but also, and just as importantly, to the stakeholders, clients, and future end-users. In line with this, we would like to add to this recommendation an emphasis on using as much prototyping and diverse testing as possible throughout the whole development, where both are integral parts of and inherently supported by the bada platform and its development tools. Prototypes can be exploited in nearly any phase during the development of mobile software solutions. They are primarily helpful for eliciting requirements or to get a common understanding with various stakeholders early in the project. Testing certainly is not unique to mobile software engineering but must be treated and executed differently in mobile development. This is an effect of various issues related to mobile software such as the heterogeneity of hardware and devices, the dependence on context factors that are difficult to test on simulators (e.g. geographic locations), and the phenomenon of the discrepancy between simulator and real device behaviour. The bada toolset provides means to support both. First, the UI Builder, which is integrated into the bada IDE, allows building simple mock-up prototypes easily and quickly. Developers can use this WYSIWYG tool to create first ‘clickable’ demos by visually placing a variety of UI controls on the device screen. A second convenient tool is the Event Injector that comes with the bada Simulator. This is useful for simulating a broad variety of context data. Incoming calls, text messages, and battery level can be tested, as well as location and sensors, including acceleration, tilt, compass, and proximity. It is always difficult to test mobile apps in a simulator because obviously you are missing all the context data, which is so necessary. By far the more expensive and complex type of test is deployment on real devices and test-runs in the real-world context. With the bada Event Injector (see Figure 1.2), a lot of this effort can be shifted to Simulator tests, making system tests less time consuming and cheaper.

3

See http://www.agilemanifesto.org/.

06_974018-ch01.indd 1506_974018-ch01.indd 15

8/31/10 12:33 AM8/31/10 12:33 AM

16

Part I



About bada

Figure 1.2 The bada Event Injector.

But let us return to the ideas postulated by the agile manifesto. Often, ‘agile’ is misused to describe everything that does not have clear rules or a process. We would rather call this ‘cowboy coding’. Agile cannot be equated to chaos, or lack of rules or discipline. Agile app development does propose following some simple maxims and recommendations. So, let us describe some rules. We do so by listing a toolbox of some bestpractices coming from various agile methodologies such as Scrum, Test-driven Development, eXtreme Programming, and Crystal. Again, the core cornerstones are focus on results, incremental iterations, appropriateness of the means, and communication. The following best-practice recommendations all deal with one or more of these cornerstones: ■■

Focus on results more than on processes. Every procedure or means that does not help to achieve the goal of the software project should be cut off. The more complex a project, the more tools, rules, and formalisms it will require.

■■

Plan your software development into cycles or iterations. Identify the core and most critical components and priorities, and start with the most important ones (‘first things first’).

06_974018-ch01.indd 1606_974018-ch01.indd 16

8/31/10 12:33 AM8/31/10 12:33 AM

Chapter 1



The Mobile Difference

■■

Be tolerant towards change (changing requirements and change requests). Avoid rigid or inflexible structures, processes, tools, or methods.

■■

Try to produce executable software at the end of every iteration.

■■

Treat each iteration as an increment to the final software product.

■■

Try to keep design and software simple. Have possible extensions in mind but focus on producing executable code at least at the end of each iteration (‘keep it short and simple – KISS’).

■■

Make use of early feedback from various stakeholders, such as your client or end-users. User acceptance tests could possibly be integrated into every iteration.

■■

In the early stages, even use paper and pen to sketch software designs or early prototypes.

■■

Make use of a test-oriented development where you write the test cases first, at least for core or critical code parts.

■■

Build and integrate tested parts frequently (e.g. daily).

■■

Set up communication channels such that close contact with client and end-users is possible.

■■

Try to have regular, frequent, and brief intra-team communication without a formal overhead (e.g. daily stand-up meetings).

■■

Establish and publish team and project rules – such as a communication etiquette or coding standards.

■■

Conduct code reviews or pair programming sessions for core or critical code parts.

■■

Make sure you have efficient knowledge transfer within the team but also to client and user. This may not always be applicable or sensible. Sometimes this knowledge transfer may also be unidirectional.

■■

Use visualisation for your communication. Use, for instance, a visible whiteboard accessible to everyone in the team for sketching the tasks or features, and development progress.

■■

Although some form of documentation is necessary, keep it to a minimum: only as much as is necessary. And beware of over-specification.

17

Again, please bear in mind that you do not have to stick to the mobile software engineering best-practices outlined here. This is simply advice and something you can stick to.

06_974018-ch01.indd 1706_974018-ch01.indd 17

8/31/10 12:33 AM8/31/10 12:33 AM

06_974018-ch01.indd 1806_974018-ch01.indd 18

8/31/10 12:33 AM8/31/10 12:33 AM

CHAPTER

2 bada Basics

This chapter gets straight down to the essentials of developing native bada applications in C++. We’ll see just how easy it is to get a first skeleton application up and running on the bada Simulator. To start with, this little app doesn’t do much – think Hello World! But this is the code at the heart of every bada app, and as we’ll see in the next few chapters, bada makes it easy to build up from this basic skeleton to create a full-featured, native application. Note: At the time of writing the SDK version is 1.0.0 beta3. Current SDKs install on Microsoft Windows only. It’s likely that bada will support other development options eventually, but nothing is currently announced. The Simulator launches from the Eclipse-based bada IDE, which is included in the SDK.

What You Will Learn This chapter aims to get you started quickly. You will learn: ■■

How to create a simple application using the Application Wizard.

■■

How to add a simple UI using UI Builder.

19

07_974018-ch02.indd 1907_974018-ch02.indd 19

8/31/10 12:34 AM8/31/10 12:34 AM

20

Part I



About bada

■■

How to use the developer and publishing services provided by the bada developer portal.

■■

How to build for and deploy to a phone.

What You Will Need This book assumes beginner’s C++ skills. If you don’t know C++, don’t give up: bada works hard to make the app developer’s life as easy as possible. If you have experience using any modern programming language, a good C++ primer should be enough to get you up and running. By the way, don’t worry if you are new to mobile development. As we saw in the previous chapter, there are some things that make mobile unique, and different from the world of the desktop. We’ll highlight those issues as they arise in the context of each chapter.

2.1 Your First bada Application Native bada apps are C++ executables that combine the code that you write with framework code. Because the bada frameworks take care of the basic functionality that every app requires, there is very little code required to create a minimal app, as we will see. To start with, we will build for the bada Simulator only. Later in the chapter we’ll dig a little deeper and show you how to build for (and deploy to) a real bada phone. Because bada is highly modular, most of your time as a developer will be spent connecting together the pieces while the bada frameworks do the heavy lifting for you. As you might expect, all bada applications are fully graphical programs. In fact, one easy way to think of a bada application is as a GUI that does something. For any app, the GUI is where the user and the app meet. It’s the GUI that presents the application functionality to the user, and the GUI that allows the user to control that functionality. In fact for the user, your GUI is your app, and to a large degree determines the complete app experience. All bada apps that use the standard UI elements share the distinctive lookand-feel and behaviour of the bada UI and application frameworks. When you need more customised elements, you can derive your own and extend the default behaviour. Of course, there may be times when you want complete UI control (in a game, for example), and don’t want the standard look and feel. In that case bada allows you to write directly to the full-screen display to construct your own UI from scratch.

07_974018-ch02.indd 2007_974018-ch02.indd 20

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

21

But that’s enough of an introduction! If your C++ is rusty, this is a good time to get out your favourite C++ primer. Then fire up the bada IDE, and follow along. Note: The bada IDE is included in the SDK and is based on the industrystandard Eclipse IDE, see eclipse.org, and includes the Sourcery G++ GNU Toolchain, including C++ compilers for Win32 Simulator targets and ARM core phone targets. The SDK adds the bada header files, libraries, documentation, and code example and sample programs. See the appendices for more information about obtaining and installing the SDK. Installation is usually straightforward; for a normal setup, no manual configuration or intervention is required.

2.1.1 A Skeleton App Creating a new app is easy – the Application Wizard does all the hard work for you, and generates complete C++ skeleton code (.h header and .cpp source files), together with all the additional files the app requires. Let’s try it out. Launch the bada IDE, and select File | New | bada Application Project to pop up the Project Wizard. Give your project a name – we call ours BuddyFix – and choose Application | bada Form Based Application in the Project type panel (see Figure 2.1).

Figure 2.1 Creating a new bada project in the IDE.

07_974018-ch02.indd 2107_974018-ch02.indd 21

8/31/10 12:34 AM8/31/10 12:34 AM

22

Part I



About bada

Note: BuddyFix is the name of the project we use as a running example throughout this book, showing you how to build it up from scratch. To start with, BuddyFix has only rudimentary functionality, but eventually it will be a useful little application that enables you to swap live location information with selected ‘buddies’. Select Next, and accept the default SDK Root path. This just tells the build tools where to find common headers and libraries; modify the path if you have multiple SDK versions installed. Finally, check the phone model you want to build for (at the time of writing, the default is Wave) (see Figure 2.2). To get started, that’s all you need. There are more options available (you can explore them by choosing Next), but for now you can select Finish and let the Wizard do its work. In the Project Explorer pane, you’ll see that a folder has been created, named with the project name you specified. Inside is a basic skeleton app. Let’s look at it.

Figure 2.2 Setting the default SDK root path. We’re using the default.

07_974018-ch02.indd 2207_974018-ch02.indd 22

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

23

2.1.2 Project Structure Note: When you start the IDE, you can choose the workspace in which Eclipse will create new folders and look for existing project files. You can switch between workspaces at any time by choosing File | Switch Workspace from the IDE main menu. In your workspace, you will see a folder named BuddyFix (or the name you chose for your new project). Inside it you’ll see some subfolders (see Figure 2.3). As summarised in Table 2.1, the folder structure is as follows: ■■

The /inc and /src folders are where the generated C++ code files for your project are saved; .h files in /inc and .cpp files in /src.

■■

The /Home folder is the filesystem root for any data files or folders your app reads or writes.

■■

The /Icons folder is where you should store the icons used by your app, and it’s where the Wizard copies the default app icon – which you should change for your own artwork, of course, when you create a real project.

■■

The /Res folder is where your application keeps resource files that it uses. We will see how resources are used when we create the BuddyFix UI.

Figure 2.3 The BuddyFix folder and subfolders.

07_974018-ch02.indd 2307_974018-ch02.indd 23

8/31/10 12:34 AM8/31/10 12:34 AM

24

Part I



About bada

Note that /Icons, /Home, and /Res are also created as folders on a real device when you install your app. On a phone, /Icons and /Res are read-only ‘system’ locations, while /Home is readable and writeable, and private to your application. Note: In the IDE, the Project Explorer view also shows an /Includes folder, which is a virtual folder that maps all include paths for your project. It is not a physical folder in your Windows filesystem. Project Explorer also hides some files that you will see in your Windows filesystem, with names like .badaprj, .cproject, and .project. These are standard Eclipse house-keeping files, which you can ignore.

Table 2.1

Project folders generated by the Wizard.

/Home

Root folder of the application private data area, which provides dedicated (and protected) file system storage. The folder is empty until the app creates and saves file data, but always exists, even if not used by the app

/Icons

Contains default .png app icon and splash screen files, which you should replace with your own custom graphics

/Res

Contains all resources used by the app, typically Forms and Strings. Forms are defined by XML definition files, and partitioned into display resolution-specific subfolders if you choose to target phones with different display resolutions. For BuddyFix, the supported resolution is 480 × 800 pixels, i.e. Wide VGA (WVGA)

/inc

Contains the skeleton app’s .h header files

/src

Contains the skeleton app’s .cpp files, including an Entry file that defines the app entry point to the framework. This is generated code that you will not need to modify

2.1.3 App Metadata There are two important files that we haven’t mentioned yet, application. xml and manifest.xml. The application.xml is generated by the Wizard, and placed into your project root directory. The manifest.xml is ideally created by using the Application Manager on the developer.bada.com web site; alternatively, you can use the default file created by the Wizard.

07_974018-ch02.indd 2407_974018-ch02.indd 24

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

25

These are metadata files and are essential to your project. They declare application information used to create your final app package – the app name and version, vendor name, and so on – as well as critical information about the APIs that your app uses and any security permissions, known as privileges in bada, that are required to use them. Privileges are part of the bada security model, and we will look at them in detail in Chapter 4. When you start a real project, you’ll need to create a custom version of the manifest using the tools that are available through your account on the bada developer portal (see Section 2.7). But to start with we needn’t worry about these details at all; the default metadata files generated by the Application Wizard will be fine to get started. application.xml

Used by the app packaging tools to create an installable package. Declares the app name, description, vendor, and version; identifies the app icon files. manifest.xml

Used for privilege checking by the certification process. Declares app properties including keys and IDs; required device features, for example CPU type, minimum heap size, screen size, sensors used; and required privileges. Note: If you’ve done any widget development, then application.xml will look familiar; it’s the equivalent of the config.xml file that defines a W3C-style1 widget package; and if you’ve developed for Android, manifest.xml does a similar job to the Android manifest file.

2.1.4 Build and Run Although we have done nothing more than run the Wizard, we have enough code to build and launch a first, skeleton version of our app. Let’s verify that the code builds. In the IDE, select your project by name in Project Explorer. From the menu bar select Project | Build Project, and your project should compile and link (see Figure 2.4).

1

See www.w3.org.

07_974018-ch02.indd 2507_974018-ch02.indd 25

8/31/10 12:34 AM8/31/10 12:34 AM

26

Part I



About bada

Figure 2.4 Building the project.

When your project has successfully built, a Binaries folder will display in Project Explorer, which maps to the.Simulator-Debug directory in your Windows filesystem, where the project binary and object files are stored. To launch your app, select your project by name in Project Explorer. From the menu bar select Run | Run As | 1 bada Simulator Application from the pop-down menu. The bada Simulator will run. We chose Wave as the phone model when we created our project, so what we see is a good approximation of Wave, running on the PC screen. The Simulator launches and initialises, briefly displays the phone home screen, and then launches our app (see Figure 2.5). Note: The Application Wizard sets the application Title bar to ‘Hello bada!’ for any app generated with the Form Based Application option, and launches with an OK button when the app runs. This is a bit confusing, because it’s not obvious that it’s our app that’s running. But take our word for it – it is!

07_974018-ch02.indd 2607_974018-ch02.indd 26

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

27

Figure 2.5 Our app running in the Simulator.

To close the app, select the phone’s Power/End key on the Simulator. Your app will close, and you will be returned to the home screen. Select the Menu key to go to the Application Manager. You’ll see your app displayed there in the icon menu list, using the default app icon (see Figure 2.6). Note: When BuddyFix launched, you may have noticed that a splash screen was briefly displayed before the application was shown, based on splash. png, a default file in the /Icons folder. You can change the image that’s displayed by changing this file. The splash screen is a customisable property of your bada project – it is set in the same way as setting your app icon. By the way, the splash screen is displayed to fill any delay while your app is launched. Delay may occur for a number of reasons, depending on the load on the phone at any time. The splash screen is not displayed by the app itself to hide a delay while the app initialises. And, in fact, you should design your app to postpone doing any initialisation which might cause perceptible delay in showing its main screen. You can do this either by performing such initialisation in the background using multi-threading techniques, or by deferring this deeper initialisation until the app has launched, or both. A hint: in order to pass the certification process a bada app must have its own splash screen and app icon.

07_974018-ch02.indd 2707_974018-ch02.indd 27

8/31/10 12:34 AM8/31/10 12:34 AM

28

Part I



About bada

Figure 2.6 BuddyFix showing in the main menu.

2.1.5 Standard Output One useful view in the Eclipse IDE is the Output pane. When you launch an app in the Simulator, the system logs an ‘Application started’ message, and when you close the app, the system logs an ‘Application finished’ message: 0010.200,INFO,P26,T-01,A-01,OspMain (24) > Application started. 0014.030,INFO,P26,T-01,A93,OspMain (39) > Application finished.

Between these log points, you can output your own printf-like logging statements to trace your app’s behaviour at runtime, using bada’s logging macros, AppLog(), AppLogDebug(), and AppLogException(). For example, to output a simple log message, add the line: AppLog(“This message will display in the output view”);

Log files can be exported to simple text files with a .log suffix. In the Output pane, once your application is running, select the second icon on the left (as indicated in Figure 2.7); a dialog is invoked that allows saving the output into a log file on your development machine.

07_974018-ch02.indd 2807_974018-ch02.indd 28

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

29

Figure 2.7 Output pane of the bada IDE.

Log messages are also written by the assert macros AppAssert() and AppAssertf(), which test the truth (or falsity, respectively) of a condition, and by the exception handling macros, which we look at in detail in Chapter 4. The debugging macros are described in the SDK Help, select Help | Help Contents | bada Developer Guide in the IDE.

2.2 The Application UI We’ve said that a bada application can be thought of as a GUI that does something, where the GUI is the public face that your app shows to the user. Before getting down to practicalities and showing you how to build a simple GUI, let’s fill in some background. Depending on its complexity, an application may require only a single screen – a simple calculator layout, for example, for a Calculator app. Or it may require multiple screens such as an Address Book app, which might organise its main screen as a scrolling list of name and address entries, with a details screen to display details of a single complete entry, and editing screens to enable editing of entry details, labels, and so on. Getting your GUI design right is one of the most important tasks you’ll face as an app developer. Lots has been written about the art of good UI design, and a lot has been written about the special case of good mobile UI design.2 Two attributes that characterise the best are: fanatical attention to detail and ruthless simplification. It is important, too, to understand your app GUI in the context of the platform look-and-feel. Remember that bada is designed to push the smartphone experience down from the high end into the midrange. This influences the design of the bada touch UI, and in turn it should influence your GUI design. 2 Scott Jensen’s The Simplicity Shift (Cambridge University Press, 2002) is an excellent corrective to engineering-led design habits. Christian Lindholm et al., Mobile Usability: How Nokia Changed the Face of the Mobile Phone (McGraw-Hill, 2003) provides fascinating case studies in the evolution of first- and second-generation mobile phone UIs. Barbara Ballard, Designing the Mobile User Experience (Wiley, 2007), is a good overview text. And no app developer should be without Bill Moggridge, Designing Interactions (MIT Press, 2007). There’s also a wealth of material on the Web that discusses the general principles of mobile UI design, including some excellent documentation published for other mobile platforms you may be familiar with, relevant to all mobile app development, whatever the platform.

07_974018-ch02.indd 2907_974018-ch02.indd 29

8/31/10 12:34 AM8/31/10 12:34 AM

30

Part I



About bada

While there is no substitute for getting your hands on a real device, the following bada design points are worth bearing in mind: ■■

Touch – finger-based direct manipulation including multi-touch, pinching and swiping, and of course tactile feedback.

■■

Simplicity – simple screen layout, relatively large and bold fonts, large GUI elements for interaction, large simple icons, limited customisation, simple menus.

■■

Bright and bold – making the most of superAMOLED display technology, high contrast, vivid colours, saturated blacks (and by the way, dark colour schemes are preferred to light, because with AMOLED technology dark pixels consume less power than light pixels).

■■

Extended user input – as well as touch and hard keys, the touch UI supports gestures (physical motions including tapping on the case, rotating the phone, snap and shake), and even face detection.

■■

Multiple display sizes and resolutions – WVGA (Wide VGA) 480 × 800, WQVGA (Wide Quarter VGA) 240 × 400.

You can find detailed UI guidelines in the SDK Help. Select Help | Help Contents | bada Application UI Guide in the IDE.

2.2.1 Frames, Forms, and Controls The GUI is not just what you see on the screen. The simplicity of bada’s touch UI look-and-feel extends to the architecture beneath it, and to the concepts that motivate the architecture. While bada won’t design your GUI for you, it does provide a simple and standardised GUI architecture for your app to use. You can think of everything your app displays as being organised in a hierarchical tree. The root of the tree is the application Frame. Within every app, the Frame is the top-level container to which all GUI elements are added. More formally, the Frame class encapsulates the device display, and plays the role of the application’s top-level window, of which there is exactly one per application. All applications have a Frame, and you don’t need to do anything to create it or set it up. It’s all taken care of by the framework. Within the Frame, what the GUI displays is based on a simple metaphor of Forms as containers for standard GUI elements. A Form implements a single application screen, and an app can include as many Forms as it needs to build a complete GUI.3 Each Form is a layout container that is populated with controls, which are the individual GUI elements required to construct the screen’s behaviour – buttons, lists, popups, and so on – and any other graphical elements, backgrounds, or images that make up the screen’s design. Controls are either 3

To be precise, each app is limited to 30 Forms active at any time. If you create Forms dynamically, and destroy ones you no longer need, then this number is not a practical limitation.

07_974018-ch02.indd 3007_974018-ch02.indd 30

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

31

standard controls that are ready-made by the framework, or your own derived custom controls. The Control class abstracts a screen region, both for display and capturing input. Naturally, bada provides comprehensive graphical primitives, bitmaps, animations, and fonts, so the real limits here are your imagination – and your design skills!4 The relationship between Frames, Forms, and Controls is shown in Figure 2.8.

Figure 2.8 All applications have a Frame, the top level container within which Forms are added; Forms are populated with Controls.

2.2.2 Standard Elements of a Form – Indicator Bar, Title Bar, Soft Keys, Option Menu A Form occupies the full physical display area of the phone – everything visible on the screen. Forms therefore also optionally include some standard system elements (see Figure 2.9). These are ■■

The Indicator bar at the top of the display area, used to display system icons (such as signal and battery strength) and notifications (such as whether you have unread messages).

■■

The Title bar, which can display a string.

4

Under the hood, the raw horsepower for bada’s graphics capabilities is based on OpenGL ES, with support for 2.0 (hardware acceleration and hardware shaders) and 1.1 standards (hardware acceleration only). The OpenGL ES version available is device dependent. It is also possible that at the low end, some bada phones will not support OpenGL ES at all. Apps that require OpenGL ES will not install on phones that lack appropriate support.

07_974018-ch02.indd 3107_974018-ch02.indd 31

8/31/10 12:34 AM8/31/10 12:34 AM

32

Part I



About bada

■■

Soft keys that are displayed in the command area at the bottom of the main display.

■■

The Option menu key, displayed at the bottom of the display area between the soft keys, used to launch an Option menu.

The system elements are defined as properties of the Form. The decision whether to display all or some of them is made by each Form, and is therefore under the control of the application that defines the Form. However, their look and feel (and in the case of the Indicator bar, its contents too) is not directly controlled by the app. Although the Form displays the system elements, the framework retains control of them.

Figure 2.9 The application name and standard system elements.

2.2.3 Handling Events We said that every Control-derived class abstracts a screen region, both for display and input, but we didn’t say how. Input events include input from the touch screen, including menus and soft keys, from the physical phone keys including side keys such as Lock and Camera, from gestures and raw sensor events, from bada system events – potentially from any type of event. Listeners are the glue that binds behaviour to presentation in a bada app. In bada, listeners provide the mechanism for all event handling. At any time, exactly one control has focus in the GUI. Focus just means which object is actively updating the display and receiving user and system events. Conceptually, focus belongs to the currently active control of the currently running foreground application. This control receives any input events that occur (and by the way, also initiates redrawing the display). Every control has built-in listeners for the basic event types it recognises. Depending on the control, these might include any of the following: ■■

Focus events

■■

Key events

■■

Touch events

■■

Drag and drop events

07_974018-ch02.indd 3207_974018-ch02.indd 32

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

33

Many controls then add their own, control-specific listeners. For example, slider controls recognise the slider-specific ‘adjustment’ event, which reports how far the slider has been moved. Also, many controls share a generic ‘action’ event listener, which responds to standard events generated by the UI framework, including: ■■

Button and CheckButton events

■■

ContextMenu and OptionMenu events

■■

Tab events

2.2.4 Summary Let’s sum up the essentials. The application Frame, and the Form or Forms it contains, and the controls that populate the Forms, are the building blocks from which a bada application constructs its GUI: ■■

Each application has a single Frame, which abstracts the device display.

■■

Frame is the root object of the app GUI.

■■

A Frame contains one or more Forms (usually – a special case is a full-screen, also known as Frame-based, app, which contains no Forms; instead it draws its graphics directly).

■■

A Form is the highest level container object after Frame, and defines a complete application screen.

■■

Arbitrary controls can be added to Forms.

■■

Listeners are added to controls to capture events the app wants to respond to.

2.3 UI Builder Now we know what’s in a GUI, let’s build one. The WYSIWYG, UI Builder tool makes it easy to create a basic GUI layout, using standard controls. UI Builder will also generate the underlying class source code for the controls we define. Only a small amount of hand coding will then be required to hook up the UI layout and controls with the application skeleton we have already created.

2.3.1 A Simple UI BuddyFix is a single screen application, with a simple list-based presentation. The UI design is based on the requirements summarised in the box below. If this was a fully-fledged commercial app we would want something more than this simple spec; but it’s enough for our purposes as an exercise in defining basic but realistic application functionality, and showing how to implement it in bada.

07_974018-ch02.indd 3307_974018-ch02.indd 33

8/31/10 12:34 AM8/31/10 12:34 AM

34

Part I



About bada

The BuddyFix UI BuddyFix is a simple app that enables a simple use-case. It enables a user to share periodically updated location information with a list of friends in order to converge in real-time on a meeting place. To do so, BuddyFix uses the Buddy service that bada provides as a service API. BuddyFix displays a list of buddies, with the following information displayed for each buddy: ♦ picture; ♦ name; ♦ location fix, i.e. last known location; ♦ time fix, i.e. time of last location fix; ♦ location status, on or off the grid, i.e. currently reachable or not; ♦ whether location sharing is enabled for this buddy. Additionally the UI must provide the following information: ♦ whether sharing is paused or active at application level; ♦ interval at which location fixes are updated. Points to note: ♦ Location sharing is always in both directions. ♦ Location fixes are therefore always updated in both directions. ♦ Application-level pausing of location sharing allows power to be saved. ♦ Location display format should be user selectable. ♦ Location sharing is periodic not continuous, and is scheduled according to the update interval. ♦ The update interval should be user selectable. ♦ The update interval applies to all buddies. ♦ Individual buddies are added from the phone Contacts app. ♦ Friends must already be buddies on the Buddy service to be allowed by BuddyFix. Clearly, some of the above are too limiting for the app to be fully featured, but for current purposes they keep complexity manageable. The UI must enable the following actions: ♦ Add/Remove a buddy. ♦ Start/Stop sharing, for some buddy. ♦ Nudge now, share a location fix with some buddy now, without waiting for the next scheduled update. ♦ Set the update interval. ♦ Pause/Unpause all sharing.

07_974018-ch02.indd 3407_974018-ch02.indd 34

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

35

So let’s get started. We’ll define a single MainListForm as the basic app screen, from which all functionality will be available. Launch the Resource Explorer by selecting Window | Show View | Other from the Eclipse main menu bar as shown in Figure 2.10.

Figure 2.10 Launching the Resource Explorer.

The Resource Explorer pane will open in the IDE. (If it is empty when it launches, make sure you have your project selected in the Project Explorer pane.) Right-click anywhere in the Resource Explorer and select Open Insert Wizard, as shown in Figure 2.11. It’s a new Form we want to create, so select Create Form File, and Finish. A new Form appears in the Resource Explorer pane. Double click to launch the WYSIWYG UI Builder and you should see the screen shown in Figure 2.12. Note that the default Form – for demonstration purposes – already contains a Button control, which you can use or simply delete. When the UI Builder pane is launched, double-click on the main Form pane to open the Form Properties pane as shown in Figure 2.13.

2.3.2 Form Properties Before doing anything else, let’s change the Form name to something meaningful. Properties are simple name, value pairs. To edit a property, double click the property name in the property list and change the associated value. For BuddyFix, we retain the ‘IDF’ prefix and the all-capitals resource naming convention to provide clarity in our code, and name the Form IDF_MAIN_LIST_FORM.

07_974018-ch02.indd 3507_974018-ch02.indd 35

8/31/10 12:34 AM8/31/10 12:34 AM

36

Part I



About bada

Figure 2.11 Opening the Insert Wizard.

Figure 2.12 A new Form has been created in the Resource Explorer pane.

07_974018-ch02.indd 3607_974018-ch02.indd 36

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

37

Figure 2.13 The Form Properties pane.

Next, notice that the Form that UI Builder has created for us is not empty. At the top, it already contains an Indicator bar and Title bar (though the Title bar is empty). We said earlier that each Form defines which standard elements to display, and that these are included as Form properties. Setting the ‘Title’ property will display a string in the Title bar. A good rule of thumb is that the string displayed should describe the function of the Form that displays it. In a single Form app, this should always be the app name. We will set the value to ‘BuddyFix’. By default, all Forms display the Indicator bar. Unless you are writing a fullscreen game or similar application, it is good practice always to include the Indicator bar in your UI, to enable the user to remain fully aware of the device state and to receive alerts. As mentioned previously, although you can display it, you cannot update the Indicator bar directly. Displaying the Indicator bar is a Style option in the Properties list. Other Style options include whether or not to show soft keys, and soft key styles if any. The look and feel of a Form is highly configurable. The most important properties are shown in Table 2.2.

07_974018-ch02.indd 3707_974018-ch02.indd 37

8/31/10 12:34 AM8/31/10 12:34 AM

38

Part I



About bada

Table 2.2

Form properties.

Property

Purpose

Id

Form identifier, typically prefixed IDF_; this is also used in C++ code to refer to the Form layout file

Type

WINDOW_FORM is the top level Form within any Frame, where the application Frame represents the screen window in which the app displays

Title

Title that will appear in the Form Title bar, if enabled

Orientation

How the Form displays when the phone is rotated through a possible four directions

Layout | Mode

Portrait or Landscape

Note: Although you can set the background colour for both Frame and Form, you can’t set the background to be an image, unlike other types of control.

2.3.3 The Buddy List The most important part of the UI is the main buddy list itself, which will display a number of items of information for each buddy. UI Builder gives us a choice of several list types, and bada allows us to define custom lists of our own, but to start with we’ll keep things simple and use a basic, simple list, displaying the following fields for each item: ■■

Picture

■■

Name

■■

Last known location fix/time fix

■■

Whether location sharing is enabled for this buddy

To add a list to the Form in UI Builder, select the List icon from the controls Palette, and drag onto (or click inside) the main Form view, as shown in Figure 2.14. Resize the List to occupy the whole area of the Form. Now double-click anywhere inside the List to open the Properties editor pane. Editing List properties is exactly like editing Form properties.

07_974018-ch02.indd 3807_974018-ch02.indd 38

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

39

Figure 2.14 Adding a list to our Form.

First let’s rename the List to IDC_MAIN_LIST. Next, let’s look at the properties that are of interest. First, we can define basic properties like the row heights and widths for each item and the order in which the different fields will display: Row 1 Height

Default 80

Row 2 Height

Default 50, only shown when a two-line format is selected

Column 1 Width

Default 50

Text Of Empty List

Text to display in case the list is empty

List Item Format

One of 11 possible format styles specifying the structure of the list contents, for example: LIST_ITEM_SINGLE_IMAGE, LIST_ITEM_DOUBLE_IMAGE_TEXT_FULLTEXT

A simple list can display one or two columns, and the first column can display one or two rows. We’ll set the format to LIST_ITEM_DOUBLE_IMAGE_TEXT_ FULLTEXT, which will display a first line of image and text, and a second line of text.

07_974018-ch02.indd 3907_974018-ch02.indd 39

8/31/10 12:34 AM8/31/10 12:34 AM

40

Part I



About bada

Next, under Layout, we can set the list style (see Figure 2.15). Even with a simple list we have lots of styles to choose from, including: LIST_STYLE_NORMAL

Normal style

LIST_STYLE_NUMBER

Numbered style

LIST_STYLE_RADIO

Radio style for single selection

LIST_STYLE_RADIO_WITH_DIVIDER

Radio style with divider for single selection

LIST_STYLE_MARK

Mark style for multiple selection

LIST_STYLE_MARK_WITH_DIVIDER

Mark style with divider for multiple selection

LIST_STYLE_ONOFF

On/Off style

LIST_STYLE_ONOFF_WITH_DIVIDER

On/Off style with divider

We’ll choose LIST_STYLE_MARK, which displays a selection marker for each item, allowing us to make a selection and apply operations to the selected subset. Finally, we’ll set the Text Of Empty List property to ‘No buddies...’. UI Builder gives us a basic idea of how our list will look, but there is no substitute for seeing it in a running app. There is just a little more to do before we can do that.

Figure 2.15 Using UI Builder to set the properties of our list.

07_974018-ch02.indd 4007_974018-ch02.indd 40

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

41

But first, we should save the changes that we have made. Select File | Save All Resources. Note: Always save when you finish working with UI Builder, because resource files are only saved into your project /Res folder when you explicitly save them. If you don’t, your changes may be lost when UI Builder exits.

2.4 Hooking Up Your Forms to Your Code UI Builder takes the properties we have defined and generates a declarative XML layout file from them. If you open up IDF_MAIN_LIST_FORM in a text editor, you will see the XML declarations.









It is easy enough to see how our property settings have been translated into attributes of the Form and List objects that the XML declares. However, the layout file is just a declaration, not an implementation. At runtime, if we load the layout file, the framework will do the rest of the work of instantiating objects for us. But we must first load the layout file.

07_974018-ch02.indd 4107_974018-ch02.indd 41

8/31/10 12:34 AM8/31/10 12:34 AM

42

Part I



About bada

To do that, we need to create a Form class. UI Builder can do that for us. Note that so far, no changes at all (and no additions) have been made to the Application Wizard-generated C++ code. In UI Builder, generate the underlying code for the main Form by rightclicking on the Form to open the context menu. (Be sure to click on the Form, not the List; clicking inside the Title bar ensures the Form is not hidden beneath another control.) Select Add Class as shown in Figure 2.16 to pop up the New Class Wizard, which will display the window shown in Figure 2.17. We will name the class MainListForm, matching the resource file name. Next, let’s set its listeners. In the EventListener dialog, we set IActionEventListener. We don’t set IOrientationEventListener, because we have only designed a portraitmode screen. In a real app, unless we have specific reasons not to, we should enable both portrait and landscape modes. In the Control Base EventListener dialog, we select focus, key, and touch events. These are the underlying events that will be detected by the framework and from which action events will be generated. We know therefore that in our code we should expect to handle key, touch, and focus events. We don’t set drag and drop events, because we don’t want drag and drop interaction with the buddy list.

Figure 2.16 Using the New Class Wizard.

07_974018-ch02.indd 4207_974018-ch02.indd 42

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

43

Figure 2.17 Setting control listeners.

Notice that the List control that the Form contains is also included in the Wizard (because it is embedded inside the Form in the XML description). In the Control dialog, we set the List’s IItemEventListener. Select Finish, and then Save from the main menu. If you open MainListForm.cpp, you can see that the Form is initialised by loading the resource declaration into the constructor: bool MainListForm::Initialize() { Form::Construct(L”IDF_MAIN_LIST_FORM”); return true; } result MainListForm::OnInitializing(void) { result r = E_SUCCESS; // TODO: Add your initialization code here return r; }

07_974018-ch02.indd 4307_974018-ch02.indd 43

8/31/10 12:34 AM8/31/10 12:34 AM

44

Part I



About bada

Note: You will see that we always use the ‘L’ macro to create a String object from literal text, ensuring that all string literals are encoded as Unicode, and not as simple C-style single-byte character strings. We recommended that you adopt this usage too. In addition, all the listener methods of the events we chose to respond to have been added: class MainListForm : public Osp::Ui::Controls::Form, public Osp::Ui::IActionEventListener, public Osp::Ui::IFocusEventListener, public Osp::Ui::IKeyEventListener, public Osp::Ui::ITouchEventListener, public Osp::Ui::IItemEventListener { // ... Other methods omitted // Generated call-back functions public: void OnActionPerformed(const Osp::Ui::Control&, int); void OnFocusGained(const Osp::Ui::Control&); void OnFocusLost(const Osp::Ui::Control&); void OnKeyLongPressed(const Osp::Ui::Control&, Osp::Ui::KeyCode); void OnKeyPressed(const Osp::Ui::Control&, Osp::Ui::KeyCode); void OnKeyReleased(const Osp::Ui::Control&, Osp::Ui::KeyCode); void OnTouchDoublePressed(const Osp::Ui::Control&, const Osp::Graphics::Point&, const Osp::Ui::TouchEventInfo&); void OnTouchFocusIn(const Osp::Ui::Control&, const Osp::Graphics::Point&, const Osp::Ui::TouchEventInfo&); void OnTouchFocusOut(const Osp::Ui::Control&, const Osp::Graphics::Point&, const Osp::Ui::TouchEventInfo&); void OnTouchLongPressed(const Osp::Ui::Control&, const Osp::Graphics::Point&, const Osp::Ui::TouchEventInfo&); void OnTouchMoved(const Osp::Ui::Control&, const Osp::Graphics::Point&, const Osp::Ui::TouchEventInfo&); void OnTouchPressed(const Osp::Ui::Control&, const Osp::Graphics::Point&, const Osp::Ui::TouchEventInfo&); void OnTouchReleased(const Osp::Ui::Control&, const Osp::Graphics::Point&, const Osp::Ui::TouchEventInfo&); void OnItemStateChanged(const Osp::Ui::Control&, int, int, Osp::Ui::ItemStatus); // ... etc };

There is one final step required to hook up our new Form. In BuddyFix.cpp, we still have the original code generated by the Application Wizard, which constructed a default Form class, Form1. Instead, we construct our new Form class MainListForm:

07_974018-ch02.indd 4407_974018-ch02.indd 44

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

45

// Customised to load IDF_MAIN_LIST_FORM bool BuddyFix::OnAppInitializing(AppRegistry& appRegistry) { // TODO: // Initialize UI resources and application specific data. // The application’s permanent data and context can be obtained // from the appRegistry. // // // //

If this method is successful, return true; otherwise, return false. If this method returns false, the application will be terminated.

// Uncomment the following statement to listen to the screen // on/off events. //PowerManager::SetScreenEventListener(*this); // Create a form //REPLACED Form1 *pForm1 = new Form1(); MainListForm *pMainListForm = new MainListForm(); //REPLACED pForm1->Initialize(); pMainListForm->Initialize(); // Add the form to the frame //REPLACED Frame *pFrame = GetAppFrame()->GetFrame(); Frame *pFrame = GetAppFrame()->GetFrame(); //REPLACED pFrame->AddControl(*pForm1); pFrame->AddControl(*pMainListForm); // Set the current form //REPLACED pFrame->SetCurrentForm(*pForm1); pFrame->SetCurrentForm(*pMainListForm); // Draw and Show the form //REPLACED pForm1->Draw(); pMainListForm->Draw(); //REPLACED pForm1->Show(); pMainListForm->Show(); return true; }

A quick look at the code in MainListForm.cpp shows us that the call to Initialize() completes the Form construction, loading the layout file: bool MainListForm::Initialize() { Form::Construct(L”IDF_MAIN_LIST_FORM”); // ... Etc. }

Don’t forget to #include the header file for the new Form. In BuddyFix.cpp: #include “BuddyFix.h” //REPLACED #include “Form1.h” #include “MainListForm.h”

07_974018-ch02.indd 4507_974018-ch02.indd 45

8/31/10 12:34 AM8/31/10 12:34 AM

46

Part I



About bada

In Project Explorer we can now build and run the project (see Figure 2.18).

Figure 2.18 Running BuddyFix in the Simulator.

When BuddyFix runs, instead of the buddy list, what we see is the default text that we set to display when the list is empty. Before we can actually see the list, we will need to populate it, and to do that we’ll need to write some code – which we’ll do in the next chapter.

2.5 The App Icon There is only one more thing to do to complete our app skeleton. Every app needs an icon. As we saw, the icon is displayed in the main menu, and provides the mechanism for the user to launch your app. The app icon is defined as a property of the app project, and is easy to set. Select your project in Project Explorer, and select Project | Properties from the main menu to launch the Properties dialog. Expand the bada Build item and select Application Information. Here we can see some basic defining information for BuddyFix.

07_974018-ch02.indd 4607_974018-ch02.indd 46

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

47

To add an icon, you will first need to create the graphic of course. We recommend that you create an icon graphic with the following properties: File Type

PNG

Size

135 × 135 pixels

Resolution

72dpi

Bit depth

32 bit

Create an icon in your favourite graphics application, and add it to the /Icons folder. Select the File System button beside the Main Menu icon to browse the /Icons folder and choose the app icon of choice. Select OK to save. Next time you launch the Simulator, your chosen icon will display in the main menu. (You do not need to rebuild for the change to take effect.) Note: No effects are applied to the icon, for example rounding or bevelling (other than dimming to indicate selection). You should create your icon with any effects that you want, with a transparent background, for example if you round the icon corners. At runtime the framework supplies the app name, so you only need to provide a graphic.

2.6 Becoming Multilingual in Three Easy Steps As implemented, our BuddyFix GUI has a serious limitation: we have hardcoded English language strings into the UI text that we display – for example the soft key text. One excellent feature of bada is its extensive language support. In fact, at the time of writing, the SDK includes language packs for almost 40 languages, with more promised soon.5 As this makes clear, bada is a truly multilingual platform, with a wide range of support for both Latin and non-Latin languages, making it possible for you to localise your application for a huge range of potential markets.

5 As of SDK version 1.0.0b3, the supported languages are: Basque, Bulgarian, Catalan, Chinese Simplified, Chinese Traditional (Hong Kong), Chinese Traditional (Taiwan), Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, Galician, German, Greek, Hungarian, Icelandic, Irish, Italian, Kazakh, Korean, Latvian, Lithuanian, Macedonian, Norwegian, Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovenian, Spanish, Swedish, Turkish, and Ukrainian. Promised soon are Arabic, Farsi, Hebrew, Malay, Thai, Urdu, and Vietnamese.

07_974018-ch02.indd 4707_974018-ch02.indd 47

8/31/10 12:34 AM8/31/10 12:34 AM

48

Part I



About bada

One aspect of localisation is ensuring that all the text you display in your application’s UI matches the user’s language settings. Another is ensuring that everything you display to the user is in a format that they expect. Date and time information should appear in the right format for a particular country and language setting, with the appropriate separators, and day and month names. Numbers should appear with the correct separators and the appropriate currency symbols should be used. In bada, support for localised number formats, dates, times, and currency is provided by the classes in the Locales namespace. (More on this in Chapter 6). Supporting multiple languages and date, time, and number formats really improves your application’s chances of worldwide success. The rest of this section will show you how to build multilingual support into your UI. Fortunately, bada makes this easy. Everything you need to create a multilingual UI is included in the UI Builder.

2.6.1 Add New Languages Adding languages is easy. To support additional languages, open the Resource Explorer in the IDE. Double click String. Right-click inside the String window and from the menu displayed, choose Language Setting. The Add New Language dialogue is now displayed, as shown in Figure 2.19.

Figure 2.19 Adding a new language in the UI Builder string table view.

07_974018-ch02.indd 4807_974018-ch02.indd 48

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

49

Choose the languages you want to support. When you’ve finished you’ll notice that the string table window has been updated to include a column for each language you’ve chosen. Note: An XML file containing a localised string table is added to the project for each language. For example, the British English string table is called eng-GB.xml, while the French one is fra-FRA.xml.

2.6.2 Add Text for Each Language Now it’s just a matter of adding the strings that appear in your UI into the corresponding columns in the string table for every language you support. For example, in Figure 2.19, we add the English and French version of every string displayed in our UI. Add the appropriate text for each language and bada will choose the right one according to the user’s language settings. Next, you want to make sure that the title of a Form or the text of a button control, for example, is shown correctly for each language. All you need to do is add localised text for each string resource and use UI Builder to ensure that the control uses a string resource for its title or text. Figure 2.20 shows you how. In Figure 2.20, we set the title of the Form to be IDS_STRING5. If the user has set their language to French, the Form title will automatically be set to ‘Bonjour bada’. If no localised string is found, the English one is used.

Figure 2.20 Using a stringID as a Form title: bada will choose the correct localised string.

07_974018-ch02.indd 4907_974018-ch02.indd 49

8/31/10 12:34 AM8/31/10 12:34 AM

50

Part I



About bada

2.6.3 Use String Resource IDs in Your Code To take full advantage of bada’s multilingual support, don’t hard-code strings in your code. Hard-coded strings are difficult to track down and update for multiple languages, so instead read the string from a resource, as shown in the following code: Application* pApp= Application::GetInstance(); String str1; r = pApp->GetAppResource()->GetString(L”IDS_STRING1”, str1);

The value of str1 is read from a resource file rather than hard-coded. If you’ve set up a different string for each language, the appropriate string will be chosen based on the user’s language setting.

2.7 From Idea to Published App If you have an idea for a ground-breaking bada app you only have to go through the following three steps (see Figure 2.21):

Figure 2.21 The steps to publishing your app on Samsung Apps.

07_974018-ch02.indd 5007_974018-ch02.indd 50

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

51

Step 1: On the developer.bada.com Portal When you signed up on the developer.bada.com portal to download the IDE and SDK, you did more than register for a download; you joined the bada developer programme. This enables you to access the online services that provide many useful resources such as documentation, API reference, code samples, tutorials, blogs, videos, or a support forum. Generate an Application Profile and Download the manifest.xml

In this section we concentrate on the custom app profile generator, which should be the starting point for your real projects, because it allows you to define the functionality of your app and to specify the hardware features your app requires or expects (e.g. screen size, sensors, default orientation). The portal also checks that your app name is globally unique, as well as assigning a unique numerical ID that your app uses to protect its private resources. In section 2.1, metadata, we looked very briefly at the two metadata files that every app project must include: application.xml and manifest.xml. These, we said, declare application information used to package the app – such as names, versions, and intended target phone models – as well as critical security permission declarations. Configuration of the application.xml is handled by the IDE. The web portal helps to establish the manifest.xml. To create your manifest file go to the developer.bada.com portal and click the My Applications tab. Then invoke the Application Manager on the left. There you can then start to generate your application profile. Figure 2.22 shows the web site and the five simple steps to follow. First, give your app a name, and add a description if you want. Second, you define the privileges that are the main functionalities of your app. If your application involves any remote services from the bada Server, you can define them during the third step. Fourth, you specify the hardware requirements against the mobile handset. And finally you can download the manifest file. The downloaded manifest.xml typically contains info as illustrated below:

93bt1p123e 9C645DDBA19C71BAD1204DA4DAA7A0B9 1.0.0

IMAGE

Cortex8 16 4 OpenGL-ES1.1 OpenGL-ES2.0

07_974018-ch02.indd 5107_974018-ch02.indd 51

8/31/10 12:34 AM8/31/10 12:34 AM

52

Part I



About bada

OPP SPP Infrastructure Ad-hoc GPS Accelerometer Magnetic Proximity Touch 480x800 Enable 1.0

Here, the first attributes are basic application information. While and both appear in code, the framework takes care of their use. The ID is a unique number. The secret key is uniquely related to your app.

Figure 2.22 Application Manager on developer.bada.com.

07_974018-ch02.indd 5207_974018-ch02.indd 52

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

53

Most interesting, then, is the attribute, and its sub-attributes. In the manifest file above, the single IMAGE privilege is specified:

IMAGE

The format of the declaration here is straightforward XML: is an attribute, and contains a list of sub-attributes, each of which is declared using the sub-sub-attribute, in this case IMAGE.6 Privileges declare which functionality an app offers. If appropriate privileges are not declared, an exception will be thrown at runtime the first time the app attempts to use an undeclared, privileged API. More interesting than how to declare privileges is what they mean and what they do. Privileges are important for the security mechanisms in bada to ensure privacy (for instance). You can find more information about the privilege model in bada in Chapter 4. The next XML tag in the manifest file is the . It declares the minimum system requirements for the application. It is all automatically generated by the portal from the information the developer provides. You can update the manifest in the same way that you generate it, using the portal tools. Declaring privileges is easy. Just remember that whenever you add APIs from a new namespace, you probably need to declare a new privilege (and update the libraries you are linking when you build).

Step 2: In the bada IDE/SDK Create bada App with the Manifest File

After you’ve downloaded the manifest file to your hard disk you can create a bada app project as described earlier. In the Wizard where you arrive at the point to select the manifest file, you should uncheck the default one and point the Wizard to the just downloaded manifest.xml on your hard disk. The other option – if you already have an existing project with an existing manifest file – is to simply overwrite the old manifest file with the new one. Program and Build

The next necessary bit to bring your app to life is actually thinking of your logic and programming. When you think your app is in a runable state you can build your bada project in the IDE as described earlier. 6

Instead of ‘attributes’, you can call these ‘properties’ if you prefer.

07_974018-ch02.indd 5307_974018-ch02.indd 53

8/31/10 12:34 AM8/31/10 12:34 AM

54

Part I



About bada

Test and Debug on Simulator

Once your app compiles and can be built without any errors, you can start testing by running it in the bada Simulator. The Simulator is very useful for testing the principal correctness of your code. Traditionally there was a large discrepancy between the behaviour of simulators and real mobile devices. Because of the importance of context information, intensive real-world tests had to be on the mobile device anyway. The bada Simulator comes very close to the real device. In addition to that, it provides an extra tool called the Event Injector (see Figure 2.23), which allows injecting sensor events of all kinds into the Simulator. In fact, so too can other events such as phone calls, messaging events, network events, and device events like low battery or low memory. This helps a lot and makes testing much more efficient because many of the real-world context tests can be shifted to the less expensive simulator tests. The following events can be simulated: ■■

incoming calls;

■■

network characteristics and quality (e.g. service level, roaming, or network codes);

■■

transmission of text messages, WAP push7, and push notifications;

■■

location data (latitude and longitude) by choosing on a map or explicitly inserting;

■■

various sensors, such as accelerometer, GPS, magnetic, tilt, proximity, or weather;

■■

device events such as memory or battery level.

The bada Motion Sensor is a logical sensor that is based on composite data from onboard hardware sensors. The Motion Sensor detects predefined movement of the phone by the user: Snap

Rapid one-time back and forth movement of the phone in any of the X, Y, or Z dimensions. Three different events are recognised, one for each axis, in each of portrait and landscape modes. Shake

Rapid repeated sideways movement of the phone. 7

WAP is the Wireless Application Protocol, an early initiative to enable the Web on mobile devices. From a user perspective WAP has largely been overtaken by the ‘real’ Web on mobile, but WAP protocols still play an important infrastructure role. WAP Push remains the standard for pushing network notifications and setup messages to mobile phones.

07_974018-ch02.indd 5407_974018-ch02.indd 54

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

55

Double Tap

Double tap on any side of the phone case.

Figure 2.23 The Event Injector.

Note: In effect, the bada Simulator is a complete build of the bada platform, customised to run on top of a desktop OS, specifically Win32 in the Microsoft Windows hosted SDK, instead of a mobile phone OS. Of course, your app might not run perfectly right from the beginning. There may be bugs in it. The bada IDE supports the GNU Project Debugger (GDB), which allows you to use the common functionalities of software code debugging such as setting breakpoints, stepping in, out or over methods or watch variables. Figures 2.24 and 2.25 illustrate how to invoke debugging and show the Debug perspective of the IDE.

07_974018-ch02.indd 5507_974018-ch02.indd 55

8/31/10 12:34 AM8/31/10 12:34 AM

56

Part I



About bada

Figure 2.24 Invoking GDB in the bada IDE.

Figure 2.25 The Debug perspective of the bada IDE.

07_974018-ch02.indd 5607_974018-ch02.indd 56

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

57

Test and Debug on Real Target Device

The obvious difference between developing for a mobile platform such as bada and the more conventional world of application development on the desktop is the fact that the development environment is not the same as the execution environment. To understand and test the mobile app the simulator as described above is very useful. But eventually you really want to find out how your app behaves on a real mobile handset. Turning back the time machine, mobile platforms were difficult. But bada shows just how far things have come. Some platforms still bear the legacy – Symbian’s quirky build-system, for example. In fact, these are all part of what makes mobile different and gives mobile development its reputation for difficulty. At the time of writing, the first bada phone has been shipped – the Samsung Wave, a feature-packed, top-of-the-line phone that defines the high end of the bada product line. Eventually, bada phones will extend from this high point down through the midrange of affordable ‘smartphones for everyone’, taking smartphone features to the mass-market. Before you can build and deploy a bada app on your Wave target you need to install the Wave device driver in your desktop OS. These device drivers are a simple executable file shipped within the IDE/SDK bundle that you downloaded from the developer.bada.com portal. If this is successful, you need to copy and install the Test Root Certificate, which is necessary for testing an app on the target device. An app cannot be installed, run, and tested on the Wave without this Test Root Certificate. It is up to you how you transfer the Test Root Certificate file to your Wave. The easiest way is to push it from your desktop computer using Bluetooth. The other way is to use the USB cable connection in ‘Mass storage’ mode. This can be set on the Wave by invoking the Menu and then going to: Settings | Connectivity | USB | Mass storage and then clicking on the ‘Set’ soft key. The Test Root Certificate file that needs to be transferred from the desktop to the Wave device is shipped with the SDK/IDE download. You will find the necessary file “rootCACert.cer” in \Tools\sbuild. Then disconnect your Wave device from the desktop. On the Wave invoke the Menu and then go to My files | Other. Tab the rootCACert.cer file and it should be installed automatically (see Figure 2.26). To make use of on-device debugging via USB you need to explicitly set this in your Wave device. Open the Menu and go to Settings | Connectivity | USB | USB Debugging and then click on the ‘Set’ soft key (see Figure 2.27).

07_974018-ch02.indd 5707_974018-ch02.indd 57

8/31/10 12:34 AM8/31/10 12:34 AM

58

Part I



About bada

Figure 2.26 Installing the Root Certificate.

Figure 2.27 Setting up the device for USB debugging.

To deploy your bada app on your Wave device all you have to do is change the active build configuration and build it for the target platform. Open your bada IDE and create or open your bada project. Go to the context menu of your project by right-clicking the project name in the Project Explorer window. Then go to Build Configurations | Set Active and check Target-Debug (see Figure 2.28). After that, build your project for the target device again by entering the context menu of your project and clicking Build Project. Before running your bada app on the target device make sure that it is connected to your computer via USB and that it is in USB Debugging mode so you can make use of the debugging messages in your IDE. To run your app go to the context menu of your project and select Run As | bada Target Application (see Figure 2.29).

07_974018-ch02.indd 5807_974018-ch02.indd 58

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

59

Figure 2.28 Setting Target-Debug as the active build configuration.

Figure 2.29 Running your application on the target device.

07_974018-ch02.indd 5907_974018-ch02.indd 59

8/31/10 12:34 AM8/31/10 12:34 AM

60

Part I



About bada

After this, your app should successfully run on your mobile device and logging messages should be visible in your IDE output window. Note: A further very useful feature is in beta testing status at the time of writing. Samsung will soon provide you with the chance to make use of real device target deployment even if you do not have a device available. The code name for this is RTL: Remote Testing Lab. There will be a lab somewhere in the world hosting a large number of real bada-powered devices. You can conveniently connect to these over the Internet and deploy your bada app there – just as if it was on your desk in front of you. This will all soon be accessed through a RTL plug-in for the bada IDE. So stay tuned! Create Package

The last task in the second step of the process of taking an idea to a published app is to create the full package that is used in the third step for certifying your app. To create a package, select the bada project in the IDE that you want to submit for certification. Click on the Project menu and select Make Package (see Figure 2.30).

Figure 2.30 Creating an application package.

In the next dialog you can define the output folder where the package (which is a zip) should be stored.

Step 3: On the seller.samsungapps.com Site When all this is done and you have implemented your idea into an app that is built, run, tested, and packaged, you are one step away from becoming rich and famous – or both. This final step is certifying before publishing your app.

07_974018-ch02.indd 6007_974018-ch02.indd 60

8/31/10 12:34 AM8/31/10 12:34 AM

Chapter 2



bada Basics

61

Get Certification

To get certification you need to go to the seller.samsungapps.com web site. There you can use the same account to log in as you used for the developer.bada.com portal in step 1. Once you are logged in the main screen is displayed, as shown in Figure 2.31. You start the submission process by clicking the Add New Application button at the top. Then the web site guides you step-by-step through the necessary tasks to submit your app for certification (see Figure 2.32). After you complete the process, your app is submitted for certification. The app is tested to ensure that it works functionally and non-functionally and that it meets quality standards (regarding usability, for instance). Our aim is to take no more than seven working days to do the QA and give you feedback. Publish App

When you have your app certified, it will be published for download. You set criteria such as price or geographic markets during the upload for certification process. All the apps can be accessed through the samsungapps.com web site or can be downloaded directly onto your bada phone. A handy way to manage your apps and downloads is the desktop software Samsung Kies, which you can also get from the Samsung Apps Store at samsungapps.com.

Figure 2.31 Samsung Apps Seller Office main screen.

07_974018-ch02.indd 6107_974018-ch02.indd 61

8/31/10 12:34 AM8/31/10 12:34 AM

62

Part I



About bada

Figure 2.32 Adding your application to the Samsung Apps Seller Office.

07_974018-ch02.indd 6207_974018-ch02.indd 62

8/31/10 12:34 AM8/31/10 12:34 AM

CHAPTER

3 Beyond the Basics

So far, BuddyFix is just a shell. In this chapter we begin to extend it. As we do, we will learn more about how apps interact with the bada frameworks to inherit their runtime architecture and the GUI look and feel.

What You Will Learn This chapter shows how to go beyond the Application Wizard skeleton as you start to shape your application functionality. You will learn about: ■■

How bada apps interact with the application and UI frameworks.

■■

The runtime application lifecycle.

■■

Some essential UI and graphics classes.

■■

How to add soft keys and an Option menu to an app UI.

What You Will Need The emphasis in this chapter stays practical and hands on. Have your own code in front of you, and the bada reference documentation to hand to check out API details.

63

08_974018-ch03.indd 6308_974018-ch03.indd 63

8/31/10 12:35 AM8/31/10 12:35 AM

64

Part I



About bada

3.1 Expanding the Application Skeleton We have seen how easy it is to get a project started in bada; Wizards do the hard work for you. Now let’s dig a bit deeper into code. Let’s start by walking through the main BuddyFix class as declared in buddyfix.h (this is code the Application Wizard generated for us): class BuddyFix : public Osp::App::Application, public Osp::System::IScreenEventListener {

Every app derives from the App::Application class; so when you create your own app and derive from Application, you extend a class the bada frameworks already know about, with the custom behaviour you specify. All the methods the frameworks expect are present in your derived class. You’ll notice that your app also derives from the System::IScreenEventListener class; ‘I’ stands for ‘Interface’, which is a pattern we’ll see a lot more of (discussed in more detail in Chapter 4). Next, we see various constructors declared: public: static Osp::App::Application* CreateInstance(void); public: BuddyFix(); ~BuddyFix();

CreateInstance() is a so-called factory function that wraps the C++ constructor and when invoked, returns an instance of the application. The two declarations that follow it are the C++ constructor and destructor methods. Since the default implementations for all three will work fine for us, there’s nothing to worry about here. The remaining public declarations, which complete the class, are the ones we’re interested in: public: bool OnAppInitializing(Osp::App::AppRegistry& appRegistry); bool OnAppTerminating(Osp::App::AppRegistry& appRegistry, bool forcedTermination = false); void OnForeground(void); void OnBackground(void); void OnLowMemory(void); void OnBatteryLevelChanged(Osp::System::BatteryLevel batteryLevel); void OnScreenOn (void); void OnScreenOff (void); };

Let’s call these the ‘lifecycle’ methods; every app has them, and every app must implement them. The Wizard provides a minimal implementation for us, but as we’ll see, these methods are important in defining the way our app behaves, so we definitely want to understand what they can do for us.

08_974018-ch03.indd 6408_974018-ch03.indd 64

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

65

3.1.1 Being Event Driven A bada app is entirely event driven; its runtime behaviour is defined in response to events that it receives from the framework. These include user-originated events such as touch events, soft key events and (hard) key events, and systemoriginated events such as timers, sensor notifications, incoming voice calls or messages, and lifecycle events. In bada the event loop is hidden within the bada frameworks, and is not visible to the application. To receive the events that it wants to handle, the app just implements the appropriate listener call-back methods. This makes a bada application very straightforward to write. Applications are essentially reactive, and are completely defined by the set of events they handle. Choosing which events to listen for and handle depends on how you want your GUI to behave, and on your app’s core functionality. However, the lifecycle methods define a common set of system events that every bada app should handle.

3.1.2 The Runtime App Lifecycle The app lifecycle defines the dynamic, runtime architecture of every application. The lifecycle is defined by the bada app frameworks, and when you derive your app from App::Application, your app inherits the lifecycle methods. In bada, the lifecycle is very simple. Your app exists in one of four possible states: Initialising, Running, Terminating, or Terminated. At any time, your app can be in only one of these states. You probably recognise this as a simple state machine: your application transitions between these states, and associated with the transitions or states are the lifecycle methods: 1. Initialising OnAppInitializing() 2. Running OnForeground(); OnBackground(); OnLow Memory(); OnBatteryLevelChanged(); OnScreenOn(); OnScreenOff(); 3. Terminating OnAppTerminating(); 4. Terminated (no associated methods – your app is no longer running). The application lifecycle is shown in Figure 3.1. Strictly speaking, only four of these methods relate specifically to the lifecycle; the others, such as OnBatteryLevelChanged() and OnScreenOff(), respond to system events triggered by conditions that are so important, or so frequent on mobile, that the framework makes a special case of them and gives you the opportunity to respond appropriately. Let’s look more closely at the four lifecycle states, and at how the lifecycle methods map to them.

08_974018-ch03.indd 6508_974018-ch03.indd 65

8/31/10 12:35 AM8/31/10 12:35 AM

66

Part I



About bada

Figure 3.1 The application lifecycle.

1. Initialising When launched by the bada application framework, your app enters the Initialising state and its OnAppInitializing() method is called. Look at the implementation in BuddyFix.cpp; recall that we have updated the code the Application Wizard generated to load our own Form pMainListForm, otherwise this is the default implementation: // Customised to load IDF_MAIN_LIST_FORM bool BuddyFix::OnAppInitializing(AppRegistry& appRegistry) { // Initialize UI resources and application specific data. // The application’s permanent data and context can be obtained // from the appRegistry. // If this method is successful, return true; otherwise, return // false. // If this method returns false, the application will be terminated. // Uncomment the following statement to listen to the screen on/off // events. //PowerManager::SetScreenEventListener(*this); // Create a form //REPLACED Form1 *pForm1 = new Form1(); MainListForm *pMainListForm = new MainListForm();

08_974018-ch03.indd 6608_974018-ch03.indd 66

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

67

//REPLACED pForm1->Initialize(); pMainListForm->Initialize(); // Add the form to the frame Frame *pFrame = GetAppFrame()->GetFrame(); //REPLACED pFrame->AddControl(*pForm1); pFrame->AddControl(*pMainListForm); // Set the current form //REPLACED pFrame->SetCurrentForm(*pForm1); pFrame->SetCurrentForm(*pMainListForm); // Draw and Show the form //REPLACED pForm1->Draw(); pMainListForm->Draw(); //REPLACED pForm1->Show(); pMainListForm->Show(); return true; }

In this code, when our app launches, we: 1. Create the default Form we will display, add it to the application Frame, and set it to be the current Form. 2. Draw() and Show() the Frame; in two steps, this renders the Form (and any controls it contains) to the logical display; and then updates the physical Frame buffer (which updates the phone display, so that you can see it). The AppRegistry& appRegistry parameter is passed to the method to save you having to make a method call to get it. Typical uses of the registry at initialisation time are: ■■

Look for a key to tell us whether this is the first time the app has ever run, if there are specific ‘first time’ actions we want to perform, such as inviting the user to register, or to provide default data such as a nickname, or just so that we can say ‘Hello!’

■■

If we find a key, restore any saved preferences.

In both cases it’s a good idea to limit any code to simple, quick flag setting, to be actioned later, so that the Form we loaded can be drawn and the screen updated, and we can get on and launch; which we do by setting the return value: return true;

This is important; if the value is true, the framework will set our state to Running; otherwise, it will be set to Terminating.

2. Running If OnAppInitializing() returned true, our app will enter the Running state. There is no lifecycle method associated with this transition – so how do we code for it?

08_974018-ch03.indd 6708_974018-ch03.indd 67

8/31/10 12:35 AM8/31/10 12:35 AM

68

Part I



About bada

The answer is that in the Running state we must differentiate between two sub-states, Foreground and Background. There are methods associated with transitions to these states: OnForeground() and OnBackground(). OnForeground()is implicitly called when an app is started and the app is shown. A running app is sent to the background when the Home key is pressed or when a base application such as an incoming call or SMS is invoked. Then the OnBackground() method is called and it is recommended to stop resource-intensive operations and release unneeded memory. Once your app moves into the foreground again you can proceed normally. After launch, our app is now the foreground application. Our default Form is being displayed; and user interaction will cause our event listeners to run, for example we coded OnActionPerformed() to respond to the soft keys, Option menu key, and Option menu selections. Recall also the long list of listeners the UI Builder tool added to our MainListForm; key presses, touch and multi-touch events, and focus events will all cause our listener implementations (call-backs) to run, so that we can handle the events appropriately. And of course system events too will generate call-backs. As we’ve seen, the minimum set of system events we should be prepared to handle is ■■

OnBackground()

■■

OnLowMemory()

■■

OnBatteryLevelChanged()

■■

OnScreenOn()

■■

OnScreenOff()

The two screen events, as you may have guessed, are the reason for deriving from IScreenEventListener. There are no hard and fast rules for how you should code for these events. But clearly, for example, if memory is low you should consider releasing memory you own; if the battery level becomes low, save power, and be prepared for sudden failure; if the screen is off, there is no point in updating the display, and so on.

3. Terminating Your app may be terminated by the user; typically in bada, apps do not have an Exit soft key or menu option, but instead are ended when the user presses the Power/End key. Your app may also be terminated by the system, but that will usually indicate a serious error of some kind. In either case, when your app transitions to Terminating, its OnAppTerminating() method will be called, and you should prepare to close; release all resources, and possibly save state if relevant (but typically not user data – which should always be saved at the point of change). When your app next runs, it will launch into the Initialising state, which is the difference between its being terminated, and being put into background.

08_974018-ch03.indd 6808_974018-ch03.indd 68

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

69

4. Terminated Your app is no longer running.

3.1.3 A Note about Frameworks The great thing about frameworks is that they enable your app to take advantage of ready-made behaviour. Because bada’s language is C++, bada’s frameworks use C++ inheritance to share behaviour between the frameworks and your app. If you know your C++, you’ll probably know (at least approximately) how that works, but it doesn’t matter if you don’t. The principle is simple: the frameworks declare certain methods that your app must implement; the frameworks will call these methods, and when they do, your implementations will run. The bada C++ frameworks use derivation and virtual functions to share responsibilities between the framework itself, and apps that use the frameworks. The framework base classes that apps derive from provide ready-made implementations of common behaviour that all apps will share, as well as behaviour defined in virtual methods that may optionally be overridden, and abstract behaviour defined in pure virtual methods for which the derived class must provide an implementation. Abstract classes are used extensively in bada, particularly to define interface classes. See Chapter 4 for more about interface classes and how to use them. Note: In C++, derivation (i.e. inheritance) is the generic mechanism that allows derived classes to share the behaviour of base classes; and specifically, virtual functions (dynamic binding) allow derived classes to extend the behaviour of base classes by overriding the base class behaviour. Overriding is not the same as overloading, in which methods with the same name but different signatures are allowed, and the references are resolved at compile time; virtual methods use the virtual keyword and have the same name and signature, and the references are resolved at runtime. In C++, pure virtual methods, also known as abstract methods, are declared with a special =0; syntax that indicates the method has a null body, that is, no implementation; code won’t link until an implementation is provided. Pure virtual methods in the base class must be implemented by a derived class;1 other virtual methods of the base class have a base class implementation, but optionally may be reimplemented by a derived class to override the default behaviour.

1 More precisely, a derived class that will be instantiated must implement the pure virtuals of its base class(es). Chains of abstract classes are possible, but a class that does not implement an inherited pure virtual is itself an abstract class that cannot be instantiated.

08_974018-ch03.indd 6908_974018-ch03.indd 69

8/31/10 12:35 AM8/31/10 12:35 AM

70

Part I



About bada

3.2 Using the UI Framework Implementing the application lifecycle effectively and appropriately is one important aspect of making the best use of the bada frameworks. A second is using the GUI frameworks to create an effective, good-looking, and easy-to-use GUI. The touch UI on bada has a host of nice features, and the built-in apps showcase them well. In the following sections we take a deeper look at bada’s control and graphics classes, which provide the building blocks for creating the app GUI.

3.2.1 Control Hierarchy The bada UI classes provide a useful set of ready-made Control types. All UI elements, including Frame and Form, derive from the Control class as shown in Figure 3.2 which shows the most important classes of the Control hierarchy. Note that, for reasons of clarity, the diagram does not show all the UI controls that derive from Control, but it does show the relationship between Control and Container. Control is the base class for all GUI elements, and Frame and Form are the app’s top-level GUI objects.

Figure 3.2 The Control hierarchy.

08_974018-ch03.indd 7008_974018-ch03.indd 70

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

71

3.2.2 More about UI Controls Forms contain content. Content types include plain text, directly embedded images, and standard or custom controls. Controls that derive from the Container class can also be containers for nested controls. As well as containing content, controls are active and can respond to user events such as touches, multi-touches, and gestures. As you would expect, bada provides a comprehensive set of standard controls, such as buttons, pickers, and edit areas, as well as more specialised controls including animations, Flash movies, and overlay panels that enable controls to be layered (for example to overlay player-like controls on a video frame). Applications can also derive and customise their own controls, if there is no suitable standard control that meets the application’s needs. All controls must be both drawn and shown in order to display, either synchronously using the Draw() and Show() methods, or asynchronously using RequestRedraw(). Note that the synchronous drawing methods should not be called from within a call-back. Instead, use the asynchronous RequestRedraw() method, which returns immediately after queuing the redraw request. Container controls have an OnDraw() method that is called by the framework before any child controls are drawn, enabling any custom drawing to be performed in the Container (for example, drawing a bitmap background). Subsequent drawing of child controls will overwrite the relevant regions of the Container’s canvas, allowing a Container’s background to be drawn behind any controls that populate it. Note: A control only becomes displayable after it has been added to a displayable container. Whether a control is displayable will also determine whether its child controls, if any, are displayable. For this reason, a general rule is that no methods of the control should be called until after it has been added to its container, to avoid possible unexpected behaviour, for example related to displayability. Drawing is therefore performed in the following order by the framework: 1. Calls the Form’s Draw() method. 2. Calls the Form’s OnDraw() method, since Form is a Container. 3. Calls the Draw() method of the first child control, if any.

08_974018-ch03.indd 7108_974018-ch03.indd 71

8/31/10 12:35 AM8/31/10 12:35 AM

72

Part I



About bada

4. Calls the OnDraw() method of the first child control, if any, if the child is a Container. 5. Calls the Draw() method of the second child control, etc. Note that only Container controls have the OnDraw() method. Draw()

Draws the control to the canvas of the containing Window, which will normally be the Application Frame, since Frame is Window-derived (but e.g. Form is not).

Show()

Copies the Window canvas content to the displayable frame buffer.

RequestRedraw()

Asynchronous method that invokes Draw() and Show(), and returns immediately.

OnDraw()

Called by the framework when a Container control is drawn to enable any custom drawing to be performed before drawing any nested controls.

Shown below is a selection of some of the standard Control-derived classes provided by bada, organised by the kind of user interactions you’ll need when you design your user interface. Simple Buttons and Labels Button

CheckButton

Label

This group of controls is for generic buttons, presenting the user with tick box choices and in the case of the Label control displaying non-editable text or images.

08_974018-ch03.indd 7208_974018-ch03.indd 72

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

73

Pickers ColorPicker

DatePicker

RadioGroup

Slider

TimePicker

These are controls which let the user select a colour, a date or time or, in the case of a RadioGroup, make one choice from a list of options. The slider allows the user to choose a value from a range.

08_974018-ch03.indd 7308_974018-ch03.indd 73

8/31/10 12:35 AM8/31/10 12:35 AM

74

Part I



About bada

Lists CustomList

ExpandableList

GroupedList

IconList

bada gives you lots of choice when it comes to displaying lists, from lists of icons to a CustomList where individual items can have different layouts. We use a simple list in BuddyFix to display the list of buddies. Editable Controls EditDate EditField

08_974018-ch03.indd 7408_974018-ch03.indd 74

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

75

These are input controls for text and date. You can also use EditTime and EditArea, which are not shown above. Progress and Popups Progress

These are classes that display information to the user. Progress provides feedback to the user about how much time an operation will take to finish. A Popup provides a window that can be displayed on top of a Form or a Frame. Panels ScrollPanel

A Panel is a control that can contain other controls. A ScrollPanel provides a scrollable area (notice the scrollbar on the right of the control), which in the picture above contains a label and a button. The OverlayPanel control is used to for displaying video or camera previews. Animation and Flash Animation

The Animation control is designed for playing back a series of AnimationFrames. You can also use the Flash control to play back Flash Lite content embedded in an application.

3.2.3 More about Frame Every application has access to its Frame, which abstracts a drawable, fullscreen-sized display window. Frame takes care of standard window behaviour for all of its contained controls, for example compositing drawn regions, marking regions invalid, clipping, capturing events and cascading them, and so on. Note: Frame derives from Control, Container, and Window.

08_974018-ch03.indd 7508_974018-ch03.indd 75

8/31/10 12:35 AM8/31/10 12:35 AM

76

Part I



About bada

In most cases your app can happily let Frame take care of all these details. Rarely, if ever, will you need to think about window behaviour at all, and typically you will only ever use derived Window classes such as Frame. As the Frame is the root of your GUI hierarchy, getting hold of the Frame is the starting point for setting up the UI when an app initialises. Within any Form method, getting the Frame is easy: Frame *pFrame = GetAppFrame()->GetFrame();

Typically, a Form does not declare a Frame pointer member; instead, it dynamically allocates the Frame pointer, *pFrame in the example above, when it is required. Note: While Frame is at the top of the logical hierarchy of all GUI elements in an application, and has displayable properties – for example, its background and transparency – Frame itself is only displayed if no Form exists; what the user sees are the GUI elements that are contained by the application’s Forms, or in the case of a full-screen app that does not use Forms, the user sees directly rendered graphics. It is important to remember that although Frame is Container-derived, it is a special case of a Container; the only Control type that can be added to a Frame is Form, using the AddControl() method, which is reimplemented from Osp::Ui::Container: Osp::Ui::Controls::Frame::AddControl ( const Osp::Ui::Control control) [virtual] Osp::Ui::Controls::Frame::AddControl (const Osp::Ui::Control control) [virtual]

Frame includes a number of methods that enable Forms to be manipulated: ■■

AddControl()

■■

RemoveControl()

■■

GetCurrentForm()

■■

SetCurrentForm()

Conceptually, an app that requires multiple screens should define multiple Forms, one Form per screen. Within the UI code, a Form manager should be implemented to handle Form switching in response to user actions, using the ‘get’ and ‘set’ methods above. In practice, the simplest interaction design for a multiple screen app is to use a tabbed Form. In this case, because the tab is implemented as a Form property, all the screens of a tab in fact belong to the same Form. The easiest way to

08_974018-ch03.indd 7608_974018-ch03.indd 76

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

77

manage switching in this case is to implement each screen as a separate Panel, with all the Panels belonging to the same Form. Instead of switching Forms, the switching logic should switch between Panels. Frame can be used directly to create a non-standard GUI by rendering graphics to its Canvas, instead of populating it with a Form and controls (see Section 3.3 below). This approach is typically used for games and other fullscreen apps. Note that it is always preferable to create Form-based apps than Frame-based apps, because OnDraw()is not implemented for Frames. This means that a Frame-based app may cause flicker when updating the screen, because the Frame must manage screen updates, not the framework.

3.2.4 More about Form Except for the special case of a full-screen app (or what the Application Wizard refers to as a Frame-based application), a Form is the starting point for GUI design. Like Frame, Form is a full-screen-sized container. Unlike Frame, Form can contain instances of any Control-derived class (with the exception of Frame; Frame cannot be instantiated by the app), and Form itself (a Form cannot contain another Form). As we saw in the previous chapter, because it encapsulates the full screen, Form includes system areas such as the Indicator and Title bars, and soft keys, as well as the application client area. In addition, the bada UI framework allows a Form to display an Option menu, which is launched from an Option key that displays at the bottom of the screen in the command area. In BuddyFix, for instance, we will use the Options menu to provide global options, such as managing settings and adding and removing buddies. Because the Option menu and soft keys are Form properties, it’s easy to add them just by updating Form properties in UI Builder. The change is trivial to make, but it’s worth thinking through the intended interaction semantics. In BuddyFix, possible actions we might assign to a soft key are: ■■

adding or removing a buddy;

■■

cancelling an action in progress, for example when setting or changing settings;

■■

backing out to the previous screen, which for a single-screen app means backing out to the phone’s home screen;

■■

pausing or unpausing location sharing for all buddies;

■■

‘nudging’ a buddy with an update.

A good rule of thumb is to reserve soft keys for actions that are used frequently, or that we want to make prominent. For now, ‘Add (buddy)’ and ‘Nudge (buddy)’ make a well-matched pair. The BuddyFix updated with the Soft Keys and Option menu key is featured in Figure 3.3.

08_974018-ch03.indd 7708_974018-ch03.indd 77

8/31/10 12:35 AM8/31/10 12:35 AM

78

Part I



About bada

Figure 3.3 BuddyFix updated with the Soft Keys and Option menu key display.

Let’s update the Form properties, save our resources, rebuild, and run. That’s as far as UI Builder will take us. Adding menu items to the Option menu, like adding list items to the buddy list, will require us to write some custom code.

3.3 Using Graphics Using graphics effectively is an important part of creating a good GUI experience for users, and bada provides comprehensive graphical primitives for vector graphics (drawing), bitmaps, animations, and fonts, as well as directly supporting OpenGL ES. In bada: ■■

all graphics are drawn to a Canvas object;

■■

at any time a global Canvas can be constructed that draws outside of the layout hierarchy;

■■

every control owns a local Canvas that can be requested and drawn to, and that draws within the layout hierarchy.

08_974018-ch03.indd 7808_974018-ch03.indd 78

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

79

3.3.1 More about Canvas The Canvas class enables direct access to the device display for drawing. Whenever you want to do direct drawing using graphical primitives (such as Line, Rectangle, Ellipse, Polygon, and so on, as well as TextElement for text and Bitmap for images, which are all members of the Osp::Graphics namespace), then you must use a Canvas. You can explicitly construct a normal (global) Canvas object from anywhere in your GUI: // Construct a “normal” or global canvas Canvas* pCanvas = new Canvas(); pCanvas->Construct();

Note that Canvas is always constructed in two-phases by allocating with operator new and initialising with Construct() (see Chapter 4, on twophase construction). A normal Canvas overlays the application Frame and bypasses the window (and Control) hierarchy, providing direct access to the display and overwriting anything within its display rectangle (including your current Form and any Controls it contains). If no rectangle is specified in construction, a normal Canvas is full-screen size. This means that Canvas can be used to set a full-screen background image. (Recall that both Frame and Form allow their background colour to be set, but will not load an image as background.) Once Canvas is drawn, any subsequent Draw() calls will overwrite it, allowing Controls (for example) to be drawn on top of it. However, this will only be as robust as the sequence of Draw() calls in your code. So use this with care. The more typical way of using Canvas, which operates within the window and control hierarchy (and therefore does not risk unintended overwriting of other GUI elements) is to request a local ‘window’ Canvas object. Every Controlderived object, from Form down through the Control hierarchy, owns a window Canvas object: // Get the window canvas Canvas* pCanvas = GetCanvasN();

In this case, the Canvas shares the context of its owning Control, including its display region and any other properties of the local graphics context that have been set. Typically, the caller then sets any desired display properties and draws, enabling a Canvas to be used to draw display primitives or background bitmaps directly to the screen within the context of a given Control, to create text or other graphics. In practice, Canvas is most useful in the context of Container controls such as Frame, Form, and Panel.

08_974018-ch03.indd 7908_974018-ch03.indd 79

8/31/10 12:35 AM8/31/10 12:35 AM

80

Part I



About bada

Canvas is not part of the Control hierarchy, and in fact is not part of the Osp::UI namespace; instead, it derives directly from the root bada Object class Osp::Base::Object, and is a member of the Osp::Graphics namespace. Canvas has the attibutes listed in Table 3.1, which you can set on any canvas, using methods such as SetForgroundColor() and SetLineWidth(). Table 3.1

Canvas attributes.

ATTRIBUTE

DESCRIPTION

Foreground color

Drawing colour for primitives

Background color

Background colour for clearing

Line style

Line style (only Solid)

Line width

Line width for primitives with a line style

Font

Font used for text drawing

Note: If you are drawing from within the OnDraw() call-back, then you should call GetCanvasN() on the parent Container control to retrieve the canvas that the Container is using, otherwise the control’s local canvas will be overdrawn by the parent, because drawing is always performed bottom-up through the list of controls owned by the container.

3.3.2 Graphics Primitives As you would expect, bada provides a comprehensive set of graphics primitives. These are always drawn to a Canvas object. The Canvas supplies the graphics context for the primitives that are drawn to it, in the form of the settable Canvas attributes shown. You can set and reset these dynamically at any time in your drawing code. The Canvas you draw to may be one you explicitly construct, or one you request from an appropriate Control. The Point, Dimension, and Rectangle classes are used to construct the various graphical primitives: Point

A two-dimensional point composed of X, Y coordinates. Dimension

An X, Y ordered pair of (width, height).

08_974018-ch03.indd 8008_974018-ch03.indd 80

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

81

Rectangle

A rectangular region with a top-left point (X, Y) and a width and height. Shapes are always constructed from the top left corner, which is the (0,0) point of the local coordinate space.

Simple Shapes and Text Note that for simple drawing of shapes and text, all the work is done by the Canvas. You do not need to explicitly create shape, line, or text objects; instead, set Canvas attributes and invoke a dedicated drawing method of the Canvas object, for example: 1. Construct a canvas: Canvas::Construct()

2. Clear the canvas: Canvas::Clear();

3. Set the line colour to red: Canvas::SetForegroundColor(Color::COLOR_RED);

4. Draw a rectangle onto the canvas: Canvas::DrawRectangle();

5. Show the canvas to the display: Canvas::Show();

For shapes, such as Ellipse, Polygon, Rectangle, set the fill attributes by calling Fill methods instead of plain Draw methods, for example: Canvas::FillRectangle(const Color &color, const Rectangle &rect);

Text can be drawn to a Canvas in a similar way: 1. Construct a canvas. 2. Construct a font with style and size: Font::Construct(FONT_STYLE_ITALIC, 32);

3. Clear the canvas. 4. Set the Canvas font: Canvas::SetFont(font);

5. Draw “BuddyFix!” to the canvas: Canvas::DrawText(Point(55, 55), L”BuddyFix!”);

6. Show the canvas to the display.

08_974018-ch03.indd 8108_974018-ch03.indd 81

8/31/10 12:35 AM8/31/10 12:35 AM

82

Part I



About bada

Note: Text can also be drawn directly into most (but not all) types of control – most obviously Label, which is specifically provided as a container for non-editable text, and EditArea and EditField, which are provided for editable text, as well as MessageBox, and the various List types and ListItem types. See the bada API reference documentation for details.

EnrichedText EnrichedText gives you much greater control of text styles. Using simple Canvas text styles only allows Direction, Underline, and Strikeout styles to be set. Using EnrichedText you can fully specify text styles by combining overall styles for the complete EnrichedText block, for example alignment and wrapping, with individual styles set for each TextElement object in the blocks, for example font styles and sizes, colours (see also Table 3.2). Table 3.2

EnrichedText attributes.

ATTRIBUTE

DESCRIPTION

Horizontalalignment

Left, centre, or right

Vertical alignment

Top, middle, or bottom

Text wrapping style

None, character wrap, or word wrap

Abbreviation

Whether the drawn text is abbreviated in case the text size exceeds the dimension of EnrichedText

Font size and style

The font size and style: plain, bold, or italic

Text color

The foreground colour of the text element

Background colour

The background colour of the text element

Outlinecolour

The outline colour of the text element

EnrichedText is still drawn using the Canvas, except that the text itself is explicitly created and passed as a parameter: pEnrichedText->Construct(Dimension(width, height)); pCanvas->DrawText(Point(left, top), *pEnrichedText);

08_974018-ch03.indd 8208_974018-ch03.indd 82

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

83

For example: 1. Create an EnrichedText: EnrichedText::Construct(dimension);

2. Set the attributes of the EnrichedText: EnrichedText::SetTextWrapStyle(TEXT_WRAP_CHARACTER_WRAP);

3. Create and add TextElements to the EnrichedText: TextElement::Construct(L”01234567890123“); EnrichedText::Add(TextElement&);

4. Set the attributes of the TextElement, for example, colour and font: TextElement::SetTextColor(Color::COLOR_BLUE); TextElement::SetFont(font);

5. Construct and clear a canvas. 6. Display the EnrichedText: Canvas::DrawText(Point(10, 10), *pEnrichedText);

7. Show the canvas on the display.

3.3.3 Bitmaps and Images For many apps, the ability to display and manipulate images is an essential requirement: ■■

Images may be used purely for GUI effects as background images, patterns, icons, and so on for display within (or as complete backgrounds to) GUI controls.

■■

Images may form part of the app’s displayable data, for example, thumbnail pictures of people, places, or things.

■■

Images may be originated on the phone itself (by the camera, or by using a drawing or image editing app), uploaded from a memory card or via short link (Bluetooth) or cable connection, downloaded over the network (say, from Flickr), or embedded in the app by the developer at build time (background images used in the UI).

In all of these cases, typically the image exists in the first instance as a data file.2 In file format it will be viewable by media player and browser apps, assuming the file is a supported format.

2

This is a simplification. Images can also be stored as binary data in byte buffers. See the bada API reference documentation.

08_974018-ch03.indd 8308_974018-ch03.indd 83

8/31/10 12:35 AM8/31/10 12:35 AM

84

Part I



About bada

Before it can be used within an application, image data must be loaded from file into memory. Image data that is held in memory on the phone should typically be saved into a file format before it is transferred off the phone, or before it can be shared with other apps on the phone. In bada, the Bitmap class encapsulates image data in memory, and the Image class is provided as a utility class to perform conversions both ways between files and bitmaps, as well as directly between different file formats. Using the Image class, image data can be: ■■

decoded into a bitmap from a supported file format;

■■

or encoded from a bitmap into a supported file format.

A Bitmap object contains a (decoded) physical copy of the original file data, stored in a standard bitmap format (see below). This means that after decoding, the Image object and the original image file are no longer required. To create a Bitmap object from an image file: 1. new and Construct() an empty Image object: Image* pImage = new Image(); pImage->Construct(); Bitmap* pBitmap = null;

2. Call the Image.DecodeN() method to decode the image data from the file. DecodeN() returns a Bitmap object: pBitmap = pImage->DecodeN(L”/Res/bada.png”, BITMAP_PIXEL_FORMAT_ARGB8888);

3. Delete the Image object: delete pImage;

4. Use the Bitmap object, and delete when no longer required, for example: pButton->SetNormalBitmap(Point(0,0),*pBitmap); delete pBitmap;

Specifically, the Image class contains utility methods for handling images: ■■

encoding and decoding image data to/from file;

■■

converting bitmap or file image data between image formats;

■■

Compressing JPEG images;

Decoding image data supports the following file types: ■■

JPEG

■■

GIF

■■

PNG

08_974018-ch03.indd 8408_974018-ch03.indd 84

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3 ■■

BMP

■■

TIFF

■■

WBMP



Beyond the Basics

85

Encoding supports the following file types: ■■

JPEG

■■

PNG

■■

BMP

Three different bitmap formats are supported by bada. The bitmap pixel format specifier defines the colour mode of the destination bitmap and accepts the following enumerated types: RGB565 pixel format

BITMAP_PIXEL_FORMAT_RGB565

ARGB8888 pixel format

BITMAP_PIXEL_FORMAT_ARGB8888

R8G8B8A8 pixel format for OpenGL

BITMAP_PIXEL_FORMAT_R8G8B8A8

The pixel formats represent the following standard colour modes: ■■

RGB565 specifies 16-bit RGB with 5 bits of red and blue, and 6 bits green.

■■

ARGB8888 specifies 32-bit Alpha RGB with 8 bits each.

■■

R8G8B8A8 is an alternative 32-bit, byte-based format preferred by OpenGL(R).

See FGrpBitmapCommon.h, the header file for all enumerations of the Bitmap class. As with the graphics drawing primitives, Bitmap objects represent pixel data and are displayed by drawing the Bitmap object into a region of a Canvas, and showing the Canvas. Because every image has a ‘real’ size (the size at which it was created), which may not be the size at which you wish to display it on the phone, decoding from an image file supports image scaling. Other transformations, for example rotation, can be performed when the image is drawn to the Canvas. A bitmap can also be clipped to a region of the Canvas, as a separate step from sizing and positioning the screen region (which must always be a rectangle) to which it is drawn. The following is a complete example, with code, of the steps required to display a bitmap.

08_974018-ch03.indd 8508_974018-ch03.indd 85

8/31/10 12:35 AM8/31/10 12:35 AM

86

Part I



About bada

Create a Bitmap from File FMedia.h is the header file for Media namespace which contains the Image class, while Bitmap is defined in the Graphics namespace in FGraphics.h. The required #include declaration is: #include FMedia.h #include FGraphics.h

FMedia is the required library to use the classes in the Media namespace, while FGraphics is required to use the classes, such as Bitmap, defined in Graphics. The required namespace declaration is: using namespace Osp::Media; using namespace Osp::Graphics;

Privilege level is NORMAL. Privilege group is IMAGE. Image construction is performed as: result r = E_SUCCESS; Image *pImage = new Image; r = pImage -> Construct(); if (IsFailed(r)) { // handle error condition }

r contains E_SUCCESS if the method was successful, and an error status otherwise. For more about system error values see FBaseErrors.h, which defines all framework error codes. Image provides four decoding methods: 1. Takes a source file image path string and destination bitmap pixel format specifier. ■■

No resizing performed.

■■

Original aspect ratio preserved:

Bitmap* DecodeN(const Osp::Base::String& srcImagePath, BitmapPixelFormat colorFormat) const;

2. Takes a source file image path string and destination bitmap pixel format specifier, plus output image width and height. ■■

Resized as specified:

Bitmap* DecodeN(const Osp::Base::ByteBuffer& srcImageBuf, ImageFormat srcImageFormat, BitmapPixelFormat colorFormat, int destWidth, int destHeight) const;

08_974018-ch03.indd 8608_974018-ch03.indd 86

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

87

3. Takes a reference to a source buffer and destination bitmap pixel format specifier. ■■

No resizing performed.

■■

Original aspect ratio preserved.

Bitmap* DecodeN(const Osp::Base::ByteBuffer& srcImageBuf, ImageFormat srcImageFormat, BitmapPixelFormat colorFormat) const;

4. Takes a reference to a source buffer and destination bitmap pixel format specifier, plus output image width and height ■■

Resized as specified.

Bitmap* DecodeN(const Osp::Base::ByteBuffer& srcImageBuf, ImageFormat srcImageFormat, BitmapPixelFormat colorFormat, int destWidth, int destHeight) const;

Continuing the code fragment from above, with result r declared and pImage constructed: Bitmap* pBitmap = null; String path(L”/Res/Sample.jpg”); pBitmap = pImage->DecodeN( path, BITMAP_PIXEL_FORMAT_RGB565, SCREEN_WIDTH, SCREEN_HEIGHT ); if (null == pBitmap) { delete pImage; } //Your code goes here… //Finally, delete the image instance delete pImage;

Note that we delete the Image object as soon as we have finished with it, or in case of error, we must delete it. Because pBitmap and String are not constructed (but are just declared as automatics), we should not call a destructor on them; they will simply be deallocated when they go out of scope when the method returns. In the code above, we create a String object to store the path; more efficiently, we can use the L macro to create a string literal within the method call: pBitmap = pImage->DecodeN(L”/Res/Sample.jpg”, BITMAP_PIXEL_FORMAT_ RGB565, SCREEN_WIDTH, SCREEN_HEIGHT );

Draw a Bitmap onto a Canvas Now that we have created the bitmap we can use it. For example, to display the bitmap, we get the Canvas for the Form (or Frame if we have no Form), draw to the canvas and Show() it.

08_974018-ch03.indd 8708_974018-ch03.indd 87

8/31/10 12:35 AM8/31/10 12:35 AM

88

Part I



About bada

Continuing the code fragment: // Create a rectangle to draw into, get the bounds of the client area Rectangle rect = TopBoardViewForm-> GetClientAreaBounds(); // Get a Canvas instance Canvas *pCanvas = null; pCanvas = pForm -> GetCanvasN(); // If we want to display directly in the app Frame then we get the // Canvas instead with: // pCanvas = GetAppFrame()->GetCanvasN(); r = pCanvas -> DrawBitmap(rect, *pBitmap); if (IsFailed(r)) { delete pCanvas; } r = pCanvas->Show(); if (IsFailed(r)) { delete pCanvas; } // Your further code … delete pCanvas;

To draw the bitmap to the canvas, we must create a rectangle to draw into. Note that the rectangle size, not the bitmap size, determines the size of the bitmap drawn. Note, also, that we must delete the Canvas object in the case of failure. In the code fragment above we set the Canvas rectangle from the available client area. To create an arbitrary rectangle we would use the rectangle initialising constructor, for example we could supply the values x=20, y=80, width=440, height=440: Osp::Graphics::Rectangle::Rectangle (int x, int y, int width, int height);

Note: You can construct a Canvas larger than the device screen. In FGrpCanvas.h: result Construct(const Rectangle& rect);

3.3.4 Colours Finally, to complete this survey we will look briefly at the Color class. Colour values do not occur as frequently in code as, say, String or Number types, but most apps – in fact, all apps – are clients of the graphics classes that define colours, and it will help to have at least a casual understanding of how colours are used and manipulated in bada.

08_974018-ch03.indd 8808_974018-ch03.indd 88

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

89

Mobile phones have come a very long way from the early, monochrome (or green-screen, text-based), devices that at least some of us remember from the early days of our careers in mobile development. In fact, Samsung is a technology leader in display technology and has consistently driven phone specifications toward the high end, breaking new ground with HD (High Definition) and AMOLED display technology. Phones such as Wave have physically big screens with high pixel density and bright, highcontrast, outdoor-readable screens with vibrant colour. With the widespread availability of hardware graphics acceleration and shader support, UI effects such as transparency, animation, and full-3D are now possible on phone displays, where just a few years ago they were unthinkable. Interestingly, AMOLED technology has brought device displays into the power-management equation in a surprising way. Unlike standard LCD technologies, OLED (Organic Light-Emitting Diode) displays use active pixels for which power requirements vary depending on the hue being displayed by the pixel. Quite literally, darker colours are cheaper (in power usage) than lighter colours, meaning that UI designers can now add power-usage to the list of factors determining their design choices for app palettes and colour schemes. In bada, colours are defined using the ARGB colour model, which uses Alpha (i.e. transparency), Red, Green, and Blue values. Note: Not all graphics objects in bada have an alpha channel. Bitmap and Canvas both do, and both therefore support alpha blending. The Color class provides useful built-in functions including: ■■

Setting and getting colour components for or from a Color object, with values for all ARGB or specific colour values (and alpha), as well as a 32-bit colour value.

■■

10 predefined colours.

All colours are 32-bit entities supporting 24-bit ‘true-colour’ or ‘millions of colours’ display, with 8 bits for each of red, green, blue, and alpha data. If a device display supports a lesser physical bit depth, colours are down-sampled, resulting in a loss of quality. Pixels, by the way, are always square on bada phones.

3.4 The BuddyFix UI Revisited As we saw, UI Builder only gets us so far in creating a functional UI. In particular, to complete the basic UI for BuddyFix we will need to:

08_974018-ch03.indd 8908_974018-ch03.indd 89

8/31/10 12:35 AM8/31/10 12:35 AM

90

Part I



About bada

■■

Implement the ‘Add’ soft key.

■■

Implement the Option menu.

Also, before we can make any final decisions about the layout of the main list and its items, we will need to populate it.

3.4.1 Adding an OptionMenu The Option menu pops up when the user presses or swipes the Option soft key (also known as the handle) in the command area at the bottom of the screen for a Form for which FORM_STYLE_OPTIONKEY is true. Each Form can choose whether or not to enable an Option menu, and each Form can define its own Option menu. The UI guide specifies some guidelines for designing an Option menu: ■■

Soft key functions should not be duplicated in the Option menu.

■■

The maximum number of menu items is 12, but the preferred limit is eight, and four to six items is probably better still.

■■

Menu items can have secondary items, for which the preferred limit is four sub-items.

The OptionMenu class derives from Control via Container. The principles for constructing and using an Option menu are as follows: ■■

Construct an OptionMenu object dynamically, typically when initialising the Form that will display the menu.

■■

Set an event ID and a listener for the option key press action.

■■

Create the menu items and add an event ID for each item.

■■

Implement an action event handler that responds to the key and menu item event IDs.

■■

Delete the OptionMenu object, typically when terminating the Form that will display the menu.

Event IDs are just integer values. Typically we assign 100 to the key event, 101 to the first top-level item, 201 to the first sub-item, and so on: static const int ID_OPTIONKEY = 100; static const int ID_OPTIONMENU_ITEM_1 = 101; static const int ID_OPTIONMENU_SUBITEM_1 = 201;

Once the event IDs have been set and the listener has been added, the framework will return event IDs corresponding to user actions performed on the menu.

08_974018-ch03.indd 9008_974018-ch03.indd 90

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

91

In BuddyFix we will implement the following top-level Option menu items and sub-items: Buddies

Top-level item

Add Buddy

Sub-item, add a new buddy to the buddy list

Remove Buddy

Sub-item, remove a buddy from the buddy list

Pause sharing (if active) or Unpause sharing (if paused)

Top-level item, globally pause or unpause location sharing for all buddies

Settings

Top-level item, launch a Settings popup

About

Top-level item, launch an information popup providing app version and other information

Let’s look at the code. Firstly in MainListForm.h, we add an OptionMenu pointer member pOptMenu, and event ID definitions: class MainListForm : public Osp::Ui::Controls::Form { // ...etc // Option Menu declarations protected: Osp::Ui::Controls::OptionMenu* pOptMenu; static const int ID_OPTIONKEY = 100; static const int ID_OPTIONMENU_ITEM_1 = 101; static const int ID_OPTIONMENU_ITEM_2 = 102; static const int ID_OPTIONMENU_ITEM_3 = 103; static const int ID_OPTIONMENU_ITEM_4 = 104; static const int ID_OPTIONMENU_ITEM_5 = 105; static const int ID_OPTIONMENU_SUBITEM_1 = 201; static const int ID_OPTIONMENU_SUBITEM_2 = 202; };

Next, in MainListForm.cpp, we add code to construct and assign the OptionMenu object. Event IDs are set by passing the ID to the item or subitem constructor method. We must also invoke two Form methods: SetOptionkeyActionId(ID_OPTIONKEY); AddOptionkeyActionListener(*this);

The Form initialisation code now looks as below. Notice the use of twophase construction to separately allocate and initialise the OptionMenu object:

08_974018-ch03.indd 9108_974018-ch03.indd 91

8/31/10 12:35 AM8/31/10 12:35 AM

92

Part I



About bada

bool MainListForm::Initialize() { Form::Construct(L”IDF_MAIN_LIST_FORM”); // Create the OptionMenu // Member in MainListForm Osp::Ui::Controls::OptionMenu* pOptMenu pOptMenu = new OptionMenu; pOptMenu->Construct(); pOptMenu->AddItem(“Buddies”,ID_OPTIONMENU_ITEM_1); pOptMenu->AddSubItem(0, “Add Buddy”,ID_OPTIONMENU_SUBITEM_1); pOptMenu->AddSubItem(0, “Remove Buddy”,ID_OPTIONMENU_SUBITEM_2); pOptMenu->AddItem(“Pause Sharing”,ID_OPTIONMENU_ITEM_2); pOptMenu->AddItem(“Unpause Sharing”,ID_OPTIONMENU_ITEM_3); pOptMenu->AddItem(“Settings”,ID_OPTIONMENU_ITEM_4); pOptMenu->AddItem(“About Buddy Fix!”,ID_OPTIONMENU_ITEM_5); // Invoked on the Form, not the menu SetOptionkeyActionId(ID_OPTIONKEY); AddOptionkeyActionListener(*this); return true; }

As we have allocated the menu object, we are responsible for deleting it. In MainListForm.cpp: result MainListForm::OnTerminating(void) { result r = E_SUCCESS; delete pOptMenu; return r; }

Finally, we need to handle the events that menu actions generate. In MainListForm.cpp, we add listener code into the OnActionPerformed() method: void MainListForm::OnActionPerformed(const Control& source, int actionId) { switch (actionId) { case ID_OPTIONKEY: ShowOptionMenu(); break; // Menu items case ID_OPTIONMENU_ITEM_1: // Todo: insert your code here break; // ... etc // Menu sub-items case ID_OPTIONMENU_SUBITEM_1: // Todo: insert your code here

08_974018-ch03.indd 9208_974018-ch03.indd 92

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

93

break; case ID_OPTIONMENU_SUBITEM_2: // Todo: insert your code here break; default: break; } }

Our implementation is nearly complete. The final step is to add methods to dynamically show and hide the menu. Hiding the menu is performed by the framework, but showing it when the option key is pressed (or swiped) is our responsibility. In MainListForm.cpp: void MainListForm::ShowOptionMenu(void) { pOptMenu->SetShowState(true); pOptMenu->Show(); } // void MainListForm::HideOptionMenu(void) { pOptMenu->SetShowState(false); Draw(); Show(); }

Note the asymmetry in the use of Draw() and Show(). In ShowOptionMenu(), Show() is called on the Option menu object. In HideOptionMenu(), Draw() and Show() are called on the Form that owns the Option menu. While there is nothing complex about the code we have had to write, it is not entirely trivial. In an app that used multiple forms, we would probably choose to factor the Option menu code out into a separate OptionMenuManager class, to be shared by all Forms, with each Form requesting its own subset of the available menu items and sub-items.

3.4.2 Adding a Soft Key Adding a soft key is easy. The soft key behaves exactly like the Option menu key. In the definition of MainListForm in MainListForm.h, we add a soft key ID as a protected member, just as we did for the Option menu: static const int ID_LEFT_SOFTKEY = 900;

In the Initialize() method in MainListForm.cpp, we add two lines, to set the soft key action ID and listener, just as we did for the option key: SetSoftkeyActionId(SOFTKEY_0,ID_LEFT_SOFTKEY); AddSoftkeyActionListener(SOFTKEY_0, *this);

08_974018-ch03.indd 9308_974018-ch03.indd 93

8/31/10 12:35 AM8/31/10 12:35 AM

94

Part I



About bada

That’s it. To capture and handle the Softkey event, in MainListForm.cpp we add an appropriate case at the top of the OnActionPerformed() switch statement: switch (actionId) { case ID_LEFT_SOFTKEY: ShowOptionMenu(); break; case ID_OPTIONKEY: ShowOptionMenu(); // ... etc default: break; } }

3.4.3 Populating a List We still can’t see how our app’s buddy list looks or behaves until we have populated it with some content. As we are only interested in the UI behaviour, we will defer any other complexity and write a test method to populate the buddy list with dummy data. This will allow us to exercise the list functionality and validate the UI behaviour. To start with we would just like to add some data to the list so that we can see how it looks. To add an item, we will write a method TestAdditem(), and add it as a protected method of MainListForm. Recall that we chose the format: LIST_ ITEM_DOUBLE_IMAGE_TEXT_FULLTEXT, to display a first line of image and text, and a second line of text. The parameters we will need to pass are those that will be needed by List. AddItem(): ■■

pText1 – the first line of our text, the buddy name string;

■■

pText2 – the second line of text, the buddy location stamp string;

■■

pBitmap1 – the first normal bitmap, the buddy picture;

■■

pBitmap2 – not used;

■■

itemId – an integer ID to allow us to identify this list item.

This is the prototype we add to MainListForm.h: // Implementation protected: //Test method, add an item to the list result TestAdditem( const Osp::Base::String* aBuddyName, const Osp::Base::String* aLocationStamp, const Osp::Graphics::Bitmap* aBuddyPic );

08_974018-ch03.indd 9408_974018-ch03.indd 94

8/31/10 12:35 AM8/31/10 12:35 AM

Chapter 3



Beyond the Basics

95

This is the stub implementation we add to MainListForm.cpp: /* * Test method, add an item to the main buddy list */ result MainListForm::TestAdditem(const Osp::Base::String* aBuddyName, const Osp::Base::String* aLocationStamp, const Osp::Graphics::Bitmap* aBuddyPic) { AppLog(“TestAdditem()\n”); return E_SUCCESS; }

First of all, we will need to create a Bitmap object to pass to this method. We can assume that in our final implementation, the bitmap and name string will be retrieved from the Contacts app. For now, we will need to supply the bitmap ourself. Because this is interim code we will make it part of the test method itself, and create a single dummy bitmap we can pass to every test item we create (so that the prototype changes). To use bitmaps and images, in manifest.xml declare:

IMAGE

For a production app you should use the Application Manager on the developer.bada.com portal. To use bitmaps and images, in MainListForm.h: #include FGraphics.h #include FSystem.h #include FMediaImage.h

To use bitmaps and images, in MainListForm.cpp: using namespace Osp::Graphics; using namespace Osp::Media;

Note: Don’t forget to add your link library! This now builds. We can now tweak the prototype to leave the image parameter out, because we create the dummy bitmap in the method. Now we can test calling the method:

08_974018-ch03.indd 9508_974018-ch03.indd 95

8/31/10 12:35 AM8/31/10 12:35 AM

96

Part I



About bada

/* * Test method, add an item to the main buddy list */ result MainListForm::TestAdditem(const Osp::Base::String * aBuddyName, const Osp::Base::String * aLocationStamp) { // First, get a pointer to the main list, by name List* mainlist = static_cast(GetControl(L”IDC_MAIN_LIST” )); if (mainlist) AppLog(“Not null list\n”); else AppLog(“Null list!\n”); // Create a dummy bitmap to put into buddy list entries result r = E_SUCCESS; Image* dummyimage = new Image; Bitmap* bitmap = null; r = dummyimage -> Construct(); if (IsFailed(r)) { // Handle error condition } bitmap = dummyimage->DecodeN(L”/Home/94-novag.png”, BITMAP_PIXEL_FORMAT_RGB565, 52, 52); if (null == bitmap) { // Handle error condition } //Delete the image instance delete dummyimage; AppLog(“TestAdditem() %s %s \n”, aBuddyName, aLocationStamp ); // Okay, now make a list item // r = mainlist->AddItem(*aBuddyName, *aLocationStamp, bitmap, bitmap, 500); r = mainlist->AddItem(aBuddyName, aLocationStamp, bitmap, null, 500); return r; }

Invoke with: String dummyname(L”Elvis”); String dummylocstamp(L”Has left the arena”); result r = TestAdditem(&dummyname, &dummylocstamp ); // Log it! AppLog(“result = %s”, GetErrorMessage(r));

We can now see the list item. This is not the final UI, but we have shown the essentials that BuddyFix uses. Look out for news of the final app at developer.bada.com.

08_974018-ch03.indd 9608_974018-ch03.indd 96

8/31/10 12:35 AM8/31/10 12:35 AM

CHAPTER

4 bada Fundamentals

This chapter starts with an overview of the bada platform – its origins and its architecture – and moves on to look at its programming idioms and conventions, and the bada class library and its platform-specific types. It concludes with some practical quick tutorials that run through the most important of bada’s C++ programming idioms.

What You Will Learn This chapter aims to give you the context you need to use bada effectively as a developer. It gives the bigger-picture view of what bada is. You will learn about: 1. The high-level system architecture 2. The bada class library and the platform specific types you’ll be using in your apps, including collections, strings and numbers 3. The idioms and naming conventions you’ll need to know to write, and read, bada code

What You Will Need To get the most from this chapter we recommend – apart from the bada SDK and IDE – a cup of tea and an armchair – but any other refreshment will do quite nicely! 97

09_974018-ch04.indd 9709_974018-ch04.indd 97

8/31/10 12:36 AM8/31/10 12:36 AM

98

Part I



About bada

4.1 Architecture Overview When bada was announced (in fact, even when it was still just a rumour), there was much talk about bada as a new mobile OS, but that’s rather misleading; that’s not really what bada is at all. Yes, bada is new, but is it a new OS? Not really, or anyway not by the usual definitions. An OS is the layer between the hardware and the applications that allows the applications to use the hardware and make the best use of it. For this, an OS deals with providing and coordinating the available hardware resources. As we elaborate in more detail in section 4.1.3, the bada smartphone platform is described as having four layers; the bottom level is the Kernel layer, while the top level is the Framework layer, which provides the APIs to applications. This has two essential advantages: first, the underlying OS can be exchanged resulting in greater flexibility and independence. Second, the apps really deal with the open interfaces provided by that extra abstraction layer, which is always the same. This helps to overcome fragmentation to a certain degree, at least. Hence bada is a platform, where that means a software architecture for creating and running apps, and implies a complete architecture. But the simplest way to think of bada is as a C++ class library supported by a small number of C++ frameworks, supported by middleware, base, and kernel layers. It’s a very complete platform, including a GUI and programming frameworks, a suite of ‘base’ or built-in applications, an application environment, a strong set of middleware services, and, unusually, a suite of service-centric APIs that integrate seamlessly with the platform APIs. At the very bottom runs the Kernel layer of bada. Since bada is strictly kernel-agnostic, this could be Linux or any commercial real time operating system (RTOS). bada is flexible so that the appropriate kernel can be chosen depending on the device hardware. From the point of view of this book, things are even simpler. Because this is a programming book, written for working programmers, we’ll emphasise the practical definition of bada and the Framework layer, which provides the C++ APIs.

4.1.1 bada Features Putting the semantics to one side, what does bada have to offer you, as an app developer with a great idea, or even an existing great app written for another platform? Quite a lot, is the answer. It includes not just a full complement of engines and runtimes – for example Flash and WebKit – but also a suite of network hosted (i.e. off-device) services for phone network, location, social networking and commerce, that are integrated into the platform at API level. So that, for example, your app calls the commerce APIs in much the same way that it calls the graphics APIs or accesses hardware features like sensors – all very nicely abstracted for the programmers.

09_974018-ch04.indd 9809_974018-ch04.indd 98

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

99

At the UI level, the middleware supports all of the things you are likely to want to do, and bada devices are cool, sexy, and full-featured. Devices, in fact, are perhaps the biggest part of the bada story – which is exactly what you might expect from Samsung. Samsung ships well over 200 million phones a year. In 2009, 40 million of these phones were touch-screen based and this number is expected to grow significantly in 2010. bada will be the main platform for touch-screen phones, replacing Samsung’s previous proprietary platform. These numbers are what bada is really about. Its goal is to open a platform that has been highly successful in the marketplace (it has driven Samsung into the number 2 slot for mobile handset vendors, after all) to bada apps developed by third-party developers. That goal will have the effect of driving the app revolution into its next phase, and pushing it down into the midrange from the high end of coveted but expensive devices – whether those are Apple devices running iOS or smartphones from all vendors, including Samsung, running smartphone OS such as Symbian, Android, Windows Mobile, and LiMo. That midrange of ‘phones for the rest of us (including your Mum)’ has proved to be fertile territory for Samsung to date, and opening it up to apps is a logical step. But let’s stop talking like marketers, and get down to nuts and bolts.

4.1.2 A Short bada History In this book, we are interested in understanding the platform software from the app developer’s perspective. In other words, our real focus is on how to use the platform and take advantage of its features to write cool bada apps. But the context in which a system has grown and evolved, and the stages through which it has evolved, have a big impact on the way it is put together, and understanding how a system is put together can help you understand how to get the best from it. Samsung started development of its in-house 3G phone platform sometime around 1999. As Samsung watchers know, one enduring principle of its phone business is to provide every phone platform for which there is market demand. At the time of writing, Samsung ships phones on each of Android, LiMo, Symbian, and Windows Mobile, as well as its proprietary platform, not to mention the first bada phone, the Wave. And these are not just any old phones. Samsung ships flagship models, or Hero devices in company-speak, on these platforms – from the LiMo H1 to the Symbian i8910 HD to the Windows Mobile Omnia II. Wave is no exception – its features put it right at the head of the field, with its Super AMOLED screen, ARM Cortex A8 1 GHz processor and support for 3D gaming and HD video recording and playback.

09_974018-ch04.indd 9909_974018-ch04.indd 99

8/31/10 12:36 AM8/31/10 12:36 AM

100

Part I



About bada

Nor is bet on every platform just a software strategy. A similar story can be told for the underlying hardware. Across the range of Samsung handsets you’ll find chipsets from TI, ST Micro, Qualcomm, and because Samsung also has the unique position among handset vendors of being a semiconductor fabricator, you’ll find Samsung chipsets. Again, perhaps uniquely, Samsung has been as successful in mobile markets dominated by CDMA-family technologies (the US and South Korea) as in those dominated by GSM-family technologies (Europe and Asia), and from 2G to 3G. These factors strongly influenced Samsung’s 2G to 3G transition strategy, as it became clear that the modest software and hardware platform requirements of 2G phones, with their simple text-based, state-oriented UIs, and low power draining modems, would be far exceeded by 3G requirements. Samsung’s 3G mobile platform was started as a solution to migration to 3G. It evolved over a dozen iterations with the first releases in June 2001 and final stable releases during 2004. Its aim was: ■■

to support multiple wireless technologies including: ■■

CDMA family technologies including cdma2000, EV-DO EV-DV;

■■

GSM technologies including GPRS and UMTS;

■■

TDMA for the China market;

■■

to support service evolution from voice to data to multimedia to video to information, and the most recent step to social networking;

■■

to be an app platform capable of competing with the likes of Symbian, Windows Mobile, BREW, Java phones;

■■

efficiency, with reference to the requirements of 40 MHz CPU MIPS and 500 KB ROM;

■■

multiple bearers (CDMA and 3G evolution, GSM and 3G evolution);

■■

multiple OS kernels;

■■

multiple chipset (Qualcomm, Thomson, TI);

■■

low to high end (midrange to smartphone);

■■

extensibility (frameworks);

■■

security (encrypted vtables, API access controls).

Substantially, this is the software that provides the foundation on which bada is built. It has been proven by several hundreds of millions of phones shipped in all global markets. From this point of view, bada is a new platform. It does, however, exploit a track record of well-proven concepts and implementations where selected components have been revised, improved, and integrated into bada platform.

09_974018-ch04.indd 10009_974018-ch04.indd 100

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

101

4.1.3 The Layered Model of the bada Platform Conceptually, the bada platform is described in terms of four layers. While application developers really only need to know the details of the top layer in order to create applications, it is useful to know more about the platform, how it’s designed and the potential it offers. The four-layer model is shown in Figure 4.1 and we’ll explain what’s contained in each layer below.

Figure 4.1 The bada architecture, a four-layer view.

At the very top of the Figure 4.1 you’ll notice that there are boxes representing three kinds of bada applications: device applications that run stand alone on the device, service applications that make use of the collaboration features of the bada Server (which we’ll explain in more detail later), and web-based and Adobe Flash® applications that the bada framework also supports through its standard controls. Your application could actually be some combination of all three types. The Framework layer consists of the APIs available to application developers, divided into the 20 top-level namespaces that are explained throughout this book and in detail in Chapter 6. These C++ APIs are the developer’s gateway to the functionality of the device. Here you’ll find the classes for implementing the architecture of an application, storing and restoring application state, supporting basic data types, and accessing system features such as the battery level. The namespaces also include classes for creating the application’s UI, 2D and 3D graphics and taking advantage of the multimedia features of the device. Through these APIs, developers can play and record audio and video, and access the camera, as well as take advantage of the motion, vibrator, and other sensors. It’s also home to the location namespace, which makes including a fully functional map control in your application really simple.

09_974018-ch04.indd 10109_974018-ch04.indd 101

8/31/10 12:36 AM8/31/10 12:36 AM

102

Part I



About bada

But it’s the service-oriented namespaces that make bada stand out from other platforms. Figure 4.2 shows a more detailed architectural view, illustrating how application functionality moves beyond the device to make use of the features of the bada Server. The real work of communicating with the server, to implement features such as collaboration, commerce, and web services, is done by the components in the Service layer. Developers use the APIs defined in the Framework layer to access features whether they’re implemented purely on the device or with support from the bada Server. For example, the Social namespace contains classes to manage the user’s address book and calendar on the device, but the Social:: Services sub-namespace contains a whole set of collaboration services that work with the bada Server, to share profile information, access third-party social networking sites, or find buddies – a good example being the BuddyFix application. Access to third-party sites, such as Facebook and Twitter, would normally involve writing complex code to communicate with each site, but developers use only the open APIs defined in the Framework layer and let the bada Server take care of the details of talking to the specific web service. A full explanation of these service-centric features can be found in Chapter 5.

Figure 4.2 The ‘system’ view of bada including the server-assisted APIs.

The Device layer contains components that provide access to the underlying features of the device. Figure 4.2 shows the different blocks of functionality, including components to handle communications, access to the file system, security, graphics and multimedia. The design of this layer is quite modular, which is a huge advantage when it comes to supporting new technologies. For example, support for new audio or video codecs, updated cameras, additional sensors, or new communications standards could be added by updating a few

09_974018-ch04.indd 10209_974018-ch04.indd 102

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

103

components rather than making huge changes to the whole of the underlying operating system. This makes the bada platform quite dynamic and offers lots of possibilities for developers to take advantage of the latest device hardware. All of the functionality provided by this layer is accessed by developers using the APIs defined in the Framework layer. At the bottom is the Kernel layer. The bada platform is designed to run, for instance, on Linux or on RTOS kernels, which makes the bada platform very flexible. It also offers the possibility of support for a wider range of devices than any other mobile platform. That’s a huge potential market for your bada applications.

4.2 bada Coding Idioms 4.2.1 C++ and bada Of all current mainstream programming languages, C++ is the most powerful and flexible. That doesn’t make it the most popular language. In fact, at the time of writing, C++ maintains a steady third place in popularity surveys, behind Java and C.1 There are good reasons why C++ is unlikely to win a popularity contest. Compared with more recent languages (Python, say, or even Java), it has a complex syntax. There are several reasons for this. One is its retention of C as a proper language subset. Another is the deliberate decision to favour terse and compact (and even cryptic) over verbose and transparent. Yet another is the breadth of the language – both high-level and low-level and everything in between – supporting procedural, object-oriented programming (OOP), and generic (template-based) programming styles. And finally, while the previous point suggests maximalist goals (include everybody!), C++ takes a very minimalist view of what a programming language should aspire to be. Its built-in types are essentially those of C, and there (more or less) the language ends. There are no frameworks, or class libraries, included in the language proper. (Even the minimalist std.h and stdio.h are strictly optional.) For all of these reasons, C++ is not the kind of language that holds your hand. This probably gives it a more fearsome reputation than it deserves. But it also means that any platform based on C++ must tame the language to suit its own purposes.

1

For example, according to the TIOBE Programming Community Index software survey, April 2010, see www.tiobe.com/index.php/content/paperinfo/tpci/index.html. Intriguingly, in 2010 Java and C have swapped places in the top two places, with C now the most popular language, as Java’s popularity share falls. Objective C meanwhile is roaring up the table. For comparison: C and Java score around 20%; C++ around 10%; and Objective C around 2%.

09_974018-ch04.indd 10309_974018-ch04.indd 103

8/31/10 12:36 AM8/31/10 12:36 AM

104

Part I



About bada

4.2.2 The Native System The bada platform itself is written in C++ (all frameworks, all higher-level components, and of course the bada class library), with some low-level C code (low-level components, kernel interfaces). The bada UI, application, and application services frameworks, and the suite of apps that are shipped on phones as part of the platform, are exclusively C++. And it’s those frameworks and the class library that the app developer sees.

4.2.3 Alternatives to Native On bada, then, native development means C++ development. However, there are other options open to app developers, for example runtimes such as Flash and WebKit, so long as the (relative) penalty of non-native performance is acceptable. These options are relevant when access to the complete native platform is not required, or when existing assets have been written using cross-platform technologies, or when cross-platform usage is the overriding requirement. There are plenty of possibilities on bada: ■■

A Flash engine is completely integrated at a low level with the native graphics architecture, making Flash a perfect choice for graphicsintensive apps (and in fact Flash is used as a system component by bada itself, enabling the phone’s UI to be written in Flash, making it seamlessly portable across multiple different families of phones in Samsung’s portfolio, across operating systems from Symbian to Windows Mobile, to Android and LiMo).

■■

WebKit is also fully supported. The bada native Dolfin browser is based on WebKit with support for HTML 4.0.1 and HTML 5.

This makes bada rich with choice for app developers, whether as a target for porting an existing app, or as a target for new apps.

4.2.4 C++ Pitfalls Coming back to native development, the C++ environment is modern, straightforward, and comprehensive. It is supported by standard, open tools including the Eclipse IDE and GNU/CodeSourcery C++ compiler.2 The pitfalls of C++ on constrained devices are well-known. It’s fair to ask if mobile platforms really can still be considered constrained, at least by the

2

From www.codesourcery.com – Sourcery G++.

09_974018-ch04.indd 10409_974018-ch04.indd 104

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

105

standards of the old definitions, in these days of 1 GHz processors and multigigabyte memory. The answer is that mobile is certainly constrained relative to the desktop, in almost all respects from CPU capability to available RAM to screen size and network bandwidth. But also, there are absolute constraints with mobile. Let’s not go through all the differences again (we looked at them in Chapter 1), but on mobile resources are critical in the following areas: ■■

memory – size and speed (e.g. flash, no HD);

■■

CPU;

■■

ROM;

■■

battery/power;

■■

network bandwidth.

The power and flexibility of C++ comes at a price. The most critical issues are: ■■

Memory management, which the application must manage for itself, in contrast with languages that provide garbage collection to reclaim allocated memory that is no longer in use.

■■

Exception handling, where the C++ standard exception mechanism is expensive in terms of memory footprint and processor cycles.

■■

Lack of native string and array types.

Most runtime failures (crashes) of C and C++ programs are caused by the same few common kinds of programming errors, specifically memory allocation errors and memory access errors, including pointer and array indexing errors. This simple fact is what motivates many of the distinctive features of Java. No pointers, true primitive types for arrays and strings, and automatic garbage collection. However, Java imposes a runtime cost that can be noticeable even on the desktop, and can be a showstopper on mobile; it also forces app developers into a sandbox in which access to native features is denied, reduces flexibility, and creates a barrier between apps and the native platform. On mobile, going native gives apps all the power of the underlying platform. However, the kind of tolerance for runtime failure that seems to have become a habit on the desktop is simply not acceptable on mobile. Mobile users will not accept data loss, calls hanging, or the other frustrations of buggy apps that crash or freeze.

09_974018-ch04.indd 10509_974018-ch04.indd 105

8/31/10 12:36 AM8/31/10 12:36 AM

106

Part I



About bada

To offer the best of both worlds – robust apps that don’t crash and a fully capable platform providing native performance – bada imposes some limitations on developers by limiting use of some C++ features, in particular: ■■

Platform code in bada uses two-phase construction (though it is not for classes you define yourself).

■■

A simple ownership policy is supported: an app is always responsible for deleting memory it allocates (every call to new must have a symmetrical call to delete), and an app must always delete platform allocated objects returned from a platform method named with a trailing N, for example SearchN(); in all other cases, the platform takes care of deleting the objects it allocates.

■■

Native C++ strings are discouraged; the bada platform provides a dedicated String class.

■■

Native C++ arrays are discouraged; the bada platform provides a dedicated Array class.

■■

Standard C++ exceptions are not supported; instead bada has its own lightweight exception model.

4.2.5 Native Idioms and Types Tutorials It’s time to get practical again. When you read through bada code in the SDK tutorials and samples below, you’ll see the native types being used in real world contexts, and of course you’ll need to use them in your own code. The following brief tutorials will get you up to speed with the things that bada does differently – and will be a useful reference to come back to as you explore the platform more deeply. You may want to bookmark these pages.

The Problem of Object Construction In C++, like C, memory at runtime is divided between: ■■

static memory, which is assigned by the compiler and is part of the application binary at runtime;

■■

stack memory, allocated and freed at runtime by the OS as function activation frames for the running program are created and released;

■■

heap memory, allocated and freed dynamically as requested by a program.

Memory leaks are caused when programs allocate heap memory and fail to release it. Because mobile phones typically run for days, weeks or longer without being switched off, memory leaks can seriously compromise the phone’s performance. The problem is compounded because (relative to the desktop),

09_974018-ch04.indd 10609_974018-ch04.indd 106

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

107

phones typically have much less RAM, and (in absolute terms) because of the power and physical size constraints of phones, memory technologies – for example Flash file systems – are slow. Unfortunately, in C++ the problem of ensuring that memory is not leaked is more complex than it is in C, and requires more than just discipline on the part of programmers (i.e. matching every allocation with a deallocation). In C++, allocating heap memory may be done either explicitly by the programmer with calls to operator new or new[], or implicitly by the compiler as part of C++ object creation. Unlike C, in which every runtime construct is either static or on the stack or on the heap, the parts of a single C++ object may be allocated in one or more or all of those allocations, depending on how the class has been coded.3 Because a C++ class has only one destructor (which will be the default one generated by the compiler, if the programmer has not explicitly coded a destructor), while it may have many different constructors, destructors must be coded with care. The result of all of which is that naive coding in C++ can very easily result in memory leaks. There are two specific problems that make matters even worse. The first problem is that in C++, when a constructor fails, the class’s destructor is not called. The problem of memory leaking is, as we have said, a problem with heap memory. (Static memory is never a problem, because it is allocated at compile time, and stack memory frames are automatically released when the functions with which they are associated return). A (heap allocated) C++ object is created when the new operator is called on a class constructor. The allocated memory must be released with a matching call to delete(), that is, allocation, and deallocation must always be symmetrical if memory is not to leak. Calling delete() invokes the class destructor. Within the destructor, any further memory allocated by the class should be released with appropriate calls to delete(). When the destructor returns, the final step performed by delete() is to release the memory that was allocated for the object itself. This is all straightforward enough. The problem arises if the class constructor attempts to allocate memory, for example calling new to create a class member that happens to be an object, and the allocation fails. In this case, the destructor cannot be called to delete the object, because the object pointer will be null (because construction failed), and trying to delete a null pointer will cause an exception. But meanwhile, if any allocations did succeed as part of construction before the failed allocation occurred, there is no way for either the system of the program to free that memory because no pointers exist to it. The allocated memory is orphaned. 3

For an excellent discussion with examples, see F. Franek, Memory as a Programming Concept in C and C++ (Cambridge University Press, 2004), Chapter 8.

09_974018-ch04.indd 10709_974018-ch04.indd 107

8/31/10 12:36 AM8/31/10 12:36 AM

108

Part I



About bada

On mobile, low memory conditions should be assumed to occur as a matter of course. Multitasking, web browsing, playing music, recording and viewing images, playing or recording video, and downloading and trying out apps are all part of the everyday use for a phone, and may occur in any dynamic pattern of usage. Any one may cause a memory usage spike, which if your own app is unlucky enough to encounter it, may cause memory to be unavailable to you. Worse, if any program running on the device is leaking memory then, over time, a low memory condition will become a certainty, and all apps on the device will effectively be compromised by the poorest quality app that the user has chosen to run. Let us assume we have a very simple class: class SimpleClass;

Then we have a more complex class that has objects of the SimpleClass as members. class ComplexClass { public: ComplexClass(void) { p1 = new SimpleClass(); p2 = new SimpleClass(); // Assume an Out-of-memory error occurs here. } ~ComplexClass(void) { delete p1; delete p2; } private: SimpleClass* p1; SimpleClass* p2; };

Then we have somewhere some method that instantiates an object of ComplexClass. void AnyClass::SomeMethod() { ComplexClass* pComplexClass = new ComplexClass(); // Calls the constructor, which could throw an exception. }

In doing so the constructor is invoked. But if an exception happens, the destructor is not called and the allocated memory cannot be released resulting in a memory leak. Java developers are spared these scenarios because all dynamic allocated memory is managed by the Java runtime (however, Java developers have plenty of other problems to make their lives hard).

09_974018-ch04.indd 10809_974018-ch04.indd 108

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

109

In fact, the scenario is not just a C++ problem. One of the most recognisable programming constructs in Objective C, on OS X for example, is two-phase object construction: id anObject = [[Rectangle alloc] init];

If you are familiar with the OS X idiom, or if you have programmed C++ apps on Symbian, then the bada solution should be immediately recognisable. Two-phase construction is just the rule that object creation and memory allocation for its members should be separated: class TwoPhaseClass { public: TwoPhaseClass(void) : p1(null), p2(null) {} ~TwoPhaseClass(void) { delete p1; delete p2; } result Construct(void) { p1 = new SimpleClass(); p2 = new SimpleClass(); // Out-of-memory error occurs. } private: SimpleClass* p1; SimpleClass* p2; };

Then we have somewhere some method that instantiates an object of TwoPhaseClass by using two-phase construction. void AnyClass::SomeMethod() { TwoPhaseClass* pTwoPhaseClass = new TwoPhaseClass(); result r = pTwoPhaseClass.Construct(); }

Because no memory for members is allocated during object creation, no memory can be leaked. Instead, we allocate memory in the Construct() method. If anything goes wrong an exception can be handled by querying the r variable of type result. The simple rule is that objects should be created in two steps: 1. Allocate: ■■

Dynamically allocate memory for the new object. This may include any simple value initialisation using initialisation list syntax.

09_974018-ch04.indd 10909_974018-ch04.indd 109

8/31/10 12:36 AM8/31/10 12:36 AM

110

Part I



About bada

2. Complete the construction: ■■

This should include creation of all objects that require dynamically allocated memory.

The object returned by the first step is not yet complete, and therefore cannot be used; but if memory allocation fails, as no memory has been allocated, there is nothing to clean up. If allocation succeeds, memory will have been allocated for all class members. Where members are simple values, there is no more work to be done if default values have been set using compile-time values, or at runtime using initialisation list syntax or (simple valued) passed parameters. Where members are themselves objects requiring dynamic allocation, memory for the member pointers will have been allocated, but not the objects themselves. The second step of object construction should now make any further allocations (and of course should also use two-phase construction for those objects where necessary). Used systematically, this is an easy convention to follow, and classes become self-documenting; wherever a Construct() method is present in the class, two-phase construction should be used.

Object Ownership Responsibilities A further small, but important, complication relating to memory allocation and object construction is that sometimes framework methods require the framework to allocate and return a new object to the calling app. However, once the object is returned by the framework, and the object is passed into the ownership of the caller, the framework no longer knows when the object is finished with. In this case, the simple rule that allocating and freeing memory should always be done symmetrically no longer holds. The problem for the app programmer is, then, to know whether or not the app, or the framework, should be responsible for cleaning up a given object. This problem is solved almost trivially in bada by a simple naming convention, and the associated rule: Convention

Trailing ‘N’ in a method name, for example Sometype SomethingN(); Rule

The caller is always responsible for deleting objects returned by a framework method named with a trailing ‘N’.

09_974018-ch04.indd 11009_974018-ch04.indd 110

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

111

To give an example, the interface IRemoteLandmarkStoreListener which is part of the Osp::Locations namespace defines a method OnLandmarksReceivedN(). This method is called when an application queries a remote server about its stored landmarks. If there are landmarks available that match the search criteria, they are stored in one of the parameters of the method. This parameter is local to the calling application, hence, the object ownership changes. The following code should exemplify this. void OnLandmarksReceivedN(RequestId reqId, IList* pResults, int pageNo, int countPerPage, int totalPageCount, int totalCount, result r, const String& errorCode, const String& errorMsg) { if (!IsFailed(r) && pResults) { // Do something with the results stored in pResults… pResults->RemoveAll(true); // You have to explicitly delete the object !!! delete pResults; } }

Exception Handling Exception handling arrived in C++ not exactly as an afterthought, but a long time after the first release.4 Efficiency was an important design goal,5 in particular avoiding adding time or space cost to code that doesn’t use exceptions. That goal was certainly achieved, but quantifying the cost for code that does use exceptions is more controversial. At least in the unoptimised case, ‘turning on’ standard C++ exception handling can add as much as a 10% code size increase to a system,6 with a measurable runtime performance penalty when exceptions are thrown and handled. For those reasons, as well as for reasons of simplicity, bada does not support native C++ exceptions, but instead implements a simple error handling mechanism. In bada: ■■

All exceptions are caught and returned as a simple type-defined result value.

4

See B. Stroustrup, The Design and Evolution of C++ (Addison-Wesley, 1994). C++ 1.0 was released in 1986, exceptions were included in 1992.

5

Stroustrup, Design and Evolution , p. 385.

6

See B. Morris, Symbian OS Architecture Source Book (Wiley, 2007). The example is Symbian.

09_974018-ch04.indd 11109_974018-ch04.indd 111

8/31/10 12:36 AM8/31/10 12:36 AM

112

Part I



About bada

■■

Framework methods that can fail return a result value, and app developers are encouraged to do the same in their own code.

■■

Framework methods are provided to get and set the ‘last result’, and get error messages, which assists simplistic propagation of exceptions.

This provides a minimal framework for propagating exceptions within application code, and a simple mechanism for returning and checking for exceptions. Significantly, it forces responsibility for exception handling onto the app developer. Looked at positively, it means that app developers are encouraged to ‘try to understand and handle problems’7 rather than bouncing them into an exception handling mechanism that, by convention, emphasises terminating programs upon exceptions rather than gracefully recovering. In this respect, mobile is different from more conventional desktop platforms. As Stroustrup himself explains, an important part of the design philosophy of C++ is to support the development of systems that execute ‘where no programmer is present’,8 for example telephone exchanges and ATMs. In those contexts, the recommended response of an application to an exception is termination.9 In a scientific or academic context such an approach to correctness is entirely appropriate, and it is indeed the kind of behaviour we have become accustomed to in (say) office applications on the desktop. But mobile couldn’t be more different; if my phone behaves like that, it will go straight back to the shop. The point to make about exceptions on mobile is not simply that they must be handled, but that they must be expected; low memory, low power, sudden loss of power, loss of connectivity and intermittent connectivity, and even the sudden loss of a file system (for example when removable media is abruptly removed from a device without first unmounting), are all everyday occurrences on mobile, and apps that respond to such events by promptly terminating will not be popular with users. On mobile, then, exception handling mechanisms do not just differ from the desktop in the degree to which any overhead they add may be acceptable, they also express different design philosophies and must respect different user expectations. If formality and correctness, as evident in abrupt termination, are most important on large systems, on mobile the values are opposite, and graceful degradation, or user friendliness, is the primary virtue. 7

In the (now possibly unfashionable) words of Doug McIlroy, quoted by Stroustrup, Design and Evolution, p. 384. 8

Stroustrup, Design and Evolution, p. 107.

9

For example, see Franek, Memory as a Programming Concept, p. 52: ‘We therefore suggest immediate program termination in the event of memory allocation failure.’ As he goes on to say, ‘of course’ some helpful message should also be reported to the user ‘so that the nature of the error can easily be determined if necessary.’

09_974018-ch04.indd 11209_974018-ch04.indd 112

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

113

Exceptions in Practice on bada

On bada, errors can be caught and handled, or propagated, by doing one of the following: ■■

Returning a result using the return type with an enumerated value, enabling a caller to test for a possible exception.

■■

Setting a result using an enumerated value, enabling a possible exception to be handled in a decoupled way by a method other than the immediate caller.

■■

Jumping to local handler label after testing a returned type for an enumerated value, enabling the exception to be handled immediately and locally, in the method in which the exception is detected.

Returning a result value and testing it has the advantages of immediacy and simplicity, where handling by the caller is appropriate: result r = E_SUCCESS; // ... // Case 1: The method returns a result. r = list.Construct(...); if (r != E_SUCCESS) // identical to ‘if (IsFailed(r))’ { // Process the error condition. }

Querying for the ‘last result’ is less direct, and runs the risk that the last caller to ‘set’ a result was not the expected caller. However, it may be useful where a more decoupled error handling is required within an app: // Case 2: The method sets the result in the method body or returns null. pObj= list.GetAt(...); if (GetLastResult() != E_SUCCESS) // or ‘if (pObj== null)’ { // Process the error condition. }

Jumping to a local label enables the error to be handled immediately and locally, which is the only recommended behaviour in the case that locally allocated resources require clean-up because of the exception: // Case 3 result r = E_SUCCESS; r = pList->Construct(..); TryCatch(r == E_SUCCESS, delete pList, “[%s] Some message.”, GetErrorMessage(r)); // ... CATCH: SetLastResult(r); Return null;

09_974018-ch04.indd 11309_974018-ch04.indd 113

8/31/10 12:36 AM8/31/10 12:36 AM

114

Part I



About bada

As the macro name implies in the third case above, this is really just a simple, local, and cheap, way of providing something like the familiar behaviour of try: catch: exception handling. As a final note, all exceptions are logged in the simulator to the Output pane, making it easy to trace errors without any explicit coding being required.

Interfaces C++ allows multiple inheritance, but only single inheritance is used in bada. There is nothing very new or surprising in that. The arguments about multiple inheritance, and whether it is a good thing or a bad thing, go back to the dawn of OOP. Allowing multiple inheritance fits with the non-prescriptive philosophy of C++, as well as with its goal of being a true modelling and simulation language, because in the real world, objects can belong to multiple categories. Restricting inheritance therefore implies a loss of flexibility and accuracy. The counter arguments – in the C++ context at least – mostly centre on precedence and ambiguity (What if multiple base classes have identically named methods? Which one will get called in the derived class?); efficiency (for example the ‘evil diamond’ pattern, which can cause code to be duplicated); and complexity (to use multiple inheritance well, programmers must understand it, which means yet another language feature to master). The compromise solution, which bada adopts, like some other mobile platforms, and like the Java language, is to promote the use of interfaces to solve the kinds of design problems that tempt programmers towards multiple inheritance, and allow multiple interface inheritance but only single inheritance from any concrete base class. Interface classes are very natural to use, and allow simple and expressive design. They also have the advantage of being familiar to developers through the Java language. In bada, for example, listeners of all kinds, interactions with base applications, collections, and collection comparators and enumerators are just some of the behaviours that can be implemented using interface classes. Java raises the concept of interfaces into a language feature with the interface keyword. In C++ there is no built-in language convention, and therefore bada introduces its own convention of naming interface classes with a leading ‘I’ (for example IList, IEnumerator, IEventListener, and so on). In bada, in common with many other platforms: ■■

An interface class is always abstract, that is, it contains only pure virtual methods, which means that it cannot be instantiated directly (you cannot new an interface class), it can only be inherited from.

09_974018-ch04.indd 11409_974018-ch04.indd 114

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

■■

The deriving class is therefore responsible for implementing the behaviour of interface methods.

■■

And you must implement all of the methods of the interface class.

115

And in bada specifically: ■■

Interface classes are always named ISomething.

■■

Derived classes should avoid using the virtual keyword in the inheritance declaration, so for example this:

public class MyClass : public Osp::Ui::IActionEventListener { … };

is preferred to this: public class MyClass : virtual public Osp::Ui::IActionEventListener { //... };

Let’s look at a real world example. The following code declares a Form class that displays a waiting animation while waiting to get a first GPS position fix. class WaitingForm : public Form, public IAnimationEventListener, public IActionEventListener, public ILocationListener { public: // ... Constructor/Destructor and other public methods public: // handle softkey press on the form (to stop animation) void OnActionPerformed(const Control& source, int actionId); // be informed when the animation has stopped void OnAnimationStopped(const Osp::Ui::Control& source); // manage requested location data virtual void OnProviderStateChanged(LocProviderState newState); virtual void OnLocationUpdated(Location& location); // ... Other methods and properties };

Here, methods are inherited from three different interface classes that enable the Form to respond to soft key presses by the user, the animation event, and location events. With the animation event, the IAnimationEventListener interface class, defined in ../Include/FUiIAnimationEventListener.h, defines the following listener method as a pure virtual (abstract) method: virtual void OnAnimationStopped(const Osp::Ui::Control& source) = 0;

09_974018-ch04.indd 11509_974018-ch04.indd 115

8/31/10 12:36 AM8/31/10 12:36 AM

116

Part I



About bada

Because the method has no implementation in the base class, we are responsible for providing an implementation, so our WaitingForm source code .cpp file will contain the following code: void WaitingForm::OnAnimationStopped(const Osp::Ui::Control& source) { // ... Implementation goes here }

In this case we don’t want to implement any specific behaviour; we have stopped the animation, so the notification is just a confirmation of our request. But in the case of the other events this example listens for, we definitely do want to provide an implementation. For example, we may want to stop the animation when a specific soft key is pressed: void WaitingForm::OnActionPerformed(const Control& source, int actionId) { switch(actionId) { case SOFTKEY_ACTION_ID_STOP: mp_Animation->Stop(); mp_Frame->RemoveControl(*this); break; default: break; } }

To summarise, these are the rules for using interface classes in your apps: ■■

Derive the class for which you want to inherit interface behaviour from the relevant interface class or classes – there is no limit on the number of classes.

■■

Use the public, but not the virtual, keyword in the inheritance declaration.

■■

Implement the interface methods in your derived class. Note that you must implement all the methods of the interface class.

■■

If the interface class is a listener class, your derived class becomes a listener itself; and it can be added as a listener to the control that should have focus when the listened-for event occurs.

Finally, note that bada provides the dedicated comparison interface class IComparer.

File System and Default Locations on bada Phones As well as a privilege model (see Section 4.4 below), bada enforces data caging for apps. To implement the policy, bada defines a number of

09_974018-ch04.indd 11609_974018-ch04.indd 116

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

117

well-known locations in the file system on a per-application basis, each of which can be accessed by an app using a virtual path prefix (see Table 4.1). Table 4.1 Virtual path prefixes on bada phones Path

Description

Permissions

/Home

Home directory for an application

r/w

/Home/Share

Used to share temporary data with r/w other applications

/Share/[appid]

Used to read temporary data of other applications

r

/Res

Used to read resourcefiles, such as the icon file that was shipped with the app. package

r

/Share/AppControl/ [appcontrol-name]

Used to read data provided by an app controlby its name

r

/Media/{Images,Sounds,Videos, Themes,Others}

Used to read mediadata likeimage, r sound, video, theme,and so on

/Storagecard/Media/ {Images,Sounds, Videos,Themes,Others}

Used to read media data in external memory such as image, sound, video, theme, and so on

r

The paths are defined by the Osp::Io namespace as part of the data caging policy that is enforced for bada apps, and ensures that an app’s private files cannot be read or written by others apps, and that files stored in read-only locations cannot be overwritten (even by the owning application). These well-known locations are important to developers too. When you create a bada project, your code is organised into several directories under the project’s root directory. Some of these locations correspond to permanent locations in the file system on bada phones, and to the virtual path prefixes.

4.3 bada Basic Functionality 4.3.1 Native Types The Base namespace in the bada class library defines a variety of essential classes that you will become familiar with as you go deeper into developing your apps for bada.

09_974018-ch04.indd 11709_974018-ch04.indd 117

8/31/10 12:36 AM8/31/10 12:36 AM

118

Part I



About bada

To get you started, this section provides a quick overview, and shows some examples of those classes in use. The native types include classes for: ■■

basic types, including Object, which is the root class of the bada class library, and wrapper classes for familiar native C++ types including Boolean and Character;

■■

Number, from which all numeric types derive, and wrapper classes for a complete set of numeric value types, from Short to LongLong;

■■

BufferBase, from which all array types derive, and Buffer and ByteBuffer, which wrap C++ native byte arrays;

■■

String, representing a Unicode string;

■■

DateTime and TimeSpan, which represent dates and date differences;

■■

UuId, a Universal Unique Identifier;

■■

as well as these wrapper classes, bada also includes a complete set of collection classes that are defined in the Base::Collection namespace.

Finally, the Base namespace also includes useful Comparer classes for many of the types above, and Base::Utility provides utilities for managing internet Uniform Resource Identifiers (URIs), the math library and string functions. Object, by the way, provides two useful built-in methods: ■■

Equals() tests for equality, which by default is interpreted as identity, that is, true if and only if the two tested objects share the same address. However, it can be overridden to support value equality, in which case it returns the same value as the equality operator. The SDK sample and example code includes several examples of overriding and using Equals().

■■

GetHashCode(), which generates a hash value for the current instance (note that the default implementation simply returns the object’s address, as a simple way of returning a random but unique number).

Object does not provide additional functionality such as zeroing memory when an object is instantiated.

4.3.2 Using Strings, Characters, and Unicode It should be no surprise that bada is thoroughly Unicode enabled, and takes non-Western alphabet and writing systems seriously. In fact, bada is designed to allow a complete, alternative windowing set to be used, for example to support Samsung’s home market in Korea. This is more than just a case of providing good localisation support (which is a great bada feature); it really is complete support for an alternative calligraphic system.

09_974018-ch04.indd 11809_974018-ch04.indd 118

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

119

The Character class wraps the mchar built-in multibyte character type. In bada, multibyte means, more precisely, UTF-8. A string in bada is a mutable sequence of 2-byte Unicode characters of type Character, and supports a familiar set of string operations including Append(), Insert(), Remove(), IndexOf(),as well as equality, comparison, sizing and resizing, and IsEmpty() methods. Strings default to 16 bytes in length if no length is specified, and grow at 1.5 times the current length, rounded to the nearest multiple of 4, so for example 16, 24, 36, 54, 80. Note that the size of a string in bytes is not a guide to its length in Characters. Note: bada also supports the L macro which is used to create a literal String object from the specified character sequence, for example L”Hello string!”. The L macro generates wide characters and ‘long’ strings (i.e. Unicode strings). The String class, or the L macro, should always be used in preference to native C++, C-style strings. To create a new String with set text, use: String str(L”Set text!”);

To create a string from a numeric value, use: String str((int) 100);

The bada platform also provides some useful utility classes for use with strings, specifically: StringTokenizer

Makes simple String parsing easy based on default or specified delimiters, and provides GetNextToken() and HasMoreTokens() methods to perform and control token extraction from strings. Length Getting and String Conversion

Simple conversions to and from multibyte mchar and UTF-8 primitive types. URI Handling

URI-specific string handling that allows URIs to be constructed and decomposed easily.

09_974018-ch04.indd 11909_974018-ch04.indd 119

8/31/10 12:36 AM8/31/10 12:36 AM

120

Part I



About bada

Text and Unicode Unicode is a universal character encoding that aims to support fonts for all living languages (and most dead ones too, not to mention some made-up ones) by providing codepoints for the individual characters of some 90 alphabets, scripts, ideographic, and hieroglyphic writing systems. The list of supported scripts includes everything from ASCII and Western Latin and non-Latin languages such as Greek and Cyrillic, all the way through the Semitic and Indic scripts and other scripts of the Indian subcontinent, to the ideographic character sets of the Far East, including Chinese, Japanese, and Korean hangul. Unicode is vast. Like most modern platforms, whether mobile or desktop, bada includes comprehensive Unicode support. Most importantly, bada supports multi-way conversion between the most common encoding schemes (many of which Unicode includes as subsets within its global character space), including those listed in Table 4.2. Table 4.2 Supported character encodings Encoding scheme

Description

UTF-8

The encoding used by XML, and therefore increasingly the standard for web-based textual resources

Latin1

Western alphabets, defined by ISO-8859-2

UCS2

Alternative Unicode encoding

ASCII

Standard single-byte text encoding

GSM

GSM-specific character set and 7-bit encoding used in SMS messaging

Encoding and decoding between different schemes can either be done perString (or per ByteBuffer or MCharBuffer) using a GetBytes() or GetChars() method of the encoded string, or by constructing an Encoder or Decoder object, which you should do for large blocks of text or where you have sequential data, for example if you are reading text in from an external source. Natively, all character strings in bada are UTF-8 by default. You can query a device for supported encodings with the method: IList* Encoding::GetAvailableEncodingsN(void)

And you can query for the encoding of a text string with: Encoding* Encoding::GetEncodingN(const String &encodingType)

09_974018-ch04.indd 12009_974018-ch04.indd 120

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

121

Encoding and decoding support is provided by the Osp::Text namespace classes, while Osp::Base classes provide the underlying support for native Unicode, including the mchar wide-character data type wchar_t. Note: mchar is supported at compiler level as a native type by the Sourcery G++ GNU Toolchain, which is used for target and simulator builds in the bada SDK. Be aware that for the sake of efficiency, the bada mchar type is defined with a 2-byte size, that is, 16-bits. On most GNU-based platforms, mchar is defined with a 4-byte size. Therefore any code that depends on the physical size of an mchar will not behave correctly if ported to bada without change. Of course, programming best practice would say that code should not depend on the phsyical size of a data type. And by the way, bada also provides excellent support for localisation generally, and not just for writing language. Support includes date, time, and time zones, number, currency, and other locale-sensitive information types, including conversions and formatting, as well as IDE support for string resources.

4.3.3 Using Buffers Just as strings should always be used instead of native C-style null-terminated character arrays (because strings are inherently Unicode, and size-checking means that they cannot overflow), the Buffer class is preferred to native, C-style arrays. Buffers are container classes that wrap arrays (sequences) of C++ primitive types, for example int, long, double, and char. (Compare with strings – which are sequences of non-primitive type, Character.) Buffers provide absolute and relative indexing, as well as a mark that stores an index: ■■

ByteBuffer is a wrapper class for sequences of 8-bit unsigned int.

■■

BufferType is provided to enable ready-made template classes of double, float, int, long, longlong, mchar, and short primitive types.

Note: A DoubleBuffer is a Buffer double object, not to be confused with the ‘double buffering’ buffer management technique!

4.3.4 Collection Classes An essential ingredient of any well-designed class library is a good set of collection classes. In keeping with its minimalist design philosophy (it’s a language for

09_974018-ch04.indd 12109_974018-ch04.indd 121

8/31/10 12:36 AM8/31/10 12:36 AM

122

Part I



About bada

OOP, not an OOP framework), C++ goes no further than providing native types, which are in essence identical to those of the C language that C++ includes as a proper subset. bada supports the Standard Template Library (STL), which is a rich class library, but does not use STL in the platform. STL was not designed for mobile (although there are mobile implementations: as used, for example, in Symbian). There are other objections to STL: it is big, like the kitchen sink, with a maximalist philosophy; it almost certainly imposes a runtime performance penalty; and template-based programming, also known as generic programming and which is strictly speaking not at all the same as OOP, adds another layer of complexity to the programming task.10 In summary, objections to the STL are: ■■

complex syntax;

■■

complex design and usage;

■■

inflated code size as a result of lots of copying of objects;

■■

not so well understood, therefore effective usage of the library has to be learned;

■■

bigger binaries (though binaries can be faster at runtime);

■■

not optimised for efficiency.

Instead, bada focuses on providing a small number of versatile collection types, with highly optimised implementations specifically designed for mobile. In summary, the bada class library includes the following collection types: HashMap, MultiHashMap, and MapEntry

Key-value pair collections hashed on the key value, where MultiHashMap allows duplicate keys (values of duplicate keys must be different), and where MapEntry is a key-value pair. ArrayList and LinkedList

Index-addressed and sequentially addressed lists. Stack and Queue

LIFO and FIFO collections, respectively.

10

See the ‘Gang of Four’ comment, ‘Dynamic, highly parameterized software is harder to understand than more static software.’ Gamma, Helm, et al., Design Patterns (Addison-Wesley, 1995), p 21.

09_974018-ch04.indd 12209_974018-ch04.indd 122

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

123

For each collection type, a templated type is available, for example, StackT, QueueT, HashMapT. As well as the concrete and template classes, bada provides interface classes that allow collections to be manipulated: ICollection

Defines the collection size, enumerator, and synchronnisation method. IEnumerator, IMapEnumerator, IBidirectionalEnumerator

Enable iteration over Collection and Map types. IList

Indexable list. IComparer

Enables comparison of two individual objects. IHashCodeProvider

A hash map. Again, exactly as with the concrete collection classes, a templated version of each of the interface classes is provided for use with the templated collection classes: for example ICollectionT representing a templated collection IListT, IMapT, and so on. The difference between the object-based classes and the template-based classes is that: ■■

Object-based collections derive from ICollection, and store objects that derive from the Object class.

■■

Template-based collections derive from ICollectionT, and should typically be used to store C++ primitive types.

Note: Object-based collections don’t collect copies of objects (for obvious reasons of efficiency); instead they collect pointers. So any object you want to put into a collection class must be allocated using operator new. Otherwise, if your collection stores a pointer to an automatic variable, its lifetime is unpredictable, and it likely will not exist when the collection comes to use it. Your app will crash, unpredictably.

09_974018-ch04.indd 12309_974018-ch04.indd 123

8/31/10 12:36 AM8/31/10 12:36 AM

124

Part I



About bada

4.3.5 Using Dates and Times Dates and times, and calculations from dates and times occur so frequently in so many kinds of application, that having convenience classes to make using them easy is essential on any platform. The DateTime class in bada hides all the complexity of creating and manipulating dates and times. A DateTime represents a value to the nearest second between 12:00:00 am (midnight) on 1 January 1 AD, and 11:59:59 am (one second before midnight) on 31 December 9999 AD. Thus a DateTime is a single, specified, instant. Since a DateTime is an instant, there is no meaningful concept of differencing (adding, subtracting) DateTime values, but there are meaningful concepts of comparison. In contrast, a TimeSpan is a time period (i.e. duration) internally represented in ‘ticks’ (milliseconds). Durations do support meaningful concepts of differencing, as well as comparison. DateTime objects can be added to (or subtracted from) using built-in add and subtract methods, for example: dt.AddYears(10); dt.AddDays(-3);

More complex manipulations of dates and times typically involve using DateTime and TimeSpan objects: TimeSpan ts(1, 1, 1); // 1 day, 1 hour, 1 second dt.Add( ts ); dt.Subtract( ts );

■■

A DateTime and a TimeSpan can be added or subtracted.

■■

A TimeSpan and a TimeSpan can be added or subtracted.

■■

The parts of a DateTime can be extracted, and a DateTime can be queried with IsLeapYear().

■■

A DateTime can be added to or subtracted from using the built-in methods AddYears(), AddDays(), and so on.

■■

A TimeSpan can be negated, converted into and between time units, hashed, compared, etc.

■■

A DateTime can be converted from, or to, seconds.

4.3.6 Using Numbers In bada, wrapper and comparison classes are defined for each of the C++ primitive numeric types of short, char (8-bit integer), int (32-bit integer), double, long, longlong, and float.

09_974018-ch04.indd 12409_974018-ch04.indd 124

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

125

The wrapper classes make number comparisons and number-to-string and string-to-number conversions, as well as hashing, trivial. They also add robustness to the platform (and to your apps) by ensuring that overflows (whether accidental or deliberate) are impossible when numeric classes are used for number handling instead of primitive numeric types. App developers are encouraged to use the number classes when handling numeric data, and not to rely on primitive C++ types.

4.4 Security and the Privilege Model in bada All platforms need to protect end-users against malicious (or just badly designed) software that might disrupt the device; corrupt, steal, or destroy private data; or spoof users or the system into performing billable actions that incur unwanted costs, for example, making premium-rate voice or expensive data calls. In some respects, mobile phones have an advantage over desktop systems: ■■

Because they are ROM-based, all system software and data can be restored by rebooting.

■■

Their network connection model ensures that they are permanently behind an operator firewall.

■■

Their intermittent and mobile connection model makes them continuously moving IP address targets.

■■

The above, together with their (relatively) low bandwidth, makes phones poor targets for infections like bot networks.

■■

Shortlink connectivity typically requires user acceptance; Bluetooth attacks are mostly mythical.

At the same time, phones are potentially an attractive target to malware because they are a rich source of personal data, and the pay-to-connect model theoretically creates opportunities for rogue software to exploit. In practice, viruses of the kind that plague desktop systems are almost unknown on phones, partly for the reasons mentioned, partly because phones require greater programming skills, and partly because mobile platforms have designed-in security. For mobile app developers, like it or not, and regardless of platform, security considerations will always be present. In this respect, bada is no different from other mobile platforms. All impose security limitations of some kind. However, unlike sandboxed systems (for example mobile Java, Windows Mobile .NET, Android), bada offers native API access for apps – and therefore layers a security model on top of its APIs.

09_974018-ch04.indd 12509_974018-ch04.indd 125

8/31/10 12:36 AM8/31/10 12:36 AM

126

Part I



About bada

4.4.1 Privileges in bada In bada, sensitive APIs are protected by privileges. Privileges have two dimensions: 1. A privilege group is a category that typically applies to related methods of a class or namespace. When you are granted access to the group, you have access to all methods requiring that privilege. 2. Every privilege group belongs to one of two privilege levels – NORMAL or SYSTEM. The goal of the privilege model in bada is to protect app users against malicious code, and to protect bada services against abuse. Because bada includes network-based, service-centric features in its API set, there is clearly scope for those with malicious intent to attempt to subvert or break the services. Because those services potentially hold private user data, protecting them is essential. Not all bada APIs are protected, and in fact most require no privileges. To access privileged APIs, you must have the required privilege level, and your app must declare the required privilege group in its manifest file. Declaring privileges is easy. Privileges are metadata, not code: you simply add the required privilege group while defining your app profile (as explained in Chapter 2). Privilege groups map quite closely to namespaces (currently there are more than 30 privilege groups, compared to 20 top-level namespaces, and 30-something namespaces in total if you include nested namespaces), and so, in general, adding a new namespace implies checking to see whether new privileges are required. The unusual dimension to privileges is the privilege level, which interprets access to privileges in terms of the app developer, and not the app itself. Access to privileges is therefore controlled based on developer status, defined as membership level in the bada ecosystem – for which currently there are only two values: ordinary members and strategic partners. The unfortunate sideeffect of this in current versions of bada is that access to privileges is severely restricted. Almost half of the privilege groups, and in many ways the most interesting ones, are placed out of the reach of ordinary third-party developers and are available only to partners. This is a reflection of the newness of the platform as much as anything, and will change. Keep an eye on developer.bada.com for news.

09_974018-ch04.indd 12609_974018-ch04.indd 126

8/31/10 12:36 AM8/31/10 12:36 AM

Chapter 4



bada Fundamentals

127

4.4.2 In Practice Privilege level restrictions aside, using privileges in your app is straightforward: ■■

Where no privilege group is required, which is the case for most of the bada class library, no special declarations or other action is required.

■■

All developers automatically have NORMAL privileges, which means that their apps can use any APIs that are marked as requiring NORMAL privileges. Simply declare the required privilege group in your manifest file.

■■

If you only have NORMAL privilege and you want to access APIs requiring SYSTEM level privilege, you should request to become a bada partner developer. Acceptance is not automatic but it is expected that requests will be granted to developers who make a good case for it. Realistically, this option is bound to be restricted compared to the number of developers who would like partner access.

You will notice that we’ve listed the privilege groups, if any, required for each namespace in the namespace descriptions in Chapter 6. For more details of privileges at the API level, please see the SDK documentation.

09_974018-ch04.indd 12709_974018-ch04.indd 127

8/31/10 12:36 AM8/31/10 12:36 AM

09_974018-ch04.indd 12809_974018-ch04.indd 128

8/31/10 12:36 AM8/31/10 12:36 AM

CHAPTER

5 Exploring bada Services

In this chapter, we explore some of the bada service APIs. As you may know, the bada platform is not limited to providing features only on devices, but also provides server-associated features. These are key and unique features compared with other mobile platforms on the market. The bada platform provides its devices with a remote server infrastructure, which makes it easy to integrate web services into applications, and also provides a full mobile application ecosystem to bada developers. This chapter is dedicated to these service-centric features.

What You Will Learn This chapter introduces the bada service APIs, and shows you how to use them in your own apps. You will learn: 1. At a high level, what services are provided and what functionality they offer. 2. Basic communication between devices, apps, and the bada Server. 3. How to work with the services, demonstrated by practical examples.

What You Will Need At the time of writing access to many of these APIs is restricted to partner developers, as a degree of trust is required from those accessing the bada 129

10_974018-ch05.indd 12910_974018-ch05.indd 129

8/31/10 12:37 AM8/31/10 12:37 AM

130

Part I



About bada

Server, which also stores private user data. Please go to the bada developer site at developer.bada.com for more information about how to become a partner developer.

5.1 What are the Services? Some bada namespaces such as Osp::Commerce::Store, Osp::Locations ::Services, Osp::Social::Services, and Osp::Content, actually refer to services provided via the bada Server rather than to device features. Other namespaces, such as Osp::Security, contain features provided by the bada Server, as well as device-side APIs. These are the services we will discuss in this chapter, and we’ll start with a summary of each.

5.1.1 Location Service The location service allows developers to utilise features such as displaying a map, geocoding an address, finding points of interest (POI) and searching routes from one place to another. The bada platform provides developers with easy to use APIs to integrate different location service providers.1 There are also some other nice features available from the bada location service that relate to social networking. It is possible to request and process location information. This positioning data can be for yourself or for others, referred to as ‘buddies’, who have allowed you access to their position via the bada Server. In addition, it is possible to fine-tune this data to allow for location reporting when a subject either enters or leaves a specified region. Users can also store their personal landmarks on the server. We will explain these features in detail in Section 5.3 below. Note: At the time of writing, only deCarta is integrated as a map provider in the bada platform.

5.1.2 Social Service Social networking has become a popular feature of current mobile applications. The bada platform provides fully functioning social services including profile management, buddy management, privacy management, messaging, and a Social Network Service (SNS) Gateway.

1

For latest information, please check the latest status from developer.bada.com.

10_974018-ch05.indd 13010_974018-ch05.indd 130

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

131

The social service allows applications to create, share, and manage information from bada user profiles. Applications can also manage buddies between bada users. The relationships between buddies are stored on the server. bada apps that use the buddy service can make use of these relationships.

Profiles Profiles can contain data such as names, gender, and marital status. More data can be added, but may be subject to access controls for privacy. The owner of a private profile must grant permission for another to view it. Custom profiles can be created to hold specific data. Communication and collaboration is possible between profile ‘associates’ through the use of message exchange services.

Buddies A buddy describes a confirmed relationship between two users of the bada Server. The relationship is initiated by a request and is only established following acceptance by the recipient. A bada application, for instance, can fully manage and categorise the buddies of an individual based on the closeness of the relationship. It is also possible to communicate with your buddies via the bada messaging server using messaging APIs. Finally you can integrate existing thirdparty social services into your bada applications utilising the unique feature of the bada SNS Gateway.

5.1.3 Content Service When we mention the word ‘content’ here, we are referring to media content such as images, audio, and videos. There are two types of content described in the Osp::Content namespace, content on the device side and content on the server side. As this chapter is dedicated to bada service-centric features, we will only explain the server-side content. The bada content service allows developers to create, read, update, and delete content on the server. It is also possible to search content and set the access level on the server remotely. By using the content service, developers can not only manage content itself, but also manipulate the metadata of content, such as thumbnail information, geo-tag information, and basic file information. Note: To use the content service, you have to sign up for the Amazon Simple Storage Service (Amazon S3). Your data will be physically stored on this Amazon server, which the bada Server is the interface to.

10_974018-ch05.indd 13110_974018-ch05.indd 131

8/31/10 12:37 AM8/31/10 12:37 AM

132

Part I



About bada

5.1.4 Commerce Service The commerce service allows end-users to browse and purchase items through bada applications. Items can be everything that can be purchased out of a bada app. Developers can set up their own online store, manage items on the store, and track purchase statistics. As a developer, you can utilise this service to create an application with functionalities such as retrieving selling item information and purchasing them in your application. Purchases are made simple, as buyers are required to pre-register their credit cards when they sign up with the Samsung Apps web site. So there is no need for developers to handle any credit card information from buyers. The Samsung Apps store maintains the buyer’s credit card details and associates it with a buyer ID. Purchases are then a simple matter of entering the buyer’s ID and a password. Note: To sell your items, you always need to register with the Samsung Apps Seller Office at seller.samsungapps.com.

5.1.5 Single Sign On bada services are not limited to the ones mentioned above. There are other services that are located in other namespaces, for example the single sign on (SSO) application control from the Osp::App::AppControl namespace, and the weather sensor service from the Osp::Uix namespace. The bada Server can manage identities by associating a single login and password with all of its services. This SSO method utilises an authentication token provided by the server to validate and sign into all the services that a user may have on the bada Server.

5.2 How It Works For most mobile application developers, the biggest problem is choosing the development language. It is even more difficult when development involves communications between web components, such as map providers (Google, NavTeq etc.), social service providers (Facebook, Twitter, etc.) or content servers (Flickr, Picasa etc.). So how does the bada platform handle these types of communications?

5.2.1 Device-to-Server Interaction – bada APIs When you develop applications to access server-associated services, you do not need to consider which language to use, whether it is JavaScript, Python,

10_974018-ch05.indd 13210_974018-ch05.indd 132

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

133

or HTML. On the bada platform, all communications between devices and servers are in native or wrapped C++ APIs. Let’s take an example of verifying your Twitter account with the Twitter server using the Open Authentication method. Using JavaScript and the OAuth JavaScript plug-in (oauth.googlecode.com/svn/code/javascript/), you can write the following lines of code: var url = “...”; var accessor = {   token: “myToken”,   tokenSecret: “myTokenSecret”,   consumerKey : “myConsumerKey”,   consumerSecret: “myConsumerSecret” }; var message = {   action: url,   method: “GET”,   parameters: [] }; OAuth.completeRequest(message, accessor);         OAuth.SignatureMethod.sign(message, accessor); url = url + ‘?’ + OAuth.formEncode(message.parameters); // send request to ‘url’

But on the bada platform, all you need to program is: Osp::Social::Services::SnsAuthenticator* pAuthenticator; pAuthenticator->Authenticate(L“twitter”, L”YourConsumerKey”,L”consumer SecretKey”);

From the above example, you can get a glimpse of bada’s C++ API for server communication. For services such as Social, Remote Landmark Store and Content, developers are directly communicating with the bada Server. For some other services such as SNS Gateway and the location service, the bada backend server is acting as a mediator between the device and third-party servers.

5.2.2 bada Server and Third-Party Server Interaction with Open APIs On the bada platform, the bada Server uses a set of open APIs to communicate with third-party servers. Through open APIs, the bada Server can make seamless connections to third-party servers to both retrieve and manage contents. Developers can use simplified bada native APIs to interrogate popular search engines and handle buddy lists for popular SNS sites such as Twitter, Facebook and MySpace. The bada Server does the hard work of handling the specifics of connecting to each SNS service. Being scaleable, further social network providers will be added soon.

10_974018-ch05.indd 13310_974018-ch05.indd 133

8/31/10 12:37 AM8/31/10 12:37 AM

134

Part I



About bada

Note: Currently the SNS Gateway is mainly used for retrieving buddy information from the third-party social network provider. For other functions, such as follow and un-follow from Twitter, you have to use the HTTP connection and XML parser provided by bada. Figure 5.1 illustrates the big picture of bada Server infrastructure. All application developers need to know is the bada C++ APIs.

Figure 5.1 bada Server.

Now let’s look at how open APIs work on the bada Server. Normally client applications use Representational State Transfer (REST) APIs to communicate with web servers, which means that calls are made over HTTP (GET, POST, etc.) to the server.2 As we mentioned in the previous section, different web services implement different sets of RESTful APIs. It is very difficult for a client application to interoperate with different services. By using the bada Server as a mediator, you are not required to use any specific RESTful APIs; instead you use native C++ APIs. The bada Server takes care of making calls to specific third-party servers. Through the third-party map server deCarta, bada can provide your applications rich mapping services that include route calculation, geocoding, and directory services.

2

By design the HTTP protocol is stateless, which means that the server does not keep any information about the client. The disadvantage of this design is that it may increase the transmission of repetitive data and thereby decrease network performance. Adding caches on the server side could make HTTP stateful.

10_974018-ch05.indd 13410_974018-ch05.indd 134

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

135

5.3 Services in Detail You should now have a general understanding of bada Server associated services. In the following sections, we explore these features in more detail. Let’s start with location services.

5.3.1 Location as a Service A key distinction between mobile applications and conventional applications is the location feature. Most modern smartphones are equipped with GPS transceivers. Devices are aware of location changes all the time. Mobile developers can utilise real-time location data to make function-rich applications, just as FourSquare and Loopt do. The bada platform provides several types of location-based service as discussed at the beginning of this chapter. So now we will examine each of them, and give you a deeper view. Before we start, let’s think of a use-case: imagine you want to create an application to give directions to a user’s nearest Starbucks based on their current location, and show it on a map. Simple, right? To search a particular landmark, you can use the directory services or remote landmark store provided by bada. In this chapter we show how to use the directory service. As mentioned in the previous chapter, all development on bada is related to: service providers (e.g. IDirectoryServiceProvider interface), listeners (e.g. IDirectoryServiceListener interface), and handlers (e.g. OnDirectoryRequestReceivedN method).

Step 1: Instantiate Directory Service Provider Object String providerName = L”deCarta”; String extraInfo = L”ClientName=username;ClientPassword=pwd; HostUrl=http://developer.kr.dz.decarta.com:80/openls”; IDirectoryServiceProvider *pProvider = dynamic_cast( ProviderManager::ConnectToServiceProviderN( providerName, LOC_SVC_PROVIDER_TYPE_DIRECTORY, extraInfo ) );

The above code is self-explanatory. To instantiate the provider object, you have to specify the client name, client password, and the host URL of the map provider. But remember that to use deCarta as your service provider you must request your own user account (client name) and password from the deCarta developer site. There is a Getting Started guide for the bada platform available from the deCarta developer zone. Also you can find Features, Testing, and Going Commercial information from dedicated bada sections on the deCarta developer zone web site.

10_974018-ch05.indd 13510_974018-ch05.indd 135

8/31/10 12:37 AM8/31/10 12:37 AM

136

Part I



About bada

Step 2: Get Preferences of Directory Service Provider Object, and Set Preference Properties DirectoryServicePreferences *pPreferences = null; pPreferences = static_cast( pProvider->GetServicePreferencesN(false) ); //if set to true, using default values from provider pPreferences->SetSortBy(&String(L”Name”)); pPreferences->SetSortOrder(Osp::Base::SORT_ORDER_ASCENDING);

After getting the directory service provider object, you can set its preference using the above code snippet. For example, you can set the sorting criteria by using a name. And you can also set the sorting order to be ascending mode or descending mode. In this example, we use ascending mode.

Step 3: Get Directory Filter and Add Search Keywords DirectoryFilter is the criteria for searching. From the above example code, we use GetFilterN() to get the criteria object from the provider object, and then we can set the criteria to use specific keywords, such as Starbucks in our example. DirectoryFilter *pFilter = null; pFilter = pProvider->GetFilterN(); pFilter->AddFilter(DirectoryFilter::SEARCH_FILTER_KEYWORD, L”Starbucks”);

Note: deCarta POI search also matches substrings. A search for ‘Star’ would find ‘Star Donuts’, ‘Nightstar restaurant’, and any POI containing ‘star’ in its name.

Step 4: Implement Listener for Handling Results class MyDirectoryServiceListener; //results returned as a list of landmarks MyDirectoryServiceListener::OnDirectoryRequestResultReceivedN( RequestId requestId, const IDirectoryServiceProvider& provider, IList* pLandmarks, result r, const String& errorCode, const String& errorMsg) { switch(r) { //handle different situation here if(pLandmarks) { IEnumerator* pEnumerator = pLandmarks->GetEnumeratorN(); While(!IsFailed(pEnumerator->MoveNext()) { const Landmark* item = static_cast(

10_974018-ch05.indd 13610_974018-ch05.indd 136

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

137

pEnumerator->GetCurrent()); String name = item->GetName(); AppLog(“Landmark Retrieved(%S)”, name.GetPointer()); } } delete pEnumerator; pLandmarks->RemoveAll(true); delete pLandmarks; } }

To be able to get the result of a directory request, you have to also implement the callback function OnDirectoryRequestResultReceivedN(), which is a virtual method. The above code snippet demonstrates a common implementation of this method. Because the results are returned as a list of landmarks, you need to iterate the pLandmarks to display the directory information.

Step 5: Define the Search Area To define the search area, use the class called GeographicArea under the Osp::Locations namespace. This class is an abstract class and provides common methods to different shapes of a geographic area. In our example, we will use the CircleGeographicArea. To get updated location information, we have to first implement the ILocationListener interface class to receive the location information. Class MyListener : public ILocationListener { public: MyListener(); ~MyListener(); virtual void OnLocationUpdated(Location& location); virtual void OnProviderStateChanged(LocProviderState newState){}; }; void MyListener::OnLocationUpdated(Location& location) { LocationProvider* pLocationProvider; const QualifiedCoordinates* pCoordinate = location. GetQualifiedCoordinates(); if(pCoordinate != null) { //We declare pArea here as local for better understanding. //In your project it is advisable to have it as a //member variable. CircleGeographicaArea* pArea; pArea = new CircleGeographicArea(); pArea->Set(*pCoordinate, 2000); } // Stop the location updating pLocationProvider->CancelLocationUpdates(); };

10_974018-ch05.indd 13710_974018-ch05.indd 137

8/31/10 12:37 AM8/31/10 12:37 AM

138

Part I



About bada

Now what we need to do is to get our LocationProvider object and update the current location. LocationProvider* pLocationProvider; pLocationProvider = new LocationProvider(); MyListener* pLocationListener = new MyListener(); result r = pLocationProvider->Construct(LOC_METHOD_HYBRID); if(!(IsFailed(r))) { int interval = 60; pLocationProvider->RequestLocationUpdates(*pLocationListener, interval, false); }

The above code instantiates a LocationProvider object using a hybrid approach, and requests the updated location with the interval value equal to 60 seconds. Once the location is updated, it will invoke the OnLocation Updated() method that you implemented in the MyListener class.

Step 6: Send Search Request RequestId reqId; MyDirectorServiceListener *pListener; //You have to implement by //yourself per step 5 CircleGeographicArea *pArea; Coordinates center; //Normally it is your current coordinates from GPS pArea = new CircleGeographicArea(); pArea->Set(center, 2000); pFilter->AddFilter(DirectoryFilter::SEARCH_FILTER_KEYWORD, L”Starbucks”); result r = pProvider->Search(*pFilter, *pArea, pPreferences, *pListener, reqId);

To send the search request, you can use the Search() method defined in the DirectoryServiceProvider class, declared at Step 1. You have to pass five parameters when calling this method: the preference of received search results pPerferences declared at Step 2, the search criteria pFilter that you just set at Step 3, the listener pListener for receiving replies from the server that you defined at Step 4, the request ID reqId that identifies this search request, and finally the search area pArea. The parameter pArea is the given area where you will search for landmarks. In this example, we are using a circle type of area that has the current location as the centre coordinates. The centre coordinate center is updated constantly within a given interval. The implementation is described at Step 5. Now you have seen how to implement the necessary classes and how to send the search request. Once you have found the preferred Starbucks

10_974018-ch05.indd 13810_974018-ch05.indd 138

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

139

location, you probably would also like to know how to get there. For this, you will need the route service. Now we’ll see how we can find a route by using the bada route service. Again, we will break down the implementation into individual steps. Some steps are very similar to those for the directory service we described above. For example, the first two steps are almost exactly the same except you have to change the service name to LOC_SVC_PROVIDER_TYPE_ROUTE in Step 1. And in Step 2, you will set the preference dedicated to route service. String providerName = L”deCarta”; String extraInfo = L”ClientName=username;ClientPassword=pwd; HostUrl=http://developer.kr.dz.decarta.com:80/openls”; IRouteServiceProvider *pProvider = dynamic_cast( ProviderManager::ConnectToServiceProviderN(providerName, LOC_SVC_PROVIDER_TYPE_ROUTE, extraInfo) );

You can just use the default preference from deCarta using the following lines of code: RouteServicePreferences *pPreferences = null; pPreferences = static_cast( pProvider->GetServicePreferencesN(true)); //if set to false if you want to use your own settings

The next step is to request the route from your current location (coordinate) to the Starbucks location that you received from the ILocationListener class in Step 5. //pLandmark is the variable defined in Step4 Coordinates *pPerferredStarbucksLocation = pLandmark->GetQualifiedCoordinates(); //location is the parameter used in Step 5 Coordinates *pCurrentLocation = location.GetQualifiedCoordinates(); ArrayList* pWaypoints = null; pWayPonints = new ArrayList(); pWaypoints->Construct(2); pWaypoints->InsertAt(*pCurrentLocation, 0); pWaypoints->InsertAy(*pPerferredStarbucksLocation, 1); pProvider->GetRoute(*pWaypoints, pPreferences, *pListener, reqId);

To receive the route results, you have to implement the IRouteService Listener interface class and override the pure virtual method defined in this class.

10_974018-ch05.indd 13910_974018-ch05.indd 139

8/31/10 12:37 AM8/31/10 12:37 AM

140

Part I



About bada

Class MyListener : public IRouteServiceListener { public: MyListener(); ~MyListener(); virtual void OnRouteReceived(RequestId reqId, const IRouteServiceProvider& pProvider, IList* pRoute, result r, const String& errorCode, const String& errorMsg); }; void OnRouteReceived(RequestId reqId, const IRouteServiceProvider& pProvider, IList* pRoute, result r, const String& errorCode, const String& errorMsg) { //For a detailed implementation, you can refer to the bada example //code provided with bada SDK };

Note: The results returned from the OnRouteReceived() method is a list of calculated routes. If the calculation of alternative routes is not available, only one route is included in the list. Once you find the route to your Starbucks, maybe you would like to invite your friends to meet you there. Let’s see what kind of features we can get from bada’s Social Service.

5.3.2 Social Network Service – All Connected Mobile users connect with each other all the time, updating and sharing their status information, and exchanging messages. At the beginning of this chapter, we mentioned five different services under the Osp::Social namespace. Now we will explain in more detail the buddy service, profile management, and privacy management. We have our location sample from the location service. Let’s take the usecase from the last section and make it even more sociable. Assume we want to share our current locations with another bada user, how could we make this happen? Before you share or request any information from your friends, there are several things you have to do.

Step 1: Make User A’s Profile Searchable Figure 5.2 shows the sequence diagram of setting profile exposure level.

10_974018-ch05.indd 14010_974018-ch05.indd 140

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

141

Figure 5.2 UML sequence diagram – User A.

There are two classes used in this use-case: PrivacyManager and MyListener. Let’s start from User A’s PrivacyManager class, which allows the user to send a privacy control related event to the bada Server, such as set profile exposure level (PEL). The code snippet below demonstrates how to use the PrivacyManager class to set User A’s profile searchable, and how to assign the listener object to this class. MyListener* pMyListener; pMyListener = new MyListener(); pMyListener->Consturct(); pMyPrivacyManager = new PrivacyManager(); pMyPrivacyManager->Construct(*pMyListener); //Register/assign the listener to PrivacyManager RequestId reqId; pMyPrivacyManager->SetProfileExposureLevel(PROFILE_SEARCHABLE, reqId);

Another class from User A’s side is the MyListener class, which is the essential class for handling the asynchronous event sent by the bada Server. The following code snippet shows you how to implement the MyListener class. // implementation of MyListener class class MyListener : public IPrivacyManagerListener { }; void MyListener::OnProfileExplosureLevelUpdated(RequestsId reqId, result r, const String &errorCode, const String &errorMsg) { //Your implementations for this virtual method }

10_974018-ch05.indd 14110_974018-ch05.indd 141

8/31/10 12:37 AM8/31/10 12:37 AM

142

Part I



About bada

As you can see, the MyListener class is derived from the interface class called IPrivacyManagerListener. It defines virtual methods starting with ‘On’ prefix. You have to implement them by yourself. From the sequence diagram, the On-methods mainly display or notify the user when results are received from the bada Server. From now, User A’s profile is searchable. Other bada users can search her or request her to become a buddy.

Step 2: User B Sends Buddy Request to User A Next we will take a look at the User B’s side. User B is the person trying to find her friend’s (User A) profile and requests to become buddies. We will start from User B’s sequence diagram, as we did for User A. Figure 5.3 illustrates the sequence for User B to search a profile and add as a buddy upon a successful search. Compared with Figure 5.2, there are two more types of classes involved called ProfileService and BuddyService. The ProfileService class accesses profiles on the bada Server and sends different types of requests to the server and the BuddyService class sends the buddy request to the bada Server. User B’s MyListener class has to implement two virtual methods called OnProfileResultsReceivedN(), which will handle the results returned by the server, and OnBuddyRequestSent(), which will be invoked when a response to the buddy request is received from the server. Let’s take a look at how to implement the class in this case.

Figure 5.3 UML sequence diagram – User B.

10_974018-ch05.indd 14210_974018-ch05.indd 142

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

143

// implementation of MyListener class class MyListener : public IProfileServiceListener, public IBuddyServiceListener {}; void MyListener::OnProfileSearchResultsReceivedN(RequestsId reqId, IList *pRequestList, int PageNo, int countPerPage, int totalPageCount, int totalCount, result r, const String &errorCode, const String &errorMsg) { //Your implementations } //invoked when server sends response void MyListener::OnBuddyRequestSent(RequestId reqId, result r, const String &errorCode, const String &errorMsg) { //Your implementation }

Step 3: Response to Buddy Request Sent by User B There are several steps User A has to consider when she receives the User B’s request from bada Server. User A can reject, ignore, or accept the request. Figure 5.4 shows how User A receives the buddy requests and responds to them.

Figure 5.4 UML sequence diagram – response buddy requests.

This time, User A’s listener has inherited one more interface class called IBuddyServiceListener. The IBuddyServiceListener allows users to

10_974018-ch05.indd 14310_974018-ch05.indd 143

8/31/10 12:37 AM8/31/10 12:37 AM

144

Part I



About bada

receive buddy service related results from the bada Server. The code snippet below demonstrates the virtual methods MyListener class has to implement. // implementation of MyListener class class MyListener : public IProfileServiceListener, public IBuddyServiceListener {}; void MyListener::OnReceivedBuddyRequestsReceivedN(RequestsId reqId, IList *pRequestList, int PageNo, int countPerPage, int totalPageCount,int totalCount, result r, const String &errorCode, const String &errorMsg) { //Your implementations } void MyListener::OnBuddyResponseSent(RequestsId reqId, result r, const String &errorCode, const String &errorMsg) { //Your implementations for this virtual method }

The OnReceivedBuddyRequestsReceivedN() call-back function is invoked when User A has some buddy request received from the bada Server. An OnBuddyResponseSent() call-back function is invoked when User A sends the response to a particular buddy request. Compared with Figure 5.2, User A has one more class called BuddyService this time. The BuddyService class is defined by the bada application framework. It directly handles user interactions such as GetReceivedBuddy Requests() and RespondToBuddyRequest(). The following code snippet shows how to use this class. BuddyService* pMyBuddyService; pMyBuddyService = new BuddyService(); pMyBuddyService->Construct(*pMyListener); pMyBuddyService->GetReceivedBuddyRequests(reqId, 1, 20); pMyBuddyService->RespondToBuddyRequest(*pRequest, RESPONSE_ACCEPT, reqId);

User A can also get the details of the request using ProfileService:: GetProfile() by passing the user ID in the returned ReceivedBuddyRequest instance.

Step 4: Sharing Location Information So far we have learned how to set the profile exposure level, how to send the buddy request, and how to handle the asynchronous event from the server

10_974018-ch05.indd 14410_974018-ch05.indd 144

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

145

using listeners, such as when receiving the results of a buddy request or a profile search request. The final step is to share the location information. The bada Server allows users to share personal data. The user can set their personal information to be sharable – for example, location information using PrivacyManager. In our case, from User A’s side, the application has to implement the following. User A has to get her location by using a new class called Location Provider, which will constantly update the location data from the GPS transceiver. Then User A has to report the location data to the bada Server by using another class called RemoteLocationProvider. The usage of this class is shown in the code snippet below. By calling the StartLocationReport() method, User A starts to report the relocation to the server. To use this method, you have to pass a listener object of type IRemoteLocationEventListener (an interface class), and define the method you want to use to report the location, a Boolean value that sets whether to report extended location information (such as speed and satellite information etc.) to the server or not, and the interval for how frequently the location is reported to the server. //Set your location information can be accessed by your buddy myPrivacyManager->SetUserInfoPrivacy(INFO_LOCATION, ACCESS_BUDDY,reqId); //Create and initialize location provider pLocationProvider->RequestLocationUpdates(); //Report location information to bada server using static function from RemoteLocationProvider RemoteLocationProvider::StartLocationReport(*pListener, LOC_METHOD_HYBRID, false, interval);

Note: In bada, there are two type of location information. One is the local location information that indicates the current location of the device. The other is the remote location information that is stored on the bada Server. It is a record of multiple local locations. Once User A sets her location information sharable and starts to report to the bada Server, User B can now request to receive updates for User A’s location because they are buddies. User B’s implementation looks like the following code snippet: //Add User A to target list ArrayList targetInfoList; TargetInfo targetInfo(userAId); TargetInforList.Add(targetInfo); //Request last known location list

10_974018-ch05.indd 14510_974018-ch05.indd 145

8/31/10 12:37 AM8/31/10 12:37 AM

146

Part I



About bada

bool isExtendedLocationIncluded = false; int maxAge = 100; RequestId reqId; ArrayListT locMethodList; locMethodList.Construct(1); locMethodList.Add(LOC_METHOD_HYBRID); pRemoteLocationProvider = new RemoteLocationProvider(); pRemoteLocationProvider->RequestLastKnownLocationList( isExtenedLocationIncluded, maxAge,locMethodList,targetInfoList, *pListener, reqId);

User B sends the request to the server by calling the RequestLaskKnown LocationList() method defined in the RemoteLocationProvider class. There are several parameters you have to pass to this method: (1) the Boolean value of whether extended location information is required; (2) the oldest location record you want to retrieve from the server; (3) the target list of user IDs for which you want to receive locations; (4) the listener object that you derived from IRemoteLocationListener interface class; (5) the request ID you pass to record about which request has been sent to the server. On receiving the results from the bada Server, the call-back function defined in the IRemoteLocationListener class called OnTargetLocationReceivedN() will be invoked. And the location information is returned with an IMap-type pointer to newly allocated memory. The sequence diagram for location sharing is shown in Figure 5.5. Note that there are multiple instances of the MyListener and RemoteLocation Provider class indicating that both User A and User B have their own instances of these two classes.

Figure 5.5 UML sequence diagram – share location.

10_974018-ch05.indd 14610_974018-ch05.indd 146

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

147

5.3.3 Content Service – Content is King As we described at the beginning of this chapter, content management on bada is divided into two categories: local content management and remote content management. In this section, we explain how to use the Remote content manager to upload and create the content on the server.

Step 1: Implement the Sign-in Form To be able to use the content service, the user has to sign in to the bada Server with a valid Samsung account. Before they can use the content service, your application needs a sign-in form. This step is very easy using the sign-in application control. AppControl* pAppControl = AppManager::FindAppControlN(APPCONTROL_SIGNIN, OPERATION_SIGNIN); if(pAppControl) { pAppControl->Start(null, pListener); delete pAppControl; }

This code automatically generates the sign-in or sign-up form for you. Once the user signs in, they can use the content service. Note: The sign-in process is necessary for some of the bada services such as the social service, location service, and the content management service.

Step 2: Transfer the Content to the Server After a successful sign-in, the user is ready to transfer content to the server. To implement this function, you have to use the ContentTransfer class provided by bada. First, we will explain how to implement the IContentTransfer Listener interface that you need for checking the results from the server. class MyListener : public Osp::Content::IContentTransferListener { public: MyListener(); ~MyListener(); void OnContentDownloadCompleted(RequestId reqId, ContentId contenteId, result r, const String &errorCode, const String &errorMsg); void OnContentDownloadToBufferCompleted(RequestId reqId, ByteBuffer *pBuf, result r, const String &errorCode, const String &errorMsg); void OnContentTransferCanceled(RequestId reqId, result r, const String &errorCode, const String &errorMsg); void OnContentTransferProgress(RequestId reqId, int totalTransferredSize);

10_974018-ch05.indd 14710_974018-ch05.indd 147

8/31/10 12:37 AM8/31/10 12:37 AM

148

Part I



About bada void OnContentUploadCompleted(RequestId reqId, result r, const String &errorCode, const String &errorMsg); void OnContentDescriptorReceived(RequestId reqId, const DownloadDescriptor &descriptor);

};

Once the server receives the completed content, it will invoke OnContent UploadCompleted() method to inform the end user results. You can also check the uploading progress by implementing OnContentTransferProgress() method. The following code snippet is the sample implementation of OnContent UploadCompleted() method. void MyListener::OnContentUploadCompleted(RequestId reqId, result r, const String &errorCode, const String &errorMsg) { if(IsFailed(r)) { AppLog(“Content Upload failed! Reasone (%s)”, errorMsg. GetPointer()); } }

To upload the content, you can just simply call the Upload() method from the ContentTransfer class. pContentTransfer = new ContentTransfer(); pContentTransfer->Construct(myListener); //Defined in step 2 Osp::Base::Utility::Uri uri; RequestId reqId; pContentTransfer->Upload(L”/Media/Images/sourceImg.jpg”, L”/Image/ destinationImg.jpg”, true, uri, reqId); //The four parameters indicate: serFilePath, destFilePath, //replace the exisiting file, request id.

Once the content is uploaded to the server, you have to create the content on the server with its information (metadata). Without its remote content information, the content is not created. In the next step we will start to manipulate the remote server. pRemoteContentInfo = new RemoteContentInfo(); Osp::Base::Utility::Uri uri; uri.SetPath(L”Image.jpg”); r = pRemoteContentInfo->Construct(L”Image”, uri, 123345); AppAssert(IsFailed(r)); r = pRemoteContentInfo->SetContentName(L”My photo”); AppAssert(IsFailed(r), “Set content name failed!”); r = pRemoteContentInfo->SetProvider(L”My name”); AppAssert(IsFailed(r), “Set content provider failed!”);

10_974018-ch05.indd 14810_974018-ch05.indd 148

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

149

Step 3: Set the Remote Content Information To set the remote content information, you have to use the RemoteContent Info class from the Osp::Content namespace.

Step 4: Implement the RemoteContentManagerListener class MyListener : public Osp::Content::IRemoteContentManager { public: MyListener(); ~MyListener(); virtual void OnContentCreated(RequestId reqId, result r, const String &errorCode, const String &errorMsg); virtual void OnContentDeleted(RequestId reqId, result r, const String &errorCode, const String &errorMsg); virtual void OnContentInfoReceivedN(RequestId reqId, RemoteContentInfo *pInfo, result r, const String &errorCode, const String &errorMsg); virtual void OnContentStatusReceived(RequestId reqId, RemoteContentStatus contentStatus, const String &errorCode, const String &errorMsg); virtual void OnContentUpdated(RequestId reqId, result r, const String &errorCode, const String &errorMsg); };

void MyListener::OnContentCreated(RequestsId reqId, result r, const String &errorCode, const String &errorMsg) { if(IsFailed(r)) { AppLog(“Failed to create content on server! Reason(%s)”, errorMsg.GetPointer()); } else { AppLog(“Content Created successfully!”); } }

In the same way as for other bada services, the service listener class has to be implemented by you in order to receive the replies sent by the server. The code snippet above demonstrates the header file of your implementation. There are five virtual methods defined in the IRemoteContentManagerListener interface class. You have to implement them according to your own requirements. For instance, if you want to create the content on the server side, and also want to know whether the create request is successful or not, you will need to implement the OnContentCreated() method. The following code snippet gives you a rough idea of how to implement the OnContentCreated() method.

10_974018-ch05.indd 14910_974018-ch05.indd 149

8/31/10 12:37 AM8/31/10 12:37 AM

150

Part I



About bada

Step 5: Create the Content To create the content on the remote server, you have to use the RemoteContent Manager class. MyListener* myListener; myListener = new MyListener(); RequestId reqId; pRemoteContentManager = new RemoteContentManager(); pRemotecontentManager->Construct(pMyListener); pRemoteContentManager->CreateContent(*pRemoteContentInfo, reqId);

The above code snippet demonstrates how to create the content on the remote server. The parameter pRemoteContentInfo is the one we defined in Step 3. And the MyListener class is the class we defined in Step 4.

5.3.4 Commerce Service – Make Your Own Business The thing that makes the bada platform most unique and interesting is the commerce service. Using the commerce service, developers can not only sell their applications on the Samsung Apps store, but also sell in-app items. The essential part of the commerce service is Samsung Apps, where you set up your own items for sale. Bear in mind that all items you sell have to be set from the seller site of Samsung Apps. It is slightly different from a normal application, because your items are not listed in the Samsung Apps client on device (COD). Figure 5.6 shows you how you can set the items using your Samsung Apps account. Let’s start with how to set up the items on the seller site. Every item listed on store has its own properties, such as name, description, price, currency, image URL, download URL, and two preserved fields for future use.

Step 1: Set up Items on Samsung Apps Seller Office Here is how you can define and register items: First, go to Samsung Apps Seller Office (seller.samsungapps.com) and, in the menu, select Applications | Item Management to submit your items for possible inclusion. Create an item group and add your items to it. Note that you must remember the item group ID to use it as a parameter for the APIs later on. Before registering the application in Samsung Apps (Applications | Add New Application), you can test purchasing items in your application without actual payment (test mode). When you add your application, you can register your items to the application by selecting the item group ID. Not all items are accepted. Please read the terms and conditions at Samsung Apps for more information.

10_974018-ch05.indd 15010_974018-ch05.indd 150

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

151

Figure 5.6 Samsung Apps Seller Office.

Step 2: Using In-App Purchase API There is a good example in the bada SDK explaining how to purchase items from Samsung Apps. Two classes are related with in-app purchase activities: ItemService and PurchaseService. We will now examine how you can use these two classes to implement your own application. The ItemService class only has one method called GetItemList(). You can use it to send a request to the Samsung Apps server to get an item list. You should also specify the item group ID that is a String type. This ID has to exist on the Samsung Apps Seller server. It is always the case that the application is hard-coded with the item group ID. When an application is launched, it will display the items only from this group. Osp::Commerce::Store::ItemService* pItemService; ItemServiceListener *pItemServiceListener; pItemService = new ItemService(); pItemService->Construct(*pItemSerivceListener); //Getting the items start from index 1 to index 2 from the item group with group ID “100000000a7” pItemService->GetItemList(L“100000000a7”, 1, 2, reqId);

In addition, you also have to implement the listener to catch the replies from the server that are needed when you construct the pItemService object.

10_974018-ch05.indd 15110_974018-ch05.indd 151

8/31/10 12:37 AM8/31/10 12:37 AM

152

Part I



About bada

class ItemServiceListener : public Osp::Commerce::Store::IItemServiceListener { public: ItemServiceListener(); ~ItemServiceListener(); void OnItemListReceivedN(RequestId reqId, Osp::Base::Collection::IList* pItemInfoList, result r, const Osp::Base::String & errorCode, onst Osp::Base::String &errorString); };

void ItemServiceListener::OnItemListReceivedN(RequestId reqId, Osp::Base::Collection::IList* pItemInfoList, result r, const Osp::Base::String & errorCode, const Osp::Base::String &errorString) { if(IsFailed(r)) { //print error message } else { //display item information } if(pItemInforList != NULL) { pItemInfoList->RemoveAll(true); delete pItemInfoList; } }

The PurchaseService class is the class that allows users to purchase items and get purchase information such as the payment history on the device. Following the same pattern as the ItemService class, you have to implement both the IPurchaseServiceListener interface class and PurchaseService class. It is very similar to IItemServiceListener mentioned above. Both classes need to have the companion listener interface class to handle the response and results from the Samsung Apps server. class PurchaseServiceListener : public Osp::Commerce::Store::IPurchaseServiceListener { public: PurchaseServiceListener(); ~PurchaseServiceListener(); void OnItemPurchaseCompleted(RequestId reqId,const PaymentId& paymentId, const ItemId& itemId, const String& itemName, double price, String& currency, const DateTime& purchaseDate, result r, const String& errorCode, const String& errorMsg); void OnItemPurchaseInfoReceivedN(RequestId reqId, IList* pPurchaseInfoList,result r, const String& errorCode, const String& errorMsg); };

10_974018-ch05.indd 15210_974018-ch05.indd 152

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

153

To purchase the item, you can use following code snippet: pPurchaseService = new PruchaseService(); pPurchaseService->Construct(pPurchaseServiceListener); result r; RequestId reqId = INVALID_REQUEST_ID; String itemGroupId(L”1000000000a7”); String purchaseItemId(L”000000000517”); r = pPurchaseService->PurchaseItem(itemGroupId, purchaseItemId, reqId);

5.3.5 Component Setup We explained how to set up the sale items on the Samsung Apps Seller Office when you are using the commerce service. There are other services that require you to set up the component via the bada developer site (developer.bada.com). The most common is the remote content management service. Before you actually start to write your code, you have to set up the Amazon S3 workspace for your application.

Step 1: Set Basic Application Information This is the first step when you generate a new application. As part of this step you need to give your application a name, a simple description, and provide version information. Figure 5.7 is a screenshot of Step 1 from the developer web site.

Figure 5.7 Create application profile.

Once you have completed the required information, the Application Manager will lead you to the next step when you click the Next button.

10_974018-ch05.indd 15310_974018-ch05.indd 153

8/31/10 12:37 AM8/31/10 12:37 AM

154

Part I



About bada

Step 2: Select Privileged API Groups Once you decide on an application name and give the description of your application, you need to select the privilege group that includes APIs used by your application. If you want to use the content management features, you need to click at least one privileged API group from CONTENT_TRANSFER, LOCAL_CONTENT, or REMOTE_CONTENT, as shown in Figure 5.8. If you want to use the content service only in your device, select LOCAL_CONTENT. If you want to use the remote content service, which is the service-centric feature, select CONTENT_TRANSFER or REMOTE_CONTENT.

Figure 5.8 Select privileged API groups.

Step 3: Set up Components Once you have selected the privileged API groups, you can set the components for your application. This step covers social components, content components and workspace, as shown in Figure 5.9. The workspace (Amazon S3) is the actual storage space for your physical content files, such as image, video, and audio. When you click the Content Type Management option from Content section, you can create new content types. There are four predefined content types in bada: image, video, audio, and others.

10_974018-ch05.indd 15410_974018-ch05.indd 154

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 5



Exploring bada Services

155

Figure 5.9 Setup components.

Step 4: Set up Amazon S3 Workspace As we mentioned in Step 3, you can also set the workspace within the same web page. The Amazon S3 workspace is the place where your physical content is stored. Your content information (such as content type and attribute information) is stored on the bada Server. That is why it always involves two steps when you create the content on the bada platform: transfer the physical content to the Amazon S3 workspace, and create the content information on the bada Server. The bada developer site provides a simple authentication process for your bada application and the Amazon S3 workspace. Once you click the Setup workspace option, you can set up your Amazon S3 access information. To authenticate your Amazon S3 workspace, you have to obtain an access key, secrete key and bucket name from Amazon. If you do not have these, you can simply register an account through aws.amazon.com/s3/. After completing all the necessary information, click the Connection Check button to verify access to the Amazon S3 server.

10_974018-ch05.indd 15510_974018-ch05.indd 155

8/31/10 12:37 AM8/31/10 12:37 AM

10_974018-ch05.indd 15610_974018-ch05.indd 156

8/31/10 12:37 AM8/31/10 12:37 AM

CHAPTER

6 bada Namespaces

Namespaces in C++, like packages in Java, or import modules in Python, for example, are a language-level mechanism for partitioning the global program namespace. In C++, namespaces can be thought of as a top-level encapsulation mechanism. In bada, namespaces provide a means for structuring the system at a programming level into well-defined, logically coherent, functional subsets. Each namespace declares a discreet subset of the classes that make up the bada class library. In all, bada contains 20 primary namespaces within the top-level Osp namespace, which encapsulates all bada third-party APIs. Around half of the primary namespaces contain one or more nested namespaces, for a total of over 30 namespaces beneath the Osp root namespace. The rest of this chapter summarises each individual namespace.

What You Will Learn This chapter walks through the bada namespaces to highlight the most important features of each, and to place each in the bigger context of the platform as a whole. It will provide you with the following:

157

11_974018-ch06.indd 15711_974018-ch06.indd 157

8/31/10 12:37 AM8/31/10 12:37 AM

158

Part I



About bada

■■

An overview of how the bada platform is partitioned into major functional areas.

■■

An understanding of what contribution to the overall system is made by each namespace.

By the end of the chapter, you’ll know where the interesting functionality is, and how to access it.

What You Will Need To get the most from this chapter, keep your editor open and browse the header files mentioned, which in almost all cases contain useful commentary and code examples.

6.1 using Directives and Declarations If you are not familiar with namespace syntax in C++, don’t despair; it is very straightforward. To use the classes and other definitions from a given namespace in C++, you must include either a using directive to declare all names from the namespace that you want to be available in a given source file, or qualify the names of individual identifiers as they occur in your code using declarations. Where somenamespace is a namespace, a directive has the form: using namespace somenamespace;

And where someidentifier is an identifier (a class name, say, or enumeration), a declaration has the form: using somenamespace::someidentifier;

For example: using namespace Graphics;

makes the Graphics namespace available to all code that follows it, allowing access to Graphics classes such as Canvas and Bitmap. In contrast: using Graphics::Canvas;

makes the Canvas class from the Graphics namespace available, but not the Bitmap class, for which you would need to make a separate declaration: using Graphics::Bitmap;

11_974018-ch06.indd 15811_974018-ch06.indd 158

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

159

To include a nested namespace, for example Ui::Controls, you must explicitly include the nested namespace, and not just the containing namespace. To use a Button object, for example, the following would appear in your code: using namespace Ui; using namespace Ui::Controls;

6.2 How This Chapter Is Organised Figure 6.1 shows how each namespace maps to the main areas of functionality in bada and should provide a starting point for identifying which namespace contains the functionality you need. Section 6.3 describes each of the namespaces in alphabetical order, so once you’ve identified the functionality you need, it’s easy to find out more details.

Figure 6.1 How namespaces map to the main areas of functionality in bada.

Included in the description of most namespaces in this chapter are one or more UML diagrams, designed to show the most important classes in each namespace and the relationship between them. We have included as many classes as possible in the diagrams, but for clarity in some cases we have just focused on the key classes within a particular namespace. In a few cases, there is no UML diagram at all, not because the namespace isn’t interesting, but because the classes are mostly self-contained and a diagram will not add much to the description. If you’re not a UML aficionado, there’s no need to panic. We’ve used just enough UML in this chapter to show how the important classes in each namespace fit together. For a refresher on UML syntax, please see the appendix for a UML primer.

11_974018-ch06.indd 15911_974018-ch06.indd 159

8/31/10 12:37 AM8/31/10 12:37 AM

160

Part I



About bada

Libraries, Headers and Privileges At the beginning of most of the namespace descriptions you’ll also find a privilege table, specifying the privilege groups required to use certain functionality within that namespace. You’ll notice some of the functionality requires privileges at the SYSTEM level that may not be available to all developers, mainly those functions that work together with the bada Server. Check out the developer site at developer.bada.com for the latest information about how your application can obtain this privilege level. More information about obtaining privileges can be found in Chapter 2, and Chapter 4 covers the bada security model in detail, including privileges. We’ve also listed the library and header files required to use each namespace. The individual libraries only need to be included when building for the Simulator; when building your application for the device FOsp is the only library required. To add a library to your project, in the IDE choose Properties | C/C++Build |Settings |bada C++ Linker |Libraries and add the required library by name. In bada, typically each namespace is associated with a single header file containing the namespace declaration and an #include list of all the individual header files that contribute declarations to the namespace. You can find the header file that you need to include at the beginning of each namespace description. At the beginning of each namespace summary we’ve also listed a selection of the most important classes within that namespace, although more classes will be explained in detail in the summary text.

6.3 Namespaces in Detail Osp Declared In:

Framework.h Summary

The top-level namespace that includes all other namespaces in bada. A reference to the original bada project name of Open Service Platform.

Osp::App Declared In:

FApp.h Library:

FApp

11_974018-ch06.indd 16011_974018-ch06.indd 160

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

161

Privileges Required:

Most functionality in this namespace requires no privileges. Some specific application features require the following privileges: Privilege group

Privilege level

Description

NOTIFICATION

NORMAL

Providing user notifications

TELEPHONY

NORMAL

Using the Call application

WEB_SERVICE

NORMAL

Using the Browser application

Note: To use APPCONTROL_SIGNIN, to allow the user to sign in to the bada Server, you must have one of the SYSTEM level privilege groups from CONTENT, LOCATIONS::SERVICES or MESSAGING specified for your application. Prerequisites:

To use notifications, you must ensure that an icon is specified for Ticker and QuickPanel in the project properties in the IDE. Summary

Selected important classes: ■■

Application

■■

AppControl

■■

AppManager

■■

NotificationManager

The App namespace contains the classes that form the basis of application development. Every application must derive from the Application base class that implements the features necessary to create the application, handle initialisation and termination, and provide handlers for system events. As shown in Figure 6.2, your application must implement a factory method that returns your application instance, MyApplication in the diagram. Application contains two pure virtual functions that the application developer must implement: OnAppInitializing and OnAppTerminating. In OnAppInitializing, the application loads any state information from the registry and initialises UI components such as forms and UI controls. In OnAppTerminating the application should write any relevant state information back to the registry and deallocate any resources it is using.

11_974018-ch06.indd 16111_974018-ch06.indd 161

8/31/10 12:37 AM8/31/10 12:37 AM

162

Part I



About bada

Figure 6.2 The main classes in the Osp::App namespace.

You can also implement other system event handlers to take action when the application moves to the background, is moved to the foreground, when the battery state changes, and when memory is so low that the application is about to be terminated, giving you a last chance to free resources and write state information back to the registry. The AppControl class provides access to features exported by bada base applications such as dialling, access to the camera, and calendar entries. The AppManager class finds the specified control (the dialling control, for example) and returns it as an object type AppControl for use by the application. The NotificationManager class includes methods to provide the user with notifications if a new message is received or something requires their attention. A notification can be displayed in the ticker and quickpanel, particularly useful when the application is running in the background, as a result of the user taking a call, for example. You can also implement other system event handlers to take action when the application moves to the background.

Osp::Base Declared In:

FBase.h

11_974018-ch06.indd 16211_974018-ch06.indd 162

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

163

Library:

FBase Privileges Required:

None. Summary

Selected important classes: ■■

ByteBuffer

■■

DateTime

■■

Number

■■

Object

■■

String

This namespace contains the classes and interfaces around which bada is built. The Object class is the root class of bada and most bada classes derive from this class or its descendants. base also provides wrapper classes for representing and manipulating primitive data types such as char, short, double, and bool as well as string handling classes as shown in Figure 6.3. There are also classes to represent date, time, number, and string comparisons. The String class represents a sequence of Unicode characters and contains basic string manipulation methods such as Append(), Insert(), and Replace(). Useful string methods also include: ToUpper() and ToLower(), which are used to change the case and Equals() for string comparisons. The DateTime class represents the date and time using the Gregorian calendar and provides methods to make it easy to perform date and time comparison and calculations, together with TimeSpan, which represents a time interval. This is described in more detail in Chapter 4. ByteBuffer represents a contiguous sequence of bytes in memory and provides methods to read and write most of the C++ primitive types to and from the buffer. ByteBuffers are also used to read from and write data to a file using Io::File.

Figure 6.3 The core classes deriving from Osp::Base::Object.

11_974018-ch06.indd 16311_974018-ch06.indd 163

8/31/10 12:37 AM8/31/10 12:37 AM

164

Part I



About bada

Base also includes wrapper classes for the numeric types defined by bada. The Number classes are shown in Figure 6.4.

Figure 6.4 Numeric types deriving from Osp::Base::Number.

Osp::Base::Collection Declared In:

FBaseCol.h Privileges Required:

None. Summary

Selected important classes: ■■

ICollection

■■

IComparer

■■

IEnumerator

■■

ArrayList

■■

LinkedList

■■

Stack

■■

Queue

■■

HashMap

This is the namespace for handling various collections such as arrays, lists, and stacks. It contains methods to make it easy to create and manipulate these collections. Collections are either object or template based. Object-based collections, derived from ICollection, are used to store objects, while template based collections, deriving from ICollectionT, are used to store interface pointers and primitive types such as int. For the sake of clarity, Figure 6.5 just shows the derivation and relationships between the non-template versions of the classes in the namespace, but for each collection class shown in the diagram there is also a version of the class that takes a templated type – LinkedList and LinkedListT, for example.

11_974018-ch06.indd 16411_974018-ch06.indd 164

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

165

Figure 6.5 Collections deriving from ICollection and related classes.

From the Collection classes shown in Figure 6.5, you just need to choose an appropriate collection class to match the way you want to manage your data. Stack and Queue are simple collections of objects organised in last in, first out (LIFO) order and first in, first out (FIFO) order respectively. ArrayList and LinkedList implement a list of objects that can be accessed by index, whereas HashMap and MultiMap manage a list of key/value pairs, represented by MapEntrys. You can iterate through the elements in both of these collections, to perform an operation on each element, for example, by using the IEnumerator derived class returned by the GetEnumeratorN() method of the collection you’re using. Note: ArrayList and LinkedList are used in the same way, but the implementation of each class is subtly different. ArrayList items are stored in a contiguous area of memory, making accessing the list faster, but adding elements slower than a LinkedList because the entire block of memory may need to be resized as a new item is added. The LinkedList is slower to access, but faster to resize. So if you have a fixed list and you don’t plan on adding or removing items frequently, choose an ArrayList. If the number of items in the list is likely to change more often, use a LinkedList. IComparer derived classes can also be used to Sort() the list in the case of ArrayList and LinkedList, or for key comparison for key/value pair

11_974018-ch06.indd 16511_974018-ch06.indd 165

8/31/10 12:37 AM8/31/10 12:37 AM

166

Part I



About bada

lists. There are number of comparers provided by bada to compare specific types, including IntegerComparer and StringComparer, but for more complex object comparisons, you could derive your own comparison class from IComparer. Note: Object-based collections don’t collect copies of objects; instead, they collect pointers. So any object you want to put into a collection class must be allocated using operator new. Otherwise, if your collection stores a pointer to an automatic variable, its lifetime is unpredictable, and it likely will not exist when the collection comes to use it. Your app will crash, unpredictably.

Osp::Base::Runtime Declared In:

FBaseRT.h Privileges Required:

None. Summary

Selected important classes: ■■

Monitor

■■

Thread

■■

Timer

This namespace includes classes that implement the runtime environment of an application, including threads, synchronisation objects and timers, as shown in Figure 6.6.

Figure 6.6 The main classes in the Osp::Base::Runtime namespace.

11_974018-ch06.indd 16611_974018-ch06.indd 166

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

167

bada applications can have several threads, and synchronisation objects, (mutexes, semaphores, and monitors) are used to control access to shared resources, so that, for example, only one thread at a time has exclusive access to a particular piece of code or shared resource on the device. Timers are used to schedule execution of a particular piece of code.

Osp::Base::Utility Declared In:

FBaseUtil.h Privileges Required:

None. Summary

Selected important classes: ■■

Math

■■

StringUtil

■■

Uri

This namespace provides some useful utility classes. The Math class is a wrapper to the math library providing access to logarithmic functions and other common maths functions, and the other classes provide string handling utilities and a class for creating and analysing URIs.

Osp::Commerce::Store Declared In:

FCommerce.h Library:

FOsp Privileges Required:

To use the functionality in this namespace requires the following privilege: Privilege group

Privilege level

Description

COMMERCE_STORE

NORMAL

Connecting to Samsung Apps to enable In App Purchases

11_974018-ch06.indd 16711_974018-ch06.indd 167

8/31/10 12:37 AM8/31/10 12:37 AM

168

Part I



About bada

Prerequisites:

To use functionality such as In App Purchases you need to have a seller account on Samsung Apps. Summary

Selected important classes: ■■

ItemInfo

■■

ItemService

■■

PurchaseService

The Commerce::Store namespace provides classes and methods to allow applications to retrieve information and make In App Purchases from Samsung Apps. These items might be In App Purchases such as new application services or new levels within a game, for example. The actual purchasing process is handled by the Samsung Apps servers, so all the application needs to do is to allow the user to choose an item to purchase and pass this request onto the server. Figure 6.7 shows how the Commerce::Store namespace is organised. There are two main classes: ItemService for retrieving item information and PurchaseService for actually buying an item. Information for each available item, such as description, price and currency is represented by the ItemInfo class while applications handle ItemService events by implementing the IItemServiceListener. Similarly for purchases, the PurchaseInfo class includes details of the purchase, while responses, such as item successfully purchased or a purchasing error, should be handled by the application’s implementation of the IPurchaseServiceListener.

Figure 6.7 Classes implementing the ItemService and PurchaseService in Osp::Commerce::Store.

Osp::Content Declared In:

FContent.h Library:

FContent

11_974018-ch06.indd 16811_974018-ch06.indd 168

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

169

Privileges Required:

To manipulate content on the device or server requires the following privilege groups to be set: Privilege group

Privilege level

Description

LOCAL_CONTENT

NORMAL

Handling device content

CONTENT_TRANSFER

SYSTEM

Uploading and downloading content to and from a server

REMOTE_CONTENT

SYSTEM

Manipulating content on a server

Prerequisites:

To manipulate remote content developers will need an account on the bada Server. While the information about the remote content is stored on the bada Server, the physical content is stored on an Amazon S3 workspace, which you will need to set up and link to your application. You can set up the Amazon workspace from the Application Manager on the bada developer site, developer. bada.com, in the ‘Set Up Components’ section. Summary

Selected important classes: ■■

ContentInfo

■■

ContentManager

■■

ContentSearch

The Content namespace contains classes and methods that are used to search and manage content both locally on the device and remotely on the server. Content is the logical representation of various media types, including images, audio, and video, containing meta information such as date and time captured, GPS information, description, and the location of the actual content itself. This information can be used to search for content using an SQLlike syntax. Creating, reading, updating, and deleting content is handled by the ContentManager and RemoteContentManager classes. Information in the content database on the device is accessed through specialised classes deriving from ContentInfo: AudioContentInfo, ImageContentInfo, and Video ContentInfo all of which contain information about their particular media types, while OtherContentInfo is used to represent content such as PDFs. As shown in Figure 6.8, these classes are used to hold content information returned by these searches.

11_974018-ch06.indd 16911_974018-ch06.indd 169

8/31/10 12:37 AM8/31/10 12:37 AM

170

Part I



About bada

Figure 6.8 The classes responsible for managing and searching for Osp::Content on a bada device.

Content searches on the device and server are provided by the ContentSearch and RemoteContentSearch classes. Local searches return items deriving from ContentInfo, while remote searches return information in the more flexible RemoteContentSearch class, as shown in Figure 6.9. Once you have the content, use Osp::Media::Player to play it, in the case of audio and video, or for an image, use Osp::Media::Image to decode it into a bitmap and the Osp::Graphics::Canvas to draw the bitmap using the information in ContentInfo. The Content namespace also provides classes to transfer content between the device and the bada Server, useful for sharing information in social networking applications, backing up content, or syncing it with the cloud. The functionality for uploading and downloading content to and from a server is provided by the ContentTransfer class.

Figure 6.9 Content can also be stored and managed remotely using the bada Server.

11_974018-ch06.indd 17011_974018-ch06.indd 170

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

171

Osp::Graphics Declared In:

FGraphics.h Library:

FGraphics Privileges Required:

None. Summary

Selected important classes: ■■

Bitmap

■■

Canvas

■■

EnrichedText

The Graphics namespace contains classes for drawing 2D and 3D primitives, text and images. All graphic primitives are rendered into a Canvas and the Canvas class contains the methods for drawing basic shapes and the graphic settings such as foreground and background colour, line style and font information for text drawing. You can create your own Canvas, but in most cases you will draw into the area of a control. Note: To get a Canvas with the bounds of the whole application frame, use the Osp::App::Application::GetAppFrame method to get the frame control and then Osp::Ui::Control::GetCanvasN to return the Canvas to draw into. Common graphic shapes drawn using the methods of the Canvas class include arcs, lines, rectangles, polygons and text as well as bitmaps. Take a look at Figure 6.10 to see the relationship between Canvas and the other Graphics classes. The Bitmap class contains methods for creating and scaling bitmaps, but bitmaps are actually rendered using the Canvas::DrawBitmap method. Bitmaps are also used to store the images decoded by Osp::Media::Image before the bitmap containing the image is drawn to the canvas. The namespace also contains some core classes used for drawing shapes: Dimension, Point and Rectangle. More advanced 2D and 3D drawing is provided by the Opengl sub-namespace.

11_974018-ch06.indd 17111_974018-ch06.indd 171

8/31/10 12:37 AM8/31/10 12:37 AM

172

Part I



About bada

Figure 6.10 The classes in the Osp::Graphics namespace. Notice the importance of Canvas.

Osp::Graphics::Opengl Declared In:

FGraphicsOpengl.h (for OpenGL ES 1.1) Libraries:

FGraphicsOpengl, FGraphicsEgl Privileges Required:

None. Prerequisites:

Note that not all hardware running the bada platform will support OpenGL. Summary

This namespace provides support for the OpenGL ES 2D and 3D graphics library. OpenGL ES is a cross-platform standard for embedded systems and provides full functionality for 3D games. By supporting OpenGL ES, bada allows developers to make use of graphics code originally written for other mobile platforms. The EGL library provides the rendering surfaces into which OpenGL draws and connects the OpenGL calls to bada’s underlying windowing system. Note: Support is provided for both OpenGL ES 1.1 and Open GL ES 2.0. Which version is available to you depends on whether the device’s hardware will support it.

11_974018-ch06.indd 17211_974018-ch06.indd 172

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

173

Osp::Io Declared In:

FIo.h Library:

FIo Privileges Required:

None. Summary

Selected important classes: ■■

Database

■■

Directory

■■

File

As shown in Figure 6.11, the Io namespace includes wrapper classes to handle files, directories, databases, and registries. The File class provides support for creating, deleting, writing to, and reading from files using raw buffers and strings. To get information about files and directories, use the FileAttributes class. Applications only have write access to files in their home or shared directory – which is used to share data with other applications.

Figure 6.11 Core classes in the Osp::Io namespace.

The Database class provides support for basic database functions, creating and deleting databases, and executing SQL commands. It also includes support for transactions and rollback, which are very useful functions when using SQL databases. The SQL used by the Database class is SQLite (www.sqlite.org). Note: The database is for storage on the local device only, there is no support for connecting to remote databases. The Registry class supports creating, writing to, and reading from registry files, which an application typically uses to store settings. This is different from the registry managed by App::AppRegistry, which only the application can access. An application could store a file created by Io::Registry in

11_974018-ch06.indd 17311_974018-ch06.indd 173

8/31/10 12:37 AM8/31/10 12:37 AM

174

Part I



About bada

its shared directory and grant read-only access to its settings information to a group of applications, for example.

Osp::Locales Declared In:

FLocales.h Library:

FLocales Privileges Required:

None Summary

Selected important classes: ■■

Calendar

■■

DateTimeFormatter

■■

Locale

■■

LocaleManager

■■

NumberFormatter

■■

TimeZone

Locales contains classes that make it easy for you to localise your application for international markets, ensuring that numbers, dates, and currencies are all displayed in a way consistent with the setting for a particular Locale. A Locale contains a language code and a country code, as well as a variant, a setting that may be used to differentiate between language settings such as simplified and traditional Chinese, for example. TimeZone allows you to encode and manipulate locale specific time information, such as Daylight Saving Time settings and time zone differences. Most of the work of formatting numbers and dates for a specific Locale is the responsibility of the DateTimeFormatter and NumberFormatter classes, which are shown in Figure 6.12. To format a number for a particular locale, you need to use a static factory function, such as NumberFormatter::CreateNumberFormatter or NumberFormatter::CreateCurrencyFormatterN to create a NumberFormatter object and use this to format a number with the correct groupings, decimals, and currency symbols for the specified locale. You can also choose to customise the format by using a pattern language very similar to that used on other platforms.

11_974018-ch06.indd 17411_974018-ch06.indd 174

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

175

Figure 6.12 The classes that make up the Osp::Locales namespace.

The following listing shows how to format a number for the current system locale: LocaleManager localeManager; localeManager.Construct(); Locale systemLocale = localeManager.GetSystemLocale(); NumberFormatter* pNumberFormatter= NumberFormatter::CreateNumberFormatterN(systemLocale); String formattedString; double num = 12345.67; pNumberFormatter->Format(num, formattedString);

Formatting dates is a similar process, just call DateTimeFormatter::Create DateTimeFormatterN and use the DateTimeFormatter to format a date for the specified locale. The current date can be obtained by using System::SystemTime::GetCurrentTime, and for more control over the date and time you can use the Calendar class. Calendar represents the date as a series of TimeFields, and provides an AddTimeField function allowing you to perform calculations on dates – moving forward or back a certain number of minutes, days or months, for example. The localised day and month names are stored in the DateTimeSymbol class, which can be retrieved from DateTimeFormatter or constructed on its own. For support for various text encodings, see the Osp::Text namespace.

11_974018-ch06.indd 17511_974018-ch06.indd 175

8/31/10 12:37 AM8/31/10 12:37 AM

176

Part I



About bada

Osp::Locations Declared In:

FLocations.h Library:

FLocations Privileges Required:

Using the features of Locations requires the following privilege levels be set to access the specified areas of functionality: Privilege group

Privilege level

Description

LOCATION

NORMAL

Accessing location information on the device

LANDMARK

NORMAL

Accessing the landmark store on the device

REMOTE_LANDMARK REMOTE_LOCATION REMOTE_TRACE

SYSTEM

Accessing location services using the bada Server.

Summary

Selected important classes: ■■

IAreaListener

■■

ILocationListener

■■

ITraceServiceListener

■■

LocationProvider

■■

Landmark

■■

LandmarkStore

■■

RemoteLocationProvider

This namespace has classes and interfaces for acquiring the location of local and remote devices. Sub-namespaces supply the classes to handle map services and map display. The starting point for processing location information is the LocationProvider class, as shown in Figure 6.13. An application can implement listener methods of this class to be notified of the device location at regular intervals, or when the device location crosses a specified area boundary. In both cases a Location object is sent to the listener method containing information about location, speed and the time the data was collected.

11_974018-ch06.indd 17611_974018-ch06.indd 176

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

177

Figure 6.13 The role of the LocationProvider class in the Osp::Locations namespace.

Server Supported Services

Using the bada Server, together with the RemoteLocationProvider class, developers can also access information about remote devices, periodically report the last location of the local device to the server, and use the SubscribeToTraceService method and ITraceServiceListener class to record a path of travel. Reporting device location to the bada Server is done using the StartLocationReport method, together with the ILocationReportListener class. This causes location information to be uploaded to the bada Server periodically, information that will then be available for other authenticated devices to read. To retrieve the last known locations of remote devices, use the RequestLastKnownLocationList method, passing in a list of TargetInfo objects that identify a device from the user’s bada Server userID. You can also narrow down the results to devices with last known locations inside a given area using the RequestLastKnownLocationListInCircle and RequestLastKnownLocationListInRectangle methods. Landmarks

The Landmark class represents a named geographical location that has a name and contains extra information such as a description and a URL. Applications can create their own landmarks, from a user-selected location on a map, for example, or use pre-defined landmarks provided by other applications or third-party content providers.

11_974018-ch06.indd 17711_974018-ch06.indd 177

8/31/10 12:37 AM8/31/10 12:37 AM

178

Part I



About bada

Landmark information is stored in a database on the device managed by the LandmarkStore class, which contains classes to create, modify, delete, and search for landmarks within a specified area or with a given name or category (such as a restaurant or theatre), for example. The landmark functionality becomes a lot more powerful when used with the bada Server and the RemoteLandmarkStore class, which allows landmark information to be shared between applications using the bada Server. Information in remote landmark stores consists of user-created stores, where the landmark information can be shared between all devices that use the same application, or pre-defined stores that are handled by third-party content providers and available to all applications. Note: Landmarks are usually drawn on a map in the overlay layer as markers of the class Locations::Controls::MapOverlayMarker. See the discussion of the way that maps are drawn in the Locations:: Controls namespace description.

Osp::Locations::Controls Declared In:

FLocations.h Privileges Required:

None. Summary

Selected important classes: ■■

IMapOverlay

■■

IMapEventListener

■■

Map

Provides classes and methods for rendering maps and UI controls to allow the user to customise the way a map is displayed and to interact with it. Maps are drawn in five layers, with the map layer drawn first, each layer adding its own set of graphical information. The main classes used to render each layer of the map are shown in Figure 6.14.

11_974018-ch06.indd 17811_974018-ch06.indd 178

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

179

Figure 6.14 Classes for rendering a Map within a UI control.

The purpose of each layer and the related classes and methods for manipulating this information is as follows: Zoom

The top layer containing UI controls for zooming. The application implements IMapEventListener::OnMapZoomingStarted and OnMapZoomingEnded to be notified when the user zooms the map. Info Window

Word bubbles that display useful information about locations and businesses. This may include a brief description of a business and its contact details, for example. Info windows are created using the NativeMapInfoWindow class for pre-defined windows and IMapInfoWindow classes for user-defined windows. MyLocation

Displays the current location on the map, together with a circular bounds showing the margin of error. The application can choose whether to display this information by using the Map::SetMyLocationEnabled method. Overlay

An interactive layer with shapes marking out locations on the map and markers that can be moved by the user like pins on a physical map. Shapes – polygons, circles, and rectangles – can be included in a map by adding objects deriving from the MapOverlayShape class, while movable markers derive from MapOverlayMarker as shown in Figure 6.15.

11_974018-ch06.indd 17911_974018-ch06.indd 179

8/31/10 12:37 AM8/31/10 12:37 AM

180

Part I



About bada

Applications implement the IMapOverlayEventListener to handle the events received when the user moves the markers around. Map

The basic map graphic as provided by the map service provider and encapsulated by the Map class. Methods of this class provide lots of control over how the map is displayed, including its size and bounding rectangle.

Figure 6.15 Classes for adding overlays to a Map.

Osp::Locations::Services Declared In:

FLocations.h Privileges Required:

Using the features of Locations::Services requires the following privilege group: Privilege group

Privilege level

Description

LOCATION_SERVICE

NORMAL

Using the directory, geocoding, map or route services

11_974018-ch06.indd 18011_974018-ch06.indd 180

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

181

Prerequisites:

An account with a geographic services provider. Summary

Selected important classes: ■■

IDirectoryServiceProvider

■■

IMapServiceProvider

■■

IRouteServiceProvider

■■

ProviderManager

This namespace provides support for geographic information services: maps, geocoding, directory, and route services. The starting point for implementing these services is the ProviderManager class, which retrieves information about the service providers available to the device and allows the application to choose the one that provides the appropriate services. Support for map services is provided by a set of interface classes called to get map information and render the map. The IMap interface implements dynamic maps from the service provider, supporting features such as panning and zooming, the UI for which is handled by classes in the Locations::Controls namespace. Route and Directory Services

The Route Service is implemented by the IRouteServiceProvider and IRouteServiceListener, and allows the application to request a route, given a set of waypoints – which, at a minimum, must consist of a start and destination – and parameters such as mode of transport and whether the route is the fastest or shortest. The application is returned a list of Routes, which contains a set of coordinates representing the route and information such as length, estimated travelling time, and a set of RouteSegments. The application could then display this information on a map to provide services such as turn-by-turn directions. The classes that provide the Route Service are shown in Figure 6.16. The Directory Service allows application developers to implement a userfriendly search for products and services within a specified geographic area – coffee shops within a certain city, for example. Developers put together their search request with the methods of IDirectoryServiceProvider and process the response asynchronously using IDirectoryServiceListener. The search results are returned as a list of Landmarks. Underpinning these services is the geocoding service, which converts an address into geographic coordinates and vice versa.

11_974018-ch06.indd 18111_974018-ch06.indd 181

8/31/10 12:37 AM8/31/10 12:37 AM

182

Part I



About bada

Note: To make use of these services, you’ll need an account with a geographic information services provider such as deCarta (www. decarta.com), which is the map provider currently supported by bada. However, you can provide access to maps within an application by using the Web::Control class and web sites such as www.googlemaps.com.

Figure 6.16 Classes that manage the functionality of service providers in Osp::Locations::Services.

Osp::Media Declared In:

FMedia.h Library:

FMedia

11_974018-ch06.indd 18211_974018-ch06.indd 182

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

183

Privileges Required:

Using the features of this namespace requires one or more of the following privilege groups, depending on the functionality you’re making use of: Privilege group

Privilege level

Description

CAMERA

NORMAL

Accessing the camera

IMAGE

NORMAL

Manipulating images

RECORDING

NORMAL

Recording audio and video

DRM_CONTENT

NORMAL

Manipulating DRM content

Summary

Selected important classes: ■■

Camera

■■

Player

■■

AudioRecorder

■■

VideoRecorder

This namespace contains classes for audio, video, and image processing, playing, and capturing. Note: The Image class is used for encoding, decoding, and converting images, but to draw an image will also require classes from other namepaces. For example, to draw an image you need to decode the image into a bitmap container defined in Osp::Graphics::Bitmap, create a rectangle to act as the image bounds and then use the method of Osp::Graphics::Canvas to actually draw the image. The other important media handling classes are shown in Figure 6.17 and described below. Player is used for playing audio and video stored locally on the device or streamed across the network. AudioRecorder and VideoRecorder classes are used to capture audio and video on the device. Camera contains methods to provide a live preview and capture a still image from the camera. The application has a lot of control over the camera and can modify settings such as contrast, effects, zoom, and flash from Camera class methods.

11_974018-ch06.indd 18311_974018-ch06.indd 183

8/31/10 12:37 AM8/31/10 12:37 AM

184

Part I



About bada

Figure 6.17 Core classes in the Osp::Media namespace.

Note: You can test out camera functionality using the Simulator on a PC with a webcam, although depending on the hardware, not all camera settings will be available. Media Format Support

A wide variety of standard audio playback formats are supported: MP3, AAC, WMA, M4A, XMF, 3GA, MMF, MIDI, WAV, and AMR. Audio can be recorded in AMR or WAV formats. The range of video playback formats is also wide – WMV, ASF, AVI, MP4, and 3GP – while video can be recorded in MP4 and 3GP formats. The following image formats can be decoded by the Image class: BMP, GIF, JPEG, PNG, TIFF, and WBMP. Images can be output in BMP, JPEG, and PNG formats. Audio and video files protected by the OMA and Windows Media Digital Rights Management (DRM) formats can also be played.

Osp::Messaging Declared In:

FMessaging.h

11_974018-ch06.indd 18411_974018-ch06.indd 184

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

185

Library:

FMessaging Privileges Required:

Sending a message using the classes in this namespace requires the following privilege group: Privilege group

Privilege level

Description

MESSAGING

SYSTEM

Sending SMS, MMS and email messages

Summary

Selected important classes: ■■

EmailManager

■■

MmsManager

■■

SmsManager

This namespace provides access to the message handling capabilities of the device. An application can send SMS, MMS or email messages. In order to check on the status of messages being sent, developers implement a listener for each type of message to receive status information asynchronously. Figure 6.18 shows the SmsManager, the RecipientList, and the SmsMessage, together with the ISmsListener which is implemented to receive message state information. MMS and email message sending is organised in a similar way with a recipient list, a class to represent the message, and a listener that is implemented to receive information about message status.

Figure 6.18 The Messaging::SmsManager and related classes.

11_974018-ch06.indd 18511_974018-ch06.indd 185

8/31/10 12:37 AM8/31/10 12:37 AM

186

Part I



About bada

Note: Push messages are not supported by version 1.0.0b3 of the bada SDK, which is the current version at the time of writing.

Osp::Net Declared In:

FNet.h Library:

FNet Privileges Required:

You will need at least one of the privilege groups listed below to use the features of this namespace and possibly more, depending on what features you’re using: Privilege group

Privilege level

Description

NET

NORMAL

Manipulating netaccount information

NET_STATISTICS

NORMAL

Accessing information on a data call

NET_ACCOUNT

SYSTEM

Creating and deleting net accounts

Prerequisites:

You may need to use a proxy server if you are behind a firewall. Summary

Selected important classes: ■■

NetAccountInfo

■■

NetAccountManager

■■

NetConnection

This namespace is responsible for accessing the data communications capabilities of bada. It contains classes for establishing, maintaining, and monitoring the connections required to send and receive data over a network. It also provides methods to retrieve information about a specific host using the internet Domain Name System (DNS). Sub-namespaces are provided for managing Wi-Fi and Bluetooth connections, and sending and receiving data using HTTP or low-level socket functions.

11_974018-ch06.indd 18611_974018-ch06.indd 186

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

187

Figure 6.19 Creating and managing connections using the classes in the Osp::Net namespace.

As shown in Figure 6.19, the main classes used to create a network connection are NetAccountManager and NetAccountInfo which encapsulates the configuration information necessary to establish a remote connection, such as a Wi-Fi access point name, DNS and authorisation information. The NetConnection class then uses this information to establish a connection and data can then be sent to and received from the remote host.

Osp::Net::Bluetooth Declared In:

FNetBluetooth.h Privileges Required:

You will need the following privilege group to make use of the features of this namespace: Privilege group

Privilege level

Description

BLUETOOTH

NORMAL

Creating connections, sending and receiving data

Prerequisites:

Bluetooth must be activated on the device. Note that it is not possible to test the features of Bluetooth using the Simulator. Summary

Selected important classes: ■■

BluetoothDevice

■■

BluetoothManager

11_974018-ch06.indd 18711_974018-ch06.indd 187

8/31/10 12:37 AM8/31/10 12:37 AM

188

Part I



About bada

This sub-namespace provides classes and methods for implementing Bluetooth data protocols. It provides methods for pairing (creating connections), and sending and receiving data over a Bluetooth connection (see Figure 6.20).

Figure 6.20 Some of the main classes in the Osp::Net::Bluetooth namespace.

Facade classes are also provided for Bluetooth profiles, such as: ■■

GAP (General Access Profile)

■■

OPP (Object Push Profile)

Note: At time of writing, the current version 1.0.0b3 does not support the Serial Port Profile.

Osp::Net::Http Declared In:

FNetHttp.h Privileges Required:

You will need at least the first of the privileges listed in the table below to make use of the features of this namespace: Privilege group

Privilege level

Description

HTTP

NORMAL

Setting up HTTP sessions

COOKIE

SYSTEM

Removing stored cookies from a HTTP session

11_974018-ch06.indd 18811_974018-ch06.indd 188

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

189

Summary

Selected important classes: ■■

HttpHeader

■■

HttpSession

■■

HttpTransaction

The Http sub-namespace provides a set of classes that support the HTTP protocol, allowing an application to act as an HTTP 1.1 compliant client, with support for standard features such as pipelining and chunking, and communicating with HTTP servers on the Internet. Secure connections using HTTPS, with the SSL 3.0 and TLS 1.0 protocols, are also supported. The main classes in the Http namespace are shown in Figure 6.21. To send HTTP requests, you must first set up a HttpSession that includes the connection type (the default is to send plain text over a TCP/IP connection), a proxy server (if any), and the URL of the host server that you’re sending HTTP requests to. To send a HTTP request and receive a response, you use a HttpTransaction, which manages the interaction between client and server. Clients support one or more sessions while a session can consist of many transactions. Messages are packaged up to be sent using the HttpRequest class, while the response is received as a HttpResponse. Adding a header to a request or reading one or a whole list of headers in a response is made easy in bada by using HttpHeader.

Figure 6.21 Classes in the Osp::Net::Http namespace implement the HTTP protocol.

11_974018-ch06.indd 18911_974018-ch06.indd 189

8/31/10 12:37 AM8/31/10 12:37 AM

190

Part I



About bada

Like the rest of the communications features of bada, HTTP requests are dealt with asynchronously, so to receive responses to a HTTP request, and to upload messages which are divided into chunks, you need to implement a IHttpTransactionEventListener. For those web sites that require a name and password, you can specify this information when you open a HttpTransaction by wrapping the login information up in an HttpAuthentication object.

Osp::Net::Sockets Declared In:

FNetSockets.h Privileges Required:

You will need the following privilege to make use of the features of the Sockets sub-namespace: Privilege group

Privilege level

Description

SOCKET

NORMAL

Creating a socket connection, sending and receiving data

Summary

Selected important classes: ■■

SecureSocket

■■

Socket

Sockets implements socket data communications protocols, similar to the standard BSD socket library. A socket is described as an endpoint, one side of the communication between two applications running on a network. bada supports TCP/IP, UDP, and secure sockets, and the stream and datagram protocols. Applications should implement the ISocketEventListener to process socket events asynchronously. The various classes for implementing socket functionality are shown in Figure 6.22. Notice that both standard and secure sockets are supported in bada.

Osp::Net::Wifi Declared In:

FNetWifi.h

11_974018-ch06.indd 19011_974018-ch06.indd 190

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

191

Figure 6.22 Osp::Net::Sockets implements functionality similar to the BSD sockets library.

Privileges Required:

You will need at least the first privilege group in the table below to make use of the features of this namespace: Privilege group

Privilege level

Description

WIFI

NORMAL

Setting up an ad-hoc network, getting information on local WiFi devices

WIFI_MANAGER

SYSTEM

Establishing a connection to a specific access point

Prerequisites:

Wi-Fi must be activated on the device and you must be connected to a wireless network. Note that it is not possible to test Wifi functionality using the Simulator. Summary

Selected important classes: ■■

AdhocService

■■

WifiManager

■■

WifiNetAccountInfo

11_974018-ch06.indd 19111_974018-ch06.indd 191

8/31/10 12:37 AM8/31/10 12:37 AM

192

Part I



About bada

This namespace contains classes and methods to get information about an active Wi-Fi connection, allowing developers to gain access to the SSID and security info by using the methods of the WiFiNetAccountInfo class. To control the current Wi-Fi connection, use the WiFiManager class, which contains methods for activating and deactivating connections, joining a specified WiFi network and returning information about the WiFi status of the device. The WifiManager and related classes are shown in Figure 6.23.

Figure 6.23 The main classes in the Osp::Net::Wifi namespace, used for managing Wi-Fi devices.

Wifi also contains classes for creating and managing an ad-hoc Wi-Fi network, so bada users can connect with their friends and play multiplayer games, for instance. This functionality is managed by the AdhocService class.

Osp::Security Declared In:

FSecurity.h

11_974018-ch06.indd 19211_974018-ch06.indd 192

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

193

Library:

FSecurity Privileges Required:

None. Summary

Selected important classes: ■■

PrivateKey

■■

PublicKey

■■

SecretKey

■■

SecretKeyGenerator

■■

AesSecureRandom, DesSecureRandom, DesEdeSecureRandom

The Security namespace provides a platform wide security system and advanced security services such as: cryptographic functions, certificate management services, key management and user authentication with single sign on. bada supports generating pseudo random numbers using the following algorithms: AES using the AesSecureRandom class, DES using DesSecureRandom, and 3DES using DesEdeSecureRandom. These functions generate cryptographically secure random numbers (CSPRNG), which can be used in bada to generate secret keys using the SecretKey, SecretKeyGenerator and related interface classes (see Figure 6.24). A secret key could be used for password protecting a file, for example.

Figure 6.24 The Osp::Security classes for generating a secret key.

11_974018-ch06.indd 19311_974018-ch06.indd 193

8/31/10 12:37 AM8/31/10 12:37 AM

194

Part I



About bada

Public/private key pairs for use in RSA standard PKI (Public Key Infrastructure) protected messages are generated by using the KeyPair and KeyPairGenerator and related interface classes. PKI is used for creating digital certificates to verify message senders and ensure a message has not been tampered with. A message in this context could refer to an email or document or a stream, for example. Adding digital signatures to messages and verifying signed messages are handled by the Crypto and Cert sub-namespaces.

Osp::Security::Cert Declared In:

FSecCert.h Privileges Required:

None. Summary

Selected important classes: ■■

X509Certificate

This namespace provides classes for getting information from X509 standard security certificates used to validate a message. The X509Certificate class represents a certificate that contains methods to return information about the certificate and a Verify method that takes an IPublicKey as a parameter and checks to see if the certificate was signed using the corresponding private key. This can be used to check if a message has been tampered with, for example.

Osp::Security::Crypto Declared In:

FSecCrypto.h Privileges Required:

None. Summary

Selected important classes: ■■

IHash

■■

IHmac

■■

RsaCipher

■■

RsaSignature

11_974018-ch06.indd 19411_974018-ch06.indd 194

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

195

This namespace contains classes and methods to support various types of encryption and decryption. There are four basic types of encryption supported: one-way encryption using hashing, encryption using a secret key, encryption using a public and private key, and the use of digital signatures. Public/private key pairs are used in two ways: to encrypt a message with a public key so that only the person with the corresponding private key can read it and to use a private key to digitally sign a document. Anyone with the public key can read the message, but signing it with a digital signature provides proof that it has not been tampered with. The RsaCipher and RsaSignature classes provide support for encrypting and signing with public/private key pairs.

Osp::Social Declared In:

FSocial.h Library:

FSocial, FSocialLifelog (if you are accessing the lifelog) Privileges Required:

Using the features of this namespace will require at least one of the privileges listed in the table below, depending on what functionality you implement: Privilege group

Privilege level

Description

ADDRESSBOOK

NORMAL

Accessing the address book on the device

CALENDARBOOK

NORMAL

Accessing the calendar on the device

LIFELOG

SYSTEM

Accessing the lifelog

Summary

Selected important classes: ■■

Addressbook

■■

Calendarbook

■■

Lifelog

The Social namespace contains classes to maintain the user’s personal data, address book, calendar, and lifelog on a device. The lifelog is a log of activities over a certain period of time, including calling and messaging, together with cell-based location information. You can think of this namespace

11_974018-ch06.indd 19511_974018-ch06.indd 195

8/31/10 12:37 AM8/31/10 12:37 AM

196

Part I



About bada

as providing the tools to write applications to help users interact with each other. It includes classes that are responsible for getting, manipulating, and sharing data and a set of server-assisted features that are implemented by the Social::Services namespace. The most important classes within the Social namespace are Addressbook, Calendarbook, and Lifelog. The Addressbook class allows access to the address book database on the device providing methods for adding and deleting categories and contacts, and searching for contact information. Addressbook and the classes which it uses is shown in Figure 6.25. Calendarbook provides methods to allow the application to create, edit, and modify events, and to-do lists stored in the device’s calendar, set up reminders and recurring events and respond when event information is changed. Calendarbook and the classes for implementing features like to-do lists and reminders are shown in Figure 6.26.

Figure 6.25 Addressbook and related classes.

Figure 6.26 Calendarbook and related classes.

11_974018-ch06.indd 19611_974018-ch06.indd 196

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

197

Lifelog lets an application analyse the most frequently called numbers, list the callers between a range of dates or from cell-based locations, as well as process the lifelog database in many other ways.

Osp::Social::Services Declared In:

FSocial.h Privileges Required:

All of the features of this namespace work together with the bada Server and SYSTEM level privileges are required for all of the services it implements: Privilege group

Privilege level

Description

BUDDY_SERVICE

SYSTEM

Buddy service

MESSAGING_SERVICE

SYSTEM

Message service

PRIVACY_SERVICE

SYSTEM

Privacy service

PROFILE_SERVICE

SYSTEM

Profile service

SNS_SERVICE

SYSTEM

SnsGateway

Prerequisites:

The user will need to be signed into an account on the bada Server to use most of these features and will also need to set their privacy levels so their friends can see them. Summary

Selected important classes: ■■

BuddyService

■■

MessagingService

■■

PrivacyManager

■■

ProfileService

■■

Profile

■■

SnsGateway

The Services namespace provides different ways for users to interact using the features of the bada Server. There are features provided to build social relationships between bada users, and a social networking aggregation

11_974018-ch06.indd 19711_974018-ch06.indd 197

8/31/10 12:37 AM8/31/10 12:37 AM

198

Part I



About bada

service (SNA) that provides built-in support for social networking services such as Facebook and Twitter all from within the application. As you can see from the table, the functionality of services can be broken into five groups: Profile, Privacy, Messaging, and Buddy management work with the features of the bada Server to connect bada users, while the SnsGateway provides the link from the application through the bada Server and onto social networking sites. The ProfileService class is used to manage profiles. A user’s profile actually consists of several different parts: a BasicProfile, which is public by default, and other profiles, such as ContactProfile and SocialProfile, which are available across the device to all permitted users, but which are set as private when stored on the bada Server. Users must choose to be listed in the public directory on the bada Server and can also choose which of their other profiles are available to be accessed by all or a specified group of users. You need to implement IProfileServiceListener to respond to requests initiated from the ProfileService. The ProfileService and the various types of Profiles are shown in Figure 6.27.

Figure 6.27 How the ProfileService manages the different kinds of Profiles.

Access to a user’s profile and other information such as their location is handled by the PrivacyManager class. This controls which parts of a user’s profile information can be searched by other users and who has access to that information – buddies, for example. Developers need to implement the IPrivacyManagerListener class to implement this functionality. Users of the bada Server can be connected as Buddys – a mutually confirmed relationship between two users. Sending and responding to buddy

11_974018-ch06.indd 19811_974018-ch06.indd 198

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

199

requests is handled by the BuddyService class and because, as with most other requests in the Services namespace, these requests are handled asynchronously, you need to implement the IBuddyServiceListener. The classes that are used to implement the BuddyService are shown in Figure 6.28.

Figure 6.28 The classes that go to make up the BuddyService.

The MessagingService is used for applications to send text messages between devices to one user or a group of users. Messages are send via the bada Server and you need to implement IMessageServiceListener and IMessageServerEventListener to take advantage of this functionality. Note : The MessagingService can only be used to send messages between the same application on different devices, not between different applications. SnsGateway

The SnsGateway class manages one of the most powerful features of the Services namespace, allowing you to create applications that can easily communicate with social networking sites such as Facebook, MySpace, and Twitter, and retrieve information such as pictures and status updates, all from within your application. All you need to do is use the SnsGateway class and related classes such as SnsAuthenticator, and the low-level work of connecting to and retrieving information from the various social networking sites is taken care of for you by the bada Server. The organisation of the classes making up the functionality of the SnsGateway is shown in Figure 6.29.

11_974018-ch06.indd 19911_974018-ch06.indd 199

8/31/10 12:37 AM8/31/10 12:37 AM

200

Part I



About bada

Figure 6.29 Classes that allow access to social networking sites, as provided by the SnsGateway.

SnsGateway helps to present a unified view of all the information from various sites, representing the retrieved information in classes such as SnsPhotoInfo and SnsStatusText, which you can then display in whatever way you want. Note: A Buddy as managed by the BuddyService refers to another user of the bada Server and is different from the concept of a buddy as returned by the SnsGateway::GetMyBuddies method. The latter refers to a buddy in a social networking service such as Facebook or MySpace and represented by a SnsProfile.

Osp::System Declared In:

FSystem.h Library:

FSystem Privileges Required:

To access any of the functions of this namespace, you need the following privilege group:

11_974018-ch06.indd 20011_974018-ch06.indd 200

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

Privilege group

Privilege level

Description

SYSTEM_SERVICE

NORMAL

Accessing the features of the utility classes provided by this namespace

201

Summary

Selected important classes: ■■

Alarm

■■

Battery

■■

PowerManager

■■

RuntimeInfo

■■

SettingInfo

■■

SystemInfo

■■

SystemTime

■■

Vibrator

The System namespace provides access to device level information including system time, the alarm service, operating the vibrator device, battery levels and charge status, and power management. The system time can be returned as UTC (coordinated universal time) and local time with or without any adjustment for daylight saving time. The classes that provide the functionality of the System namespace are shown in Figure 6.30. Note: Applications should check the battery level (using Battery:: GetCurrentLevel) before starting a particularly power-intensive function such as playing multimedia content. The Osp::App::Application::OnBatteryLevelChanged is invoked whenever the battery level changes. If the battery level is critical, the application should stop using multimedia features, and if it is empty, the application should save state information and prepare to terminate. System contains a number of classes for getting information about the device. RuntimeInfo returns information such as the amount of memory, and internal and external storage available to an application. SettingInfo provides access to system settings such as whether silent mode is switched on, whether GPS or data roaming is active, and the current language setting and country code. SystemInfo is mainly used for obtaining information about the capabilities of the device, such as the number of cameras, whether Bluetooth is supported, and the version of OpenGL ES that the device supports.

11_974018-ch06.indd 20111_974018-ch06.indd 201

8/31/10 12:37 AM8/31/10 12:37 AM

202

Part I



About bada

Figure 6.30 Osp::System consists of a group of self-contained utility classes.

Using the PowerManager class you can implement and register listeners to be notified when the screen switches on or off (IScreenEventListener) or when the charging state of the device changes (IChargingEventListener). PowerManager also includes the KeepScreenOnState method, which can be used to keep the screen on until the application is sent to the background. This is useful when using features such as media players or the camera.

Osp::Telephony Declared In:

FTelephony.h Library:

FTelephony Privileges Required:

To use the features of this namespace you need the following privilege group: Privilege group

Privilege level

Description

TELEPHONY

NORMAL

Getting network and SIM information

Summary

Selected important classes: ■■

CallManager

■■

NetworkManager

■■

SimInfo

This namespace provides classes to access the telephony features of the device and contains methods for getting information about the current call and network information, and access to information from the SIM card (see Figure 6.31).

11_974018-ch06.indd 20211_974018-ch06.indd 202

8/31/10 12:37 AM8/31/10 12:37 AM

Chapter 6



bada Namespaces

203

Figure 6.31 Accessing the Osp::Telephony features of the device.

Osp::Text Declared In:

FText.h Library:

FText Privileges Required:

None. Summary

Selected important classes: ■■

Decoder

■■

Encoder

■■

Encoding

This namespace contains classes to handle various text encodings including Unicode, ASCII, GSM and UTF-8, as shown in Figure 6.32. Classes are also provided to convert text between formats. Those interested in localising their applications should also review the Osp::Locales namespace, which is used for handling number, date, and currency formats.

Osp::Ui Declared In:

FUi.h Library:

FUi

11_974018-ch06.indd 20311_974018-ch06.indd 203

8/31/10 12:38 AM8/31/10 12:38 AM

204

Part I



About bada

Figure 6.32 Text encoding and decoding as provided by the Osp::Text namespace.

Privileges Required:

None. Summary

Selected important classes: ■■

Container

■■

Control

■■

Window

The Ui namespace together with the Controls sub-namespace provide the classes and methods to implement a GUI. The Ui namespace provides common base classes for all controls as well as interfaces for event handlers. An application UI is divided into layers of a frame, forms, and controls. The frame is the top-level window of an application and an application can have only one. Within that are forms – there can be many forms within an application and within forms are controls, which are handled by the Controls sub-namespace.

Osp::Ui::Controls Declared In:

FUiControls.h

11_974018-ch06.indd 20411_974018-ch06.indd 204

8/31/10 12:38 AM8/31/10 12:38 AM

Chapter 6



bada Namespaces

205

Privileges Required:

None. Summary

Selected important classes: ■■

Form

■■

Frame

The Controls sub-namespace contains control classes and other methods for displaying and interacting with the UI: creating controls, control layout, and responding to control events. Controls are GUI components that are displayed inside an application frame. Controls are divided into two types: containers such as forms, panels, and popups that can contain other controls, and standard controls, such as buttons, lists, and sliders. Container controls will typically have a parent/child relationship with the controls that they contain. Figure 6.33 shows the main UI controls. Note: When you delete a container control, you must not delete the controls that it contains because this will be done automatically for you by the system.

Figure 6.33 UI controls. Notice which ones are Container controls.

11_974018-ch06.indd 20511_974018-ch06.indd 205

8/31/10 12:38 AM8/31/10 12:38 AM

206

Part I



About bada

Osp::Uix Declared In:

FUix.h Library:

FUix Privileges Required:

None. Summary

Selected important classes: ■■

FaceDetector

■■

FaceRecognizer

■■

Haptic

■■

Motion

■■

SensorManager

■■

WeatherSensor

This namespace contains classes to implement UI extensions – unconventional UI features that are not covered by basic UIs. While conventional applications interact with the user via menus and physical buttons, the bada UI extensions provide ways of using the device in unconventional ways and give the application developer access to built-in sensors. The classes that represent the UI extensions are shown in Figure 6.34.

Figure 6.34 UI extensions provided by the Osp::Uix namespace.

11_974018-ch06.indd 20611_974018-ch06.indd 206

8/31/10 12:38 AM8/31/10 12:38 AM

Chapter 6



bada Namespaces

207

The FaceDetector is the class used to locate a face in a still image or camera preview, while the FaceRecognizer will analyse this image and try and identify it from a list of already identified faces. A device can contain many sensors available to application developers, including acceleration, magnetic, proximity, and tilt sensors. The SensorManager class is used to determine whether a sensor is available and to add or remove the sensor event handlers, while the SensorData class is used to retrieve information from that sensor. The classes that handle the functionality of these sensors are shown in Figure 6.35.

Figure 6.35 Sensors provided by the Osp::Uix namespace.

Note: Sensor monitoring methods such as ISensorEventListener:: OnDataReceived are called from a separate thread to the main thread, so that they are not slowed down by the API calls in the main thread. This means that if you implement monitoring of a sensor, you should minimise what you do in the OnDataReceived method and do any drawing in the main thread. This also applies to the weather services classes, including WeatherSensor and WeatherForecast, which are used to retrieve weather data for a given location.

Osp::Web Declared In:

FWeb.h

11_974018-ch06.indd 20711_974018-ch06.indd 207

8/31/10 12:38 AM8/31/10 12:38 AM

208

Part I



About bada

Library:

FWeb Privileges Required:

Some of the functions of this namespace require privileges, as explained in the table below: Privilege group

Privilege level

Description

WEB_PRIVACY

NORMAL

Accessing the web history

Summary

Selected important classes: ■■

HistoryItem

■■

WebHistory

This namespace contains classes and methods to interact with the browser engine. It contains classes that track browsing history. The functionality for displaying a web browser inside a window is handled by the Controls sub-namespace.

Osp::Web::Controls Declared In:

FWebControls.h Privileges Required:

To use the features of this namespace, you must have the following privilege group: Privilege group

Privilege level

Description

WEB_SERVICE

NORMAL

Constructing a web control

Summary

Selected important classes: ■■

Web

11_974018-ch06.indd 20811_974018-ch06.indd 208

8/31/10 12:38 AM8/31/10 12:38 AM

Chapter 6



bada Namespaces

209

This sub-namespace provides web browsing functionality to an application. A full web browser can be embedded in an application window just like any other control. This control can be used to download web content to the device and run Javascript (using the EvaluateJavaScriptN method of Web). The web control is based on the WebKit standard.

Osp::Xml Declared In:

FXml.h Library:

FXml Privileges Required:

None. Summary

Contains methods to manipulate XML documents using the standard libXml2 library for parsing document content.

11_974018-ch06.indd 20911_974018-ch06.indd 209

8/31/10 12:38 AM8/31/10 12:38 AM

11_974018-ch06.indd 21011_974018-ch06.indd 210

8/31/10 12:38 AM8/31/10 12:38 AM

PART

II Recipes

12_974018-pp02.indd 21112_974018-pp02.indd 211

8/31/10 12:38 AM8/31/10 12:38 AM

12_974018-pp02.indd 21212_974018-pp02.indd 212

8/31/10 12:38 AM8/31/10 12:38 AM

GROUP

1 Fundamentals

Recipe 1.1: Save to and Restore from the Registry Problem Description You want to write some application settings to the registry and restore them when your application launches again.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::App, Osp::Base

Header files to #include: FBase.h, FApp.h

Required libraries: FBase, FApp

Required privilege level: Normal

Required privilege groups: None

213

13_974018-gr01.indd 21313_974018-gr01.indd 213

8/31/10 12:39 AM8/31/10 12:39 AM

214

Part II



Recipes

The application registry is where you store the application state. This may include application settings such as user preference information, the current player status in a game, or configuration information that you don’t want the user to have to re-enter each time the application is run. So, for example, if the user is several levels into a complicated game, they don’t want to start all over again if they quit the application and open it again later. By storing the game state in the registry, an application developer can let them resume their game playing at the point they chose to stop. In this recipe we’ll demonstrate how to write values to and read them from the registry. Our example is a very simple currency application that provides up-to-date currency exchange rates for the UK pound against the US dollar and euro. We use the application registry to store the last known euro and dollar exchange values and the time that these values were last updated. The recipe consists of the following steps: 1. Set up the initial values for our registry entries. 2. Read each entry from the registry. If the entry does not exist, create it. 3. Restore our application state from the registry entries. 4. Write the updated entry back to the registry when the application is about to terminate. The App::AppRegistry class contains the methods to read from and write to the registry. In our class AppRegistrySample we read from the registry in the application’s OnAppInitializing method, which is sent a reference to the application’s registry: bool AppRegistrySample::OnAppInitializing(AppRegistry& appRegistry) { // The String String String

keys for each registry entry DollarKey (“LastDollarValue”); EuroKey (“LastEuroValue”); DateKey (“DateUpdated”);

// Set up initial values for our registry entries double DollarValue (1.53); double EuroValue(1.17); // Set the default date value to be the current time DateTime dateUpdated; SystemTime::GetCurrentTime(dateUpdated); String currentDateString = dateUpdated.ToString(); result r; // Read the last known value of each setting from the registry // If the registry entry does not exist, create it r = appRegistry.Get(DollarKey, DollarValue); if (r == E_KEY_NOT_FOUND) {

13_974018-gr01.indd 21413_974018-gr01.indd 214

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

215

appRegistry.Add(DollarKey, DollarValue); } r = appRegistry.Get(EuroKey, EuroValue); if (r == E_KEY_NOT_FOUND) { appRegistry.Add(EuroKey, EuroValue); } r = appRegistry.Get(DateKey, currentDateString); if (r == E_KEY_NOT_FOUND) { appRegistry.Add(DateKey, currentDateString); } // Save any updated data to the registry r = appRegistry.Save(); //...

The first time the application is run the AppRegistry will already exist but will be empty. It’s your responsibility to add registry entries. Each registry entry has a key – a String that identifies it – and a value – which can be either of type String, int or double. In our example we store the last known dollar and euro exchange rate as a double and the time that these values were last updated as a String converted from a DateTime value. To read from the registry we use the AppRegistry::Get() method. If this returns a E_KEY_NOT_FOUND error, we create the registry entry with AppRegistry::Add(), setting it to our default value. Then we store these values in our internal data structure and use this to restore our application state. In our case we display a form with the values read from the registry, as shown in Figure R1.1.

Figure R1.1 We store the last known exchange rates and the time they were last updated in the application registry.

When the application is about to terminate, your application’s OnAppTerminating() method will be called with a reference to your AppRegistry passed as a parameter. In this method you should update your registry entry

13_974018-gr01.indd 21513_974018-gr01.indd 215

8/31/10 12:39 AM8/31/10 12:39 AM

216

Part II



Recipes

with the current values. In our example, we’ll update the registry entries for the current exchange rate and the time this information was last updated: bool AppRegistrySample::OnAppTerminating(AppRegistry& appRegistry, bool forcedTermination) { String DollarKey (“LastDollarValue”); String EuroKey (“LastEuroValue”); String DateKey (“DateUpdated”); result r; // Write the current settings out to the registry r = appRegistry.Set(DollarKey, mDollarRate); if (IsFailed(r)) { // Handle error condition } r = appRegistry.Set(EuroKey, mEuroRate); if (IsFailed(r)) { // Handle error condition } r = appRegistry.Set(DateKey, mDateUpdated); if ( IsFailed(r)) { // Handle error condition } // Make sure the changes are written out to persistent storage appRegistry.Save(); return true; }

We update our registry entries with the AppRegistry::Set() method. Notice that at the end of the method we call AppRegistry::Save(). This ensures that our updated registry entries are written to persistent storage. Our registry entries are now up to date, ready to restore our application the next time it is launched.

Hints, Pitfalls, and Related Topics The application registry should be used for storing application settings and similar state information, not for larger amounts of data that should either be stored in a File or Database object, as provided by the Io namespace. File is useful for storing large blocks of information that will generally be written out and read back into memory in one block. A Database object is a SQLite database that is useful for storing information that you want to search through and update easily.

13_974018-gr01.indd 21613_974018-gr01.indd 216

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

217

Recipe 1.2: Use Error Handling in bada Problem Description bada does not support the standard C++ exception handling mechanism. However, you need to catch and handle exceptions, which you can do by exploiting the mechanisms built into bada.

The Recipe The following configuration is required for this recipe: Namespaces used: N/A

Header files to #include: N/A

Required libraries: N/A

Required privilege level: Normal

Required privilege groups: None

The content of this recipe is not related to any specific namespace. What we describe here is rather a generally valid concept and describes the way in which bada handles exceptions. The reason for this speciality lies in the fact that the bada SDK was designed with optimised runtime efficiency in mind. Most of the standard C++ was applied. However, the bada SDK does not comply with standard C++ exception handling. Although this is a very convenient and well-proven technique, it is also very heavyweight and resource intensive. The bottom line is: bada is for mobile devices, which are embedded devices that are resource restricted compared to desktop computers. Hence, programming for these devices should also be treated differently. That is why in bada there is no standard C++ exception handling. The exception handling in bada was designed to be extremely lightweight and simple. To realise this, a specific type was defined that is called result. This result type holds information about exceptions that have occurred and can be queried accordingly. Many different values are defined for describing the potentially occurring exceptions. Later in this recipe we give a list of these values. The most common way to make use of the result type in bada is to use it as a return value for relevant methods. The bada API that opens up the SDK

13_974018-gr01.indd 21713_974018-gr01.indd 217

8/31/10 12:39 AM8/31/10 12:39 AM

218

Part II



Recipes

to developers makes intensive use of this result type return value to allow for exception checking. Just to mention one example here: the Camera class of the Osp::Media namespace provides the StartPreview() method that is defined as follows: result Osp::Media::Camera::StartPreview( const Osp::Graphics::BufferInfo* pBufferInfo, bool previewedData = false );

This method starts displaying the preview image from the camera device. If pBufferInfo is null, no preview image will be displayed. If previewedData is true, previewed image data comes to the ICameraEventListener::OnCameraPreviewed() method periodically based on the frame rate, otherwise the callback will not be invoked. The default value of previewedData is false. Interesting for this recipe is the return value which is of type result to model potentially occurring exceptions. The exceptions that can happen in this method are summarised in Table R1.1. Table R1.1

The error codes that can be returned by the call to Camera::StartPreview

E_SUCCESS 

The method was successful

E_INVALID_STATE 

This method is invalid for the current state of the camera

E_UNSUPPORTED_FORMAT 

The specified format is not supported

E_DEVICE_BUSY 

The device cannot be approached because of other operations

E_DEVICE_UNAVAILABLE 

The device is unavailable

E_DEVICE_FAILED 

The device operation failed

E_OUT_OF_MEMORY 

There is insufficient memory

E_PRIVILEGE_DENIED 

The application does not have the privilege to call this method

An example of how to make use of this exception handling in bada is highlighted in the following code snippet: result r =E_SUCCESS; // Let’s assume we have a constructed pCamera object of type Camera* r = pCamera->StartPreview(null, false); if(IsFailed(r)) { // process the error condition } else { // continue normally }

13_974018-gr01.indd 21813_974018-gr01.indd 218

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

219

Another use of bada exception handling takes effect when a method already returns some other value or data type. In that case we cannot make use of the result return type directly. For this case, bada offers the static method GetLastResult(), which returns the last exception or the result set with the SetLastResult() method. This value is unique per thread and persists until SetLastResult() is called for that thread again. To get more expressive error messages the error code held by the result type can be translated in statements which are predefined in the bada SDK. The translation happens by invoking the static GetErrorMessage() method, which returns a char*. To show an example we stick to the Camera class and present another method that already returns a type other than result. The method is called GetSupportedPreviewResolutionListN(), which returns a list of dimensions representing the supported camera resolutions. If null is returned, an exception occurred. The method has the following signature: Osp::Base::Collection::IList* GetSupportedPreviewResolutionListN (void);

An exception occurring within this method can be handled by the GetLast Result() method, which we show in the following code snippet: result r =E_SUCCESS; // Let’s assume we have a constructed pCamera object of type Camera* Osp::Base::Collection::IList* pList = null; pList = pCamera->GetSupportedPreviewResolutionListN(); if (pList == null) { r = GetLastResult(); AppLog(“Operation failed with error: %s”, GetErrorMessage(r)); // Continue with further necessary actions }

Predefined bada error codes are listed in Table R1.2 with a description of when they are returned. Table R1.2 bada error codes Error code

Description

E_ADDRESS_CHANGED

The network address has been changed externally

E_ALREADY_BOUND

The target is bounded to another source

E_ALREADY_CONNECTED

The target is connected to another source

E_ALREADY_OPENED

The target is already opened (continued)

13_974018-gr01.indd 21913_974018-gr01.indd 219

8/31/10 12:39 AM8/31/10 12:39 AM

220

Part II



Recipes

Table R1.2 (continued) Error code

Description

E_AUTHENTICATION

The authentication request fails

E_CONNECTION_BUSY

The connection is busy, so cannot process the new request

E_CONNECTION_FAILED

The connection to the specific destination fails

E_CONNECTION_RESET

The connection is reset while the other thread is still working on it

E_DATA_NOT_FOUND

The requested data does not exist

E_DATABASE

The underlying database system has raised an exception

E_DECODING_FAILED

The decoding operation has failed

E_DEVICE_BUSY

The device is processing the previous task, so cannot process the new one

E_DEVICE_FAILED

The device fails for an unknown reason

E_DEVICE_INCOMPATIBLE

The device does not support the specific request

E_DEVICE_UNAVAILABLE

The device is not installed, or not answering at all

E_DHCP

General DHCP exception

E_DNS

General DNS exception

E_DNS_NOT_FOUND

DNS cannot resolve the requested address

E_EFFECTS_DISABLED

Effects being played on the current haptic device have been disabled

E_EMPTY_BODY

A body is empty

E_ENCODING_FAILED

An encoding operation has failed

E_END_OF_FILE

An end of the file or an end of the stream has been reached unexpectedly during an input operation

E_FDN_MODE

The application has tried to call with a number that is not allowed in FDN mode, while the FDN mode is enabled

E_FILE_ALREADY_EXIST

An attempt to create the file denoted by a specified pathname has failed

E_FILE_NOT_FOUND

An attempt to open the file denoted by a specified pathname has failed

E_GROUP_NOT_FOUND

A required group does not exist

E_HOST_NOT_FOUND

The destination host is not found

E_HOST_UNREACHABLE

The destination host is unreachable

E_ILLEGAL_ACCESS

The user does not have proper permissions

13_974018-gr01.indd 22013_974018-gr01.indd 220

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

Error code

Description

E_IN_PROGRESS

The application requests an operation that is in progress

E_INACCESSIBLE_PATH

The return type is supposed to be file path, but the path is not accessible to the application

E_INIT_FAILED

Initialisation has failed

E_INSTANTIATION_FAILED

An instantiation has failed for a particular reason

E_INSUFFICIENT_PRIORITY

The haptic device priority is lower than that of the current effects being played, belonging to another device instance

E_INTERRUPTED

The requested operation cannot continue because of an interruption from another thread

E_INVALID_ACCOUNT

The account configuration is invalid

E_INVALID_ADDRESS

The given address is invalid or not suitable for a requested operation

E_INVALID_ARG

A combination of passed information is not valid for performing the requested operation

E_INVALID_CONDITION

A combination of passed information is not valid for performing the requested operation

E_INVALID_CONNECTION

An operation has requested an invalid connection

E_INVALID_CONTENT

The content is invalid

E_INVALID_CONTEXT

The context is invalid

E_INVALID_DATA

The requested (given or referenced) data is invalid

E_INVALID_DOMAIN

The requested (given or referenced) domain is invalid

E_INVALID_ENCODING_RANGE

An indicated string contains code pointing outside of the bounds set by the specified character encoding scheme

E_INVALID_FORMAT

The specified input has an invalid format

E_INVALID_KEY

The specified input has an invalid format

E_INVALID_OPERATION

The current state of the instance prohibits the execution of the specified operation

E_INVALID_PROXY

The proxy address is invalid

E_INVALID_SIM_STATE

The SIM is not in a proper state for processing the requested operation

E_INVALID_SERVER

The DNS request goes to an invalid DNS server

221

(continued)

13_974018-gr01.indd 22113_974018-gr01.indd 221

8/31/10 12:39 AM8/31/10 12:39 AM

222

Part II



Recipes

Table R1.2 (continued) Error code

Description

E_INVALID_SESSION

The relevant session is invalid

E_INVALID_SOCKET

The socket that is responsible for the application’s request is invalid

E_INVALID_STATE

An instance is not in a valid state

E_INVALID_TRANSACTION

The relevant transaction is invalid

E_IO

An exception has occurred during input/output (I/O) operations. This is a general exception produced by failed or interrupted I/O operations

E_KEY_ALREADY_EXIST

A specified key already exists

E_KEY_NOT_FOUND

A required key does not exist

E_LANDMARK

An error related to handling landmark has occurred

E_LIBRARY_NOT_FOUND

A specified library does not exist

E_LIBRARY_NOT_LOADED

A specified library is not loaded

E_LINK

A link error has occurred

E_LOCATION

A Location API-specific error has occurred

E_LOCATION_SERVICE

An error related to handling service provider requests has occurred

E_LOCK_FAILED

Locking (or unlocking) has failed inside the logic, so synchronous operation cannot be guaranteed

E_MAX_EXCEEDED

The defined limit is exceeded

E_MISSING_INPUT

One or more of the required input has not been provided

E_NETWORK_FAILED

General network exception

E_NETWORK_UNAVAILABLE

The network is not enabled

E_NOT_A_MEMBER

The operation is permitted only for members and the current user is not a member

E_NOT_PAIRED

Bluetooth pairing is not established

E_NOT_RESPONDING

The target is not responding

E_NUM_FORMAT

The specified string does not represent a valid number

E_OBJ_ALREADY_EXIST

The specified instance already exists

E_OBJ_NOT_FOUND

The required instance does not exist

E_ON_INITIALIZING

A request occurs while the target is still initializing

E_OPERATION_CANCELED

The operation is cancelled explicitly

E_OPERATION_FAILED

The operation fails for a particular reason

13_974018-gr01.indd 22213_974018-gr01.indd 222

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

Error code

Description

E_OUT_OF_MEMORY

The memory is not sufficient to perform the requested operation

E_OUT_OF_RANGE

The internal state of the current instance reaches the valid range

E_OVERFLOW

The operation has caused an overflow

E_PAIRING_FAILED

The requested Bluetooth pairing fails

E_PARSING_FAILED

The parsing of some sort of content failed

E_PRIVILEGE_DENIED

An application invokes an API without a proper privilege

E_READ_ONLY

A write operation is requested for an instance in read only mode

E_REJECTED

The operation is rejected by a remote site

E_RESOURCE_UNAVAILABLE

The required resource is currently unavailable

E_RIGHT_EXPIRED

The right to get served has expired

E_SECTION_ALREADY_EXIST

The specified section already exists

E_SECTION_NOT_FOUND

The required section does not exist

E_SERVER

A server tells the device that operation failed for some reason. A detailed message will be followed by the error code and an error message

E_SERVICE_BUSY

The dedicated service module is too busy to handle another request

E_SERVICE_LIMITED

The specific service is restricted by policy

E_SERVICE_LOCKED

The service is locked

E_SERVICE_UNAVAILABLE

The dedicated service is not available

E_SESSION_DEACTIVATED

The base session is deactivated while still being used

E_STORAGE_FULL

The storage is full

E_SYMBOL_NOT_FOUND

The specified symbol is not found

E_SYNTAX

The input statement does not confirm to the specific syntax

E_SYSTEM

A failure has occurred in the underlying system

E_TABLE_NOT_FOUND

The specified table does not exist

E_TIMEOUT

The operation can not be completed within the specified time period

E_TYPE_MISMATCH

The specified type does not match

223

(continued)

13_974018-gr01.indd 22313_974018-gr01.indd 223

8/31/10 12:39 AM8/31/10 12:39 AM

224

Part II



Recipes

Table R1.2 (continued) Error code

Description

E_UNDERFLOW

The operation causes an underflow

E_UNKNOWN

An unknown error has occurred

E_UNSUPPORTED_ALGORITHM

The specified algorithm is not supported

E_UNSUPPORTED_CODEC

The required CODEC is not found

E_UNSUPPORTED_FAMILY

The requested address family is not supported

E_UNSUPPORTED_FORMAT

The current implementation does not support the format of the input

E_UNSUPPORTED_PROTOCOL

The specified protocol is not supported

E_UNSUPPORTED_OPERATION

The current implementation does not support the requested operation

E_UNSUPPORTED_OPTION

The specified option is not supported

E_UNSUPPORTED_SERVICE

The specified service is not supported

E_UNSUPPORTED_TYPE

The specified type is not supported

E_USER_AGENT_NOT_ALLOWED

Used by an HTTP transaction

E_USER_ALREADY_REGISTERED The user is already registered to the device E_USER_NOT_FOUND

The required user does not exist

E_USER_NOT_REGISTERED

No user is registered to the device yet

E_WOULD_BLOCK

A non-blocking socket operation could not be completed immediately

Recipe 1.3: Use Two-phase Construction and Leak-free Destruction Problem Description You want to construct bada objects by using the two-phase construction mechanism in order to avoid memory leaks.

The Recipe The following configuration is required for this recipe:

13_974018-gr01.indd 22413_974018-gr01.indd 224

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

225

Namespaces used: N/A

Header files to #include: N/A

Required libraries: N/A

Required privilege level: Normal

Required privilege groups: None

The content of this recipe is not related to any specific namespace. What we present here is rather a generally valid concept that describes a way of constructing and destroying objects in bada that avoids memory leaks. This speciality of bada is related to the way exceptions are handled in bada, which was described in the recipe ‘Use Error Handling in bada’. In order to optimise runtime efficiency, bada does not support standard C++ exception handling. Instead, exceptions are handled by using the specific result type, which serves as a return value. For constructing objects you need to use the constructor of a class. A constructor, however, does not provide a return value. The other possibility would be to throw an exception within the constructor. As bada does not support C++ standard exception handling this is also not possible. So, to circumvent this situation and still comply with the design goal of optimised runtime efficiency the two-phase construction concept of bada is used. This concept defines that the object construction is broken down into two phases: 1. Object creation with the class constructor, where no memory allocation for the various members happens – so an exceptional condition would not result in the risk of a memory leak. 2. Object construction with an additional Construct() method, in which the memory allocation actually happens. This Construct() method provides a result return value that can be queried for exceptions. For the destruction of an object, a class destructor can be used that follows traditional C++ conventions. The following code example should help to clarify this two-phase construction concept:

13_974018-gr01.indd 22513_974018-gr01.indd 225

8/31/10 12:39 AM8/31/10 12:39 AM

226

Part II



Recipes

result r =E_SUCCESS; // 1. Phase: create object: Popup* pPopup = new Popup(); // 2. Phase: construct object (=allocations): r = pPopup->Construct(true, Dimension(400, 500)); // Exception handling: if (IsFailed(r)) { AppLog(“Operation failed with error: %s”, GetErrorMessage(r)); delete pPopup; // Process error condition ... }

Most of the bada SDK follows this pattern. You are free to implement your object construction as you like. It is, however, highly recommended to follow this two-phase construction patterns in your classes – for obvious reasons. We show now how you can simply implement this two-phase construction concept in your classes. First we define a header file called MyOwnClass.h, which holds the standard constructor and destructor but in addition also has the Construct() method and for demonstration purposes the two members Osp::Ui::Controls::Button* pButton and Osp::Base::String* myString. We also define the public interface GetString(), which allows the caller to access the String stored in the member myString. #include #include class MyOwnClass { public: // Standard constructor MyOwnClass(); // Standard destructor virtual ~MyOwnClass(); // The actual construction result Construct(Osp::Base::String s); private: // Some member objects Osp::Ui::Controls::Button* pButton; Osp::Base::String* myString; public: Osp::Base::String* GetString(); };

13_974018-gr01.indd 22613_974018-gr01.indd 226

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

227

We now switch to the implementation of this class, namely MyOwnClass.cpp: // #include and using declarations are omitted MyOwnClass::MyOwnClass() { // Not much to do here } MyOwnClass::~MyOwnClass() { delete pButton; delete myString; } result MyOwnClass::Construct(String s) { result r =E_SUCCESS; pButton = new Button(); r = pButton->Construct(Rectangle(/*dimensions*/), L”Some Text”); if (IsFailed(r)) { AppLog(“Operation failed with error: %s”, GetErrorMessage(r)); return E_SYSTEM; } r =E_SUCCESS; myString = new String(); r = myString->Insert(s, 0); if (IsFailed(r)) { AppLog(“Operation failed with error: %s”, GetErrorMessage(r)); return E_SYSTEM; } returnE_SUCCESS; } String* MyOwnClass::GetString() { return myString; }

Important is to note that the Construct() method holds all the logic dealing with instantiation of the member objects and their memory allocation. If something goes wrong, for demonstration purposes we return the error value E_SYSTEM as result. If all is fine E_SUCCESS is delivered. In the following code fragment we show how our class can be constructed without risking memory leaks.

13_974018-gr01.indd 22713_974018-gr01.indd 227

8/31/10 12:39 AM8/31/10 12:39 AM

228

Part II



Recipes

AnyClass::TestMyOwnClass() { result r =E_SUCCESS; // 1. Phase: creation MyOwnClass* pMyOwnClass = new MyOwnClass(); // 2. Phase: construction r = pMyOwnClass->Construct(“A test String.”); // Error handling if (IsFailed(r)) { AppLog(“Operation failed with error: %s”, GetErrorMessage(r)); delete pMyOwnClass; // Further processing of error condition } // Show that the member myString was initialized correctly: AppLog( “pMyOwnClass->myString = %S”, pMyOwnClass->GetString()->GetPointer()); }

Hints, Pitfalls, and Related Topics In some very simple cases bada APIs use ordinary construction, for example string handling as the following example describes: String str; str.Append(“To this first part …”); str.Append(“… a second one is appended ! “);

Recipe 1.4: Create an AppControl to Interact with a Base Application Problem Description You want to launch a base application from a bada application using the Application Control.

The Recipe The following configuration is required for this recipe:

13_974018-gr01.indd 22813_974018-gr01.indd 228

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

229

Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::App, Osp::Base::Collection

Header files to #include:

FUi.h, FUiControls.h, FApp.h, FBase.h

Required libraries:

FUi, FUiControls, FApp, FBase

Required privilege level: Normal

Required privilege groups: WEB_SERVICE1

Base applications are those that are stored in the built-in memory of the device and are not removable via the Application Manager. Base applications export features that are commonly required by other applications, for example, playing a video, or retrieving a contact. Access to these features is provided through Application Control. The Application Manager is used to find the base application that provides the feature required by an application, and an instance of the Application Control is returned. The Application Control is then used to start a base application and control specific behaviour. Once the Application Control is started, the application goes to the background and the target application control UI is displayed. This recipe shows two different examples of accessing functionality from a base application. Each example details the steps required to use the Application Control to access the necessary functionality, and provides some sample code snippets. Both examples in this recipe assume the steps detailed in Method 2 of the ‘Add a Form to a Frame-based App’ recipe (which you can find in the second group of recipes, “UI Basics,” later in this book) have been followed to add a Form to the application’s Frame.

Example 1: Launching the Browser Application This recipe uses Application Control to launch the base application browser with a specific URI (see Figure R1.2). The relevant data to be delivered to the Application Control, in this case the URI, is constructed using a collection of type Osp::Base::Collection::ArrayList. As the Browser Application Control does not return any status information or data, no callback listener is required.

1

Required for Example 1 only.

13_974018-gr01.indd 22913_974018-gr01.indd 229

8/31/10 12:39 AM8/31/10 12:39 AM

230

Part II



Recipes

Figure R1.2 Application Control – launching the browser.

The WEB_SERVICE group privilege is required to use the Browser Application Control. The following steps are necessary to launch the Browser base application with the specified URI: 1. Use the Application Manager to find the Application Control for launching the browser. 2. Create an instance of an ArrayList collection to store the Application Control data in. 3. Create an instance of a String and initialise it with the url: tag and the URI for the Browser Application Control to launch. 4. Start the Browser Application Control, passing in the URI data in an ArrayList. The following code snippet is an example of a method that would be added to the MainForm’s class to launch the browser to a specified URI: result MainForm::LaunchBrowser(void) { result r =E_SUCCESS; // Find the required Application Control based on the application // control id and the type of operation required

13_974018-gr01.indd 23013_974018-gr01.indd 230

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

231

AppControl* pAc = AppManager::FindAppControlN(APPCONTROL_BROWSER, OPERATION_MAIN); if(pAc != null) { // Create an ArrayList and initialise ArrayList* pDataList = null; pDataList = new ArrayList(); pDataList->Construct(); // Create String for URI and add to the ArrayList String* pData = null; pData = new String(L”url:http://www.bada.com”); pDataList->Add(*pData); // Start the required application with the relevant data. // As the BROWSER does not provide any callback data, no // listener is required. r = pAc->Start(pDataList, null); delete pAc; pDataList->RemoveAll(true); delete pDataList; } else { r =E_OBJ_NOT_FOUND; } return r; }

Once the Application Control Start() method has been called, the application goes to the background and the browser UI is displayed. When the user exits the browser application, the application returns to the foreground.

Example 2: Retrieving Phone Numbers from the Contacts List This recipe uses Application Control to launch the Contacts application and allows the user to select multiple phone numbers from the list of contacts (see Figure R1.3). The relevant data to be delivered to the Application Control, in this case the selection mode and the return type, is constructed using a collection of type Osp::Base::Collection::ArrayList. To allow the user to select phone numbers from the Contacts application it is launched with the PICK operation. This operation results in some data being returned from the Contacts Application Control when it is exited. This data is the result of the operation and the value strings of the selected contacts. To receive data from the Contacts Application Control the application needs to implement the Osp::App::IAppControlEventListener interface.

13_974018-gr01.indd 23113_974018-gr01.indd 231

8/31/10 12:39 AM8/31/10 12:39 AM

232

Part II



Recipes

Figure R1.3 Application Control – select items from Contacts application.

The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::App::IAppControlEventListener { // Construction public: MainForm(void); ~MainForm(void); bool Initialize(void); public: result OnInitializing(void); result OnTerminating(void); void OnAppControlCompleted(const Osp::Base::String& appControlId, const Osp::Base::String& operationId,

13_974018-gr01.indd 23213_974018-gr01.indd 232

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

233

const Osp::Base::Collection::IList* pResultList); result GetContact(void); void DisplayContact(Osp::Base::String* number); };

The following steps are necessary to launch the Contacts base application: 1. Use the Application Manager to find the Application Control for launching the Contacts application with the PICK operation. 2. Create an instance of an ArrayList collection to store the Application Control data. 3. Create an instance of a String, initialise it with the selectionMode: tag and the selection mode for the Contacts application (in this example multiple selection mode is defined), and add it to the ArrayList. 4. Create an instance of a String, initialise it with the returnType: tag and the return type for the Contacts application (in this example the phone number value string is requested), and add it to the ArrayList. 5. Start the Contacts Application control, passing in the Application Control data in an ArrayList and a pointer to the Application Control callback listener. The following code snippet is an example of a method that would be added to the MainForm’s class, in order to launch the Contacts application for the required operation: result MainForm::GetContact(void) { result r =E_SUCCESS; // Find the required Application Control based on the application // control id and the type of operation required AppControl* pAc = AppManager::FindAppControlN(APPCONTROL_CONTACT, OPERATION_PICK); if(pAc != null) { // Create an ArrayList and initialise ArrayList* pDataList = null; pDataList = new ArrayList(); pDataList->Construct(); // Create String for selection mode and add to the // ArrayList String* pData1 = null; pData1 = new String(L”selectionMode:multiple”); pDataList->Add(*pData1); // Create String for return type and add to the ArrayList String* pData2 = null; pData2 = new String(L”returnType:phone”);

13_974018-gr01.indd 23313_974018-gr01.indd 233

8/31/10 12:39 AM8/31/10 12:39 AM

234

Part II



Recipes

pDataList->Add(*pData2); // Start the required application with the relevant data // As the CONTACTS app is going to return phone numbers, // the callback listener must be sent to the // application control. r = pAc->Start(pDataList, this); delete pAc; pDataList->RemoveAll(true); delete pDataList; } else { r

=E_OBJ_NOT_FOUND;

} return r; }

The IAppControlEventListener interface receives notification events from the Application Control when it is done (i.e. the operation has completed or has been cancelled). The type of notification data received depends on the type of Application Control started and the operation type used. For this example, the implementation of the OnAppControlCompleted() method must handle both Application status results and multiple items of Contacts data. The following steps describe the functionality that would be implemented in the OnAppControlCompleted() method: 1. Retrieve the number of result elements in the IList collection returned from the Contacts application. 2. Check that the application control ID and the operation ID match those requested when the Application Control was started (APPCONTROL_ CONTACT and OPERATION_PICK respectively). 3. If they match, determine if the request was successful by retrieving the first result item from the IList collection and comparing it with the APPCONTROL_RESULT_SUCCEEDED result. 4. If it matches, determine if the correct return type has been set by retrieving the second result item from the IList collection and comparing it with the string ‘phone’. 5. If it matches, retrieve all the data values by looping through the list until the last element is reached. The following code snippet is an example of the Application Control event handling in the MainForm’s OnAppControlCompleted() method:

13_974018-gr01.indd 23413_974018-gr01.indd 234

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

235

void MainForm::OnAppControlCompleted(const Osp::Base::String& appControlId, const Osp::Base::String& operationId, const Osp::Base::Collection::IList* pResultList) { String* pPickResult = null; int loopCount = 0; int elementCount = pResultList->GetCount(); if(appControlId.Equals(APPCONTROL_CONTACT) && operationId.Equals(OPERATION_PICK)) { pPickResult = (String*)pResultList->GetAt(0); if(pPickResult->Equals(APPCONTROL_RESULT_SUCCEEDED)) { pPickResult = (String*)pResultList->GetAt(1); if(pPickResult->Equals(String(L”phone”))) { // Result is a phone number, // so retrieve numbers from the list for (loopCount=2; loopCountGetAt(loopCount); DisplayContact(pPickResult); } } } } }

In this example a DisplayContact() method can be implemented to display the phone numbers retrieved from the Contacts application. Once the Application Control start method has been called, the application goes to the background and the Contacts UI is displayed. When the user selects required items or exits the Contacts application, the application returns to the foreground.

Hints, Pitfalls, and Related Topics The WEB_SERVICE group privilege must be set in the application’s manifest file in order to use the Browser Application Control. When using the Contacts application control it is not possible to request the return of multiple items of data related to a single contact (e.g. both the phone number and the email address). If this functionality is required, you should instead carry out the following steps: 1. Use the Contacts Application Control for the user to select the required contact, but request the return type from the operation to be the contact ID. 2 Use the Osp::Social::Addressbook class’s GetContactN() method to retrieve all the contact details associated with the contact.

13_974018-gr01.indd 23513_974018-gr01.indd 235

8/31/10 12:39 AM8/31/10 12:39 AM

236

Part II



Recipes

The ADDRESSBOOK group privilege must be set in the application’s manifest file in order to use this Address Book functionality. When selecting multiple items from the Contacts application, they may not be added to the IList collection in the same order as they are presented in the Contacts application. They will be returned in the order of ascending contact ID (i.e. in the order in which the information was saved in the Contacts application).

Related Recipe ■■

Add a Form to a Frame-based App

Recipe 1.5: Create and Use a Timer Problem Description You want to use a timer and react to an event once the timer has expired.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Base::Runtime,

Header files to #include:

FUi.h, FUiControls.h, FBase.h

Required libraries:

FUi, FUiControls, FBase

Required privilege level: Normal

Required privilege groups: None

Timers are provided in the bada platform from the Osp::Base:: Runtime::Timer class. This Timer class is not a periodic timer; it is only a one-shot timer. In order to carry out periodic tasks, the timer must be restarted after it has expired. This recipe details how to use the Timer class with a Progress control on a Form, in order to show an animating progress indication (see Figure R1.4). This recipe assumes the steps detailed in the recipe ‘Add a Form to a Framebased App’ in the second group of recipes (“UI Basics”) have been followed to add a Form to the application’s Frame.

13_974018-gr01.indd 23613_974018-gr01.indd 236

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

237

Figure R1.4 Animating progress indication.

In order to handle the timer expiry, a listener must be used. The ITimerEventListener is the interface class that must be implemented by any class interested in using a timer. The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Base::Runtime::ITimerEventListener { public: MainForm(void); ~MainForm(void); bool Initialize(void); protected: static const int PROGRESS_MIN = 0;

13_974018-gr01.indd 23713_974018-gr01.indd 237

8/31/10 12:39 AM8/31/10 12:39 AM

238

Part II



Recipes

static const int PROGRESS_MAX = 100; Osp::Ui::Controls::Progress* pProgress; Osp::Base::Runtime::Timer* pTimer; public: result OnInitializing(void); result OnTerminating(void); void OnTimerExpired(Osp::Base::Runtime::Timer& timer); };

The UI control Progress bar and the Timer object should be created during initialisation of the MainForm (OnInitializing()): 1. Create a Progress object and initialise it by setting its size, position, and minimum and maximum values. 2. Set the current value of the Progress object to its minimum value. 3. Add the Progress object to the MainForm. 4. Create a Timer object and initialise it with the event listener. 5. Start the timer with a timeout interval of 500 ms. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method to add a Progress bar to a Form and start a timer: // Create progress bar pProgress = new Progress(); // Initialise size and range of progress bar pProgress->Construct(Rectangle(20, 100, 440, 100), PROGRESS_MIN, PROGRESS_MAX); // Set initial value to minimum value pProgress->SetValue(PROGRESS_MIN); // Add progress bar to MainForm AddControl(*pProgress); // Create a timer pTimer = new Timer(); pTimer->Construct(*this); // Start a 500ms timer pTimer->Start(500);

When the timer expires (after 500 ms) the ITimerEventListener:: OnTimerExpired() method is called. In this recipe, when the timer expires the progress bar is redrawn with a new value and the timer is restarted:

13_974018-gr01.indd 23813_974018-gr01.indd 238

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

239

1. Retrieve the current value of the Progress object. 2. If the current value is less than the maximum value, increment the Progress value; otherwise reset to the minimum value. 3. Request that the MainForm is redrawn. 4. Start the timer with a timeout interval of 500 ms. The following code snippet is an example of the implementation of the OnTimerExpired() callback method: void MainForm::OnTimerExpired(Osp::Base::Runtime::Timer& timer) { // Retrieve current value of progress bar int currentValue = pProgress->GetValue(); // Increment the progress bar value or reset to minimum if(currentValue < PROGRESS_MAX) pProgress->SetValue(currentValue+5); else pProgress->SetValue(PROGRESS_MIN); RequestRedraw(); // Restart the 500ms timer timer.Start(500); }

Hints, Pitfalls, and Related Topics When the application is terminated or the timer is no longer required, the programmer is responsible for the deletion of the Timer object.

Related Recipe ■■

Add a Form to a Frame-based App

Recipe 1.6: Parse XML Content Problem Description You want to parse XML content.

The Recipe The following configuration is required for this recipe:

13_974018-gr01.indd 23913_974018-gr01.indd 239

8/31/10 12:39 AM8/31/10 12:39 AM

240

Part II



Recipes

Namespaces used:

Osp::Base, Osp::Xml

Header files to #include: FBase.h, FXml.h

Required libraries: FXml

Required privilege level: Normal

Required privilege groups: None

XML, which stands for EXtensible Markup Language, is used to transport and store data. To parse XML in bada there is a namespace called Osp::Xml, which allows manipulation of XML documents using the libXml2 library, which is explained in detail at xmlsoft.org/index.html. This recipe will provide insight into how you can parse XML data. It can also be treated as an extension to the recipe ‘Get Notes from Facebook using RESTful APIs’ because the sample XML considered here is the XML received from Facebook when you request notes. This recipe details the following steps to parse the XML returned in response to the GetNotes REST API call: 1. Load the XML into DOM and get the docPointer. 2. Parse the XML and get required node values using docPointer. 3. Delete the docPointer. The sample XML which we’ll use for parsing is as follows:

114843655202265 Web2.0 web applications that facilitate interactive information sharing, interoperability, user-centered design,[1] and collaboration on the World Wide Web. 1271379846 1271379846 100000951206325 web applications that facilitate interactive information sharing, interoperability, user-centered design, [1] and collaboration on the World Wide Web.

114843171868980 Harry Potter

13_974018-gr01.indd 24013_974018-gr01.indd 240

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

241

chamber of secrets :) 1271379740 1271379740 100000951206325 chamber of secrets :)

114579818561982 .... Man without aim is letter without address . 1271297013 1271297013 100000951206325 Man without aim is letter without address.

114054615281169 Sayings No dream comes true unless U wake up and work for it !!

1271138928 1271138928 100000951206325 No dream comes true unless U wake up and work for it !!

Below are the detailed steps for parsing the XML received in response to GetNotes: 1. Load the XML buffer into DOM parser. xmlDocPtr docPtr = null; xmlNodePtr curNodePtr = null; docPtr = xmlParseDoc((unsigned char*)pBuf->GetPointer()); if (docPtr == NULL ) { return; }

Here, pBuf is the buffer that contains the response XML from the GetNotes request to Facebook. xmlParseDoc()parses the buffer containing the XML data and returns an XmlDocPtr, which organises the data into a tree to make it easier to parse the individual elements. 2. Get the root element of XML. In this example, the XML root element is “notes_get_response”. curNodePtr = xmlDocGetRootElement(docPtr); if (curNodePtr == NULL) {

13_974018-gr01.indd 24113_974018-gr01.indd 241

8/31/10 12:39 AM8/31/10 12:39 AM

242

Part II



Recipes

xmlFreeDoc(docPtr); return; } if (xmlStrcmp(curNodePtr->name, (const xmlChar*) “notes_get_response”)) { xmlFreeDoc(docPtr); return; }

To get the root element call the xmlDocGetRootElement() function, which takes the XmlDocPtr and returns the current node pointer. To compare the node value use the xmlStrcmp() function. This returns true if the node name matches. Using this function compare the root element pointer with the root node string. 3. Now get all the child nodes of the root node and traverse them one by one to get the ‘note’ node. curNodePtr = curNodePtr->xmlChildrenNode; while (curNodePtr != NULL) { if ((!xmlStrcmp(curNodePtr->name, (const xmlChar*) “note”))) GetNoteData(docPtr, curNodePtr); curNodePtr = curNodePtr->next; }

4. Use the curNodePtr to get the value under the ‘note’ tag. void GetNoteData(xmlDocPtr doc, xmlNodePtr cur) { xmlChar* keyTitle = null; xmlChar* keyContent = null; cur = cur->xmlChildrenNode; while (cur != null) { // Get Title tag data if ((!xmlStrcmp(cur->name, (const xmlChar*) “title”))) keyTitle = xmlNodeListGetString(doc, cur-> xmlChildrenNode, 1); // Get Content Tag Data

13_974018-gr01.indd 24213_974018-gr01.indd 242

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

243

if ((!xmlStrcmp(cur->name, (const xmlChar*) “content”))) { keyContent = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); // Use this key content as per developer need. xmlFree(keyContent); xmlFree(keyTitle); } cur = cur->next; } return; }

In the above code the child node is traversed for the ‘title’ and ‘content’ tags. If a tag is found, use the function xmlNodeListGetString() to get the string contained in that tag. 5. When parsing is done delete the XmlDocPtr xmlFreeDoc(docPtr);

Hints, Pitfalls, and Related Topics Be cautious: after getting the string via xmlNodeListGetString() it should be freed using the xmlFree() function, as memory for this string is allocated internally and it is the developer’s responsibility to take care of this.

Related Recipe ■■

Get Notes from Facebook using RESTful APIs

Recipe 1.7: Get Dates and Times Problem Description You want to use the date and time functionality of the bada platform.

The Recipe The following configuration is required for this recipe:

13_974018-gr01.indd 24313_974018-gr01.indd 243

8/31/10 12:39 AM8/31/10 12:39 AM

244

Part II



Recipes

Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Base, Osp::Locales, Osp::System

Header files to #include:

FUi.h, FUiControls.h, FBase.h, FLocales.h, FSystem.h

Required libraries:

FUi, FUiControls, FBase, FLocales, FSystem

Required privilege level: Normal

Required privilege groups: None.

Time can be represented in two different ways in the bada platform: ■■

The DateTime class represents dates and times with values ranging from 12:00:00 midnight, January 1, 0001 to 11:59:59 P.M., December 31, 9999 in the Gregorian calendar and provides methods for conversion between time formats.

■■

The TimeSpan class represents a period of time measured in ticks. A tick is the smallest unit of time used by the platform or system. In bada, it is a millisecond.

This recipe details three different examples of how a developer could use these two different methods of representing time, and provides some sample code snippets. This recipe assumes the steps detailed in the recipe ‘Add a Form to a Frame-based App’ in the second group of recipes (“UI Basics”) have been followed to add a Form to the application’s Frame. Within the Osp::System namespace is the SystemTime class, which provides methods for getting the current system time and the length of time the device has been powered on. This recipe uses the SystemTime class to get time information for creating DateTime and TimeSpan objects.

Example 1: Date and Time Formatting This example shows how date and time data can be retrieved from a DateTime object and formatted for display in a Label on a Form. In this example the current time is retrieved from the system using the TimeMode::WALL_TIME mode, which represents either the standard time or Daylight Saving Time (DST), depending on the current date. The following code snippet shows an example of converting the current date and time to a String object and displaying it within a label: DateTime currentDateTime; SystemTime::GetCurrentTime(WALL_TIME, currentDateTime); Label* pLabel1 = new Label(); pLabel1->Construct(Rectangle(20, 20, 440, 100),

13_974018-gr01.indd 24413_974018-gr01.indd 244

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

245

currentDateTime.ToString()); AddControl(*pLabel1);

The ToString() method presents the date and time in the format mm/ dd/yyyy hh:mm:ss. In addition to this default format, the following methods can be used to format the date and time: ■■

Construct a string by manually retrieving specific elements of the DateTime object using the GetSecond(), GetMinute(), GetHour(), GetDay(), GetMonth(), and GetYear() methods.

■■

Format a string using an instance of the Osp::Locales::DateTime Formatter class, configured for the system locale and the style of formatting required.

This example describes how to create and use DateTimeFormatter objects to format the date and time for the system locale in three different ways. The following steps describe how to do that: 1. Create and initialise an instance of the LocaleManager. 2. Get the system locale from the device. 3. Create three DateTimeFormatter objects for the system locale, each demonstrating a different way of formatting the date and time. 4. Create labels and display the date/time, date and time strings. The following code snippet shows examples of using the DateTimeFormatter class: String formattedDateTime; String formattedDate; String formattedTime; LocaleManager localeManager; localeManager.Construct(); Locale locale = localeManager.GetSystemLocale(); DateTimeFormatter* pDateTimeFormatter = DateTimeFormatter::CreateDateTimeFormatterN(locale, DATE_TIME_STYLE_DEFAULT, DATE_TIME_STYLE_DEFAULT); pDateTimeFormatter->Format(currentDateTime, formattedDateTime); DateTimeFormatter* pDateFormatter = DateTimeFormatter::CreateDateFormatterN(locale, DATE_TIME_STYLE_FULL); pDateFormatter->Format(currentDateTime, formattedDate); DateTimeFormatter* pTimeFormatter = DateTimeFormatter::CreateTimeFormatterN(locale, DATE_TIME_STYLE_SHORT); pTimeFormatter->Format(currentDateTime, formattedTime); Label* pLabel2 = new Label(); pLabel2->Construct(Rectangle(20, 100, 440, 100),

13_974018-gr01.indd 24513_974018-gr01.indd 245

8/31/10 12:39 AM8/31/10 12:39 AM

246

Part II



Recipes

formattedDateTime); AddControl(*pLabel2); Label* pLabel3 = new Label(); pLabel3->Construct(Rectangle(20, 180, 440, 100), formattedDate); AddControl(*pLabel3); Label* pLabel4 = new Label(); pLabel4->Construct(Rectangle(20, 260, 440, 100), formattedTime); AddControl(*pLabel4); delete pDateTimeFormatter; delete pDateFormatter; delete pTimeFormatter;

Figure R1.5 shows the representation of a date and time in the four different methods shown in this example. The formatted time and date examples are based on system locale with a LanguageCode of LANGUAGE_ENG and a CountryCode of COUNTRY_GB.

Figure R1.5 Date and time formatting.

13_974018-gr01.indd 24613_974018-gr01.indd 246

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

247

Example 2: Using a TimeSpan This example shows how time can be represented using a TimeSpan object, and how time information can be retrieved from the TimeSpan object and displayed in a Label on a Form. In this example the time that has elapsed since the device was powered on is retrieved from the system using the SystemTime::GetUptime() method and stored in a TimeSpan object. The following code snippet shows an example of retrieving time information from a TimeSpan object and displaying it within labels (see Figure R1.6): TimeSpan timeInterval = 0; SystemTime::GetUptime(timeInterval); Label* pLabel1 = new Label(); pLabel1->Construct(Rectangle(20, 20, 440, 100), L”Time since power on”); AddControl(*pLabel1); Label* pLabel2 = new Label(); String label1(L”Hours: “); label1.Append(timeInterval.GetHours()); pLabel2->Construct(Rectangle(20, 100, 440, 100), label1); AddControl(*pLabel2); Label* pLabel3 = new Label(); String label2(L”Minutes: “); label2.Append(timeInterval.GetMinutes()); pLabel3->Construct(Rectangle(20, 180, 440, 100), label2); AddControl(*pLabel3); Label* pLabel4 = new Label(); String label3(L”Seconds: “); label3.Append(timeInterval.GetSeconds()); pLabel4->Construct(Rectangle(20, 260, 440, 100), label3); AddControl(*pLabel4);

Example 3: Calculating a Time Difference This example shows how to calculate the difference in time between two DateTime objects, and display the resulting time difference in Labels on a Form. In this example a difference in time is calculated between the current date and time retrieved from the system, and an appointment set for a date and time in the future. Although two DateTime objects can be compared to determine if one occurs in time before the other, a time difference cannot be calculated directly using these objects. The TimeSpan object has to be used to calculate time differences, using its overloaded operator methods.

13_974018-gr01.indd 24713_974018-gr01.indd 247

8/31/10 12:39 AM8/31/10 12:39 AM

248

Part II



Recipes

Figure R1.6 Using a TimeSpan.

The DateTime class provides a method GetTime(), which gets the number of milliseconds (in TimeSpan) since the minimum date. This value from each of the DateTime objects can then be used with the TimeSpan’s subtraction operator to calculate the time difference between the two objects (see Figure R1.7). The following code snippet shows an example of calculating a time difference and displaying it within labels: DateTime currentDateTime; SystemTime::GetCurrentTime(WALL_TIME, currentDateTime); DateTime appointment; appointment.SetValue(2010, 07, 01, 12, 30, 0); // Calculate time until appointment TimeSpan timeDiff = (appointment.GetTime())– (currentDateTime.GetTime()); Label* pLabel1 = new Label(); pLabel1->Construct(Rectangle(20, 20, 440, 100), L”Time until:”);

13_974018-gr01.indd 24813_974018-gr01.indd 248

8/31/10 12:39 AM8/31/10 12:39 AM

Group 1



Fundamentals

249

AddControl(*pLabel1); Label* pLabel2 = new Label(); pLabel2->Construct(Rectangle(20, 100, 440, 100), appointment.ToString()); AddControl(*pLabel2); Label* pLabel3 = new Label(); String string1(L”Days: “); string1.Append(timeDiff.GetDays()); pLabel3->Construct(Rectangle(20, 180, 440, 100), string1); AddControl(*pLabel3); Label* pLabel4 = new Label(); String string2(L”Hours: “); string2.Append(timeDiff.GetHours()); pLabel4->Construct(Rectangle(20, 260, 440, 100), string2); AddControl(*pLabel4); Label* pLabel5 = new Label(); String string3(L”Minutes: “); string3.Append(timeDiff.GetMinutes()); pLabel5->Construct(Rectangle(20, 340, 440, 100), string3); AddControl(*pLabel5);

Figure R1.7 Calculating a time difference.

13_974018-gr01.indd 24913_974018-gr01.indd 249

8/31/10 12:39 AM8/31/10 12:39 AM

250

Part II



Recipes

Hints, Pitfalls, and Related Topics In Example 1 of this recipe, the CreateDateTimeFormatterN(), CreateDateFormatterN() and CreateTimeFormatterN() methods are used to create date/time formatters. These methods have an ‘N’ postfix, so to prevent memory leaks the caller must delete the returned instance after the caller is finished with the instance.

Related Recipe ■■

Add a Form to a Frame-based App

13_974018-gr01.indd 25013_974018-gr01.indd 250

8/31/10 12:39 AM8/31/10 12:39 AM

GROUP

2 UI Basics

Recipe 2.1: Add a Form to a Frame-based App Problem Description You want to add a Form to a Frame-based application.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls

Header files to #include: FUi.h, FUiControls.h

Required libraries: FUi, FUiControls

Required privilege level: Normal

Required privilege groups: None

251

14_974018-gr02.indd 25114_974018-gr02.indd 251

8/31/10 12:39 AM8/31/10 12:39 AM

252

Part II



Recipes

The top-level window of an application is called a Frame. A Frame is the ultimate parent object of all controls that an application possesses. A Frame can contain one or many Forms. A Form is the highest level container. It is a full-screen container that can contain user-created controls and system UI components to help provide functionality for an application (see Figure R2.1). The Frame and Form classes are provided by the Osp::Ui::Controls namespace. This recipe shows two different methods that can be used to create a Form and add it to the application’s Frame. Each method details the steps required to add a Form to a Frame and provides some sample code snippets.

Figure R2.1 A blank Form.

14_974018-gr02.indd 25214_974018-gr02.indd 252

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

253

Method 1: Adding a Form to the Frame using the Osp::Ui::Controls::Form class This simple recipe creates a new Form object using the system’s Osp::Ui::Controls::Form class and adds it to the application’s Frame. The Form should be created and added to the application’s Frame during the application initialisation phase (OnAppInitializing()): 1. Create an instance of a Form and initialise it with the style parameters required to display a normal Form containing a title bar and an indicator bar. 2. Set the name of the Form and the text to be displayed in the Form’s Title area. 3. Add the Form to the application Frame. 4. Set the Form as the current form of the Frame. 5. Draw and Show the Form. The following code snippet is an example of code that would be added to the Application’s OnAppInitializing() method: // Create a Form Form* pForm = new Form(); pForm->Construct (FORM_STYLE_NORMAL|FORM_STYLE_TITLE|FORM_STYLE_INDICATOR); pForm->SetName(L”MainForm”); pForm->SetTitleText(L”MainForm”); // Get a frame pointer and add the Form to the Frame Frame* pFrame = GetAppFrame()->GetFrame(); pFrame->AddControl(*pForm); // Set the current Form pFrame->SetCurrentForm(*pForm); // Call Draw & Show to display Form pForm->Draw(); pForm->Show();

Method 2: Adding a Form to the Frame Using a User-defined Form Class This recipe creates the same results as Method 1, but does it using a newly created Form class. This method may be more suitable for applications that contain multiple forms, as the creation of the Form’s controls and its logic is implemented by the Form rather than in the application code. In this recipe the MainForm class is inherited from the base class Osp::Ui::Controls::Form.

14_974018-gr02.indd 25314_974018-gr02.indd 253

8/31/10 12:39 AM8/31/10 12:39 AM

254

Part II



Recipes

The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form { // Construction public: MainForm(void); ~MainForm(void); bool Initialize(void); // Call-back functions public: result OnInitializing(void); result OnTerminating(void); };

The Form should be created and added to the application’s Frame during the application initialisation phase (OnAppInitializing()): 1. Create an instance of the MainForm type and initialise it. 2. Add the Form to the Application Frame. 3. Set the Form as the current form of the Frame. 4. Draw and Show the Form. The following code snippet is an example of code that would be added to the application’s OnAppInitializing() method: // Create a form MainForm* pForm = new MainForm(); pForm->Initialize(); // Add the form to the frame Frame* pFrame = GetAppFrame()->GetFrame(); pFrame->AddControl(*pForm); // Set the current form pFrame->SetCurrentForm(*pForm); // Draw and Show the form pForm->Draw(); pForm->Show();

The Form’s style parameters and title text should be defined during initialisation of the MainForm (Initialize()): 1. Call the base class constructor with the style parameters required to display a normal Form containing a title bar and an indicator bar. 2. Set the text to be displayed in the Form’s Title area. The following code snippet is an example of code that would be implemented in the MainForm’s Initialize() method: Form::Construct(FORM_STYLE_NORMAL|FORM_STYLE_TITLE|FORM_STYLE_INDICATOR); SetTitleText(L”Main Form”);

14_974018-gr02.indd 25414_974018-gr02.indd 254

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

255

Hints, Pitfalls, and Related Topics All containers, including the Form container, must be created on the heap memory. However, once the Form has been attached to the Frame, the application framework is responsible for its deletion when the application terminates. If the developer deletes the controls, it will cause a problem.

Recipe 2.2: Add Soft Keys to a Form and Get Actions Problem Description You want to add soft keys to a Form.

The Recipe The following configuration is required for this recipe: Namespaces used: Osp::Ui, Osp::Ui::Controls, additionally Osp::Media, Osp::Graphics if the soft key displays an image

Header files to #include: FUi.h, FUiControls.h, additionally FMedia.h, FGraphics.h if the soft key displays an image

Required libraries: FUi, FUiControls, additionally FMedia, FGraphics if the soft key displays an image

Required privilege level: Normal

Required privilege groups: IMAGE

A Form is composed of an indicator area, tab and title areas, a client area, and a soft key area. The style of the Form determines whether an indicator, a tab, a title, an options key, or the soft keys are shown. A soft key can either display text or a bitmap. The soft key generates an action event when it is pressed. If an application wants to handle the action event generated by the soft key, it should implement an action event listener and register it to the soft key using the AddSoftkeyActionListener() method. This recipe details the steps to create the left and right soft keys for a Form, and describes the code that needs to be implemented for the Form to receive and handle the soft key action events (see Figure R2.2). In this recipe the left soft key contains an icon and the right soft key contains text.

14_974018-gr02.indd 25514_974018-gr02.indd 255

8/31/10 12:39 AM8/31/10 12:39 AM

256

Part II



Recipes

Figure R2.2 A Form with soft keys.

This recipe assumes the steps in Method 2 of the ‘Add a Form to a Frame-based App’ recipe have been followed to add a Form to the application’s Frame. It also assumes the steps described in the recipe ‘Add a Simple Button Control to a Form’ have been followed to implement the Osp::Ui::IActionEventListener interface class. To display the soft key area with a left and right soft key, the Form constructor needs to be called with the FORM_STYLE_SOFTKEY_0 (related to left soft key) and FORM_STYLE_SOFTKEY_1 (related to right soft key) style parameters set. The following code snippet is an example of code that would be implemented in the MainForm’s Initialize() method: Form::Construct(FORM_STYLE_NORMAL|FORM_STYLE_TITLE| FORM_STYLE_INDICATOR|FORM_STYLE_SOFTKEY_0|FORM_STYLE_SOFTKEY_1);

14_974018-gr02.indd 25614_974018-gr02.indd 256

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

257

Action IDs need to be added to the MainForm for each of the soft keys, so that the soft key action events can be identified when handling events in the OnActionPerformed() event handler: static const int ID_SOFTKEY_LEFT = 101; static const int ID_SOFTKEY_RIGHT = 102;

In the OnActionPerformed() event handler the soft key action events are identified by the action ID, which is registered when the soft key is created, and the relevant processing can be implemented. The following code snippet is an example of the MainForm’s OnActionPerformed() method: void MainForm::OnActionPerformed(const Osp::Ui::Control& source, int actionId) { switch(actionId) { case ID_SOFTKEY_LEFT: { // Add left softkey handling code here } break; case ID_SOFTKEY_RIGHT: { // Add right softkey handling code here } break; default: break; } }

The soft keys should be created during initialisation of the MainForm(OnInitializing()): 1. Create an Image object and initialise. 2. Decode the image file into the decoded bitmap container, passing the local file path of the image file and colour format parameters. 3. Set the left soft key to display an icon and assign the ‘Normal’ and ‘Pressed’ images. 4. Set the right soft key to display a text string. 5. Assign unique action IDs for both soft keys. 6. Register IActionEventListener implemented by the MainForm class with the soft keys. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method to create the left and right soft keys:

14_974018-gr02.indd 25714_974018-gr02.indd 257

8/31/10 12:39 AM8/31/10 12:39 AM

258

Part II



Recipes

// Create left softkey (SOFTKEY_0) // Create a Bitmap and decode image Bitmap* pBitmap = null; Image* pImage = new Image(); pImage->Construct(); pBitmap = pImage->DecodeN(L”/Res/bada.png”, BITMAP_PIXEL_FORMAT_ARGB8888); SetSoftkeyIcon(SOFTKEY_0, *pBitmap, pBitmap); delete pImage; delete pBitmap; // Create right softkey (SOFTKEY_1) SetSoftkeyText(SOFTKEY_1, “Right”); // Assign action IDs for both the softkeys SetSoftkeyActionId(SOFTKEY_0, ID_SOFTKEY_LEFT); SetSoftkeyActionId(SOFTKEY_1, ID_SOFTKEY_RIGHT); // Register event listener AddSoftkeyActionListener(SOFTKEY_0, *this); AddSoftkeyActionListener(SOFTKEY_1, *this);

Hints, Pitfalls, and Related Topics If both an icon and text are set for the same soft key at the same time, the text takes precedence over the icon. A soft key can be enabled or disabled using the SetSoftkeyEnabled() method, with the enable parameter set to either true or false.

Related Recipes ■■

Add a Form to a Frame-based App

■■

Add a Simple Button Control to a Form

Recipe 2.3: Add an Options Menu to a Form and Get User Selections Problem Description You want to add an options menu to a Form and get the user’s selections.

The Recipe The following configuration is required for this recipe:

14_974018-gr02.indd 25814_974018-gr02.indd 258

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

259

Namespaces used:

Osp::Ui, Osp::Ui::Controls

Header files to #include: FUi.h, FUiControls.h

Required libraries: FUi, FUiControls

Required privilege level: Normal

Required privilege groups: None

A Form is composed of an indicator area, tab and title areas, a client area, and a soft key area. The style of a Form determines whether an indicator, a tab, a title, an options key, or the soft keys are shown. An Option menu is a menu control activated from an Option key located in the command area of the display. It can be used to present multiple options to the user, and is displayed over the content of the form. It is a hierarchical menu, which can contain up to two levels, consisting of main items and subitems. The menu items can only be presented as text strings; bitmaps cannot be displayed. An Option menu control does not get added to a container, so it must be explicitly deleted when it is no longer required. The Application Framework will not delete the Option menu when the application terminates. This recipe details the steps to create the Option key and add a two-level Option menu to a Form, and describes the code that needs to be implemented for the Form to receive and handle the Option key and Option menu action events (see Figure R2.3). This recipe assumes the steps detailed in Method 2 of the recipe ‘Add a Form to a Frame-based App’ were followed to add a Form to the application’s Frame. It also assumes the steps described in the recipe ‘Add a Simple Button Control to a Form’ have been followed to implement the Osp::Ui::IActionEventListener interface class. To display the Option key in the soft key area of the display, the Form constructor needs to be called with the FORM_STYLE_OPTIONKEY style parameter set. The following code snippet is an example of code that would be implemented in the MainForm’s Initialize() method: Form::Construct(FORM_STYLE_NORMAL|FORM_STYLE_TITLE| FORM_STYLE_INDICATOR|FORM_STYLE_OPTIONKEY);

14_974018-gr02.indd 25914_974018-gr02.indd 259

8/31/10 12:39 AM8/31/10 12:39 AM

260

Part II



Recipes

Figure R2.3 Option menu with two levels.

14_974018-gr02.indd 26014_974018-gr02.indd 260

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

261

An action ID needs to be added to the MainForm for the Option key, so that its action event can be identified when handling events in the OnActionPerformed() event handler: static const int ID_OPTIONKEY = 100;

Similarly, each Option menu main item and sub-item requires an action ID to identify it in the OnActionPerformed() event handler: static static static static static

const const const const const

int int int int int

ID_OPTION1 ID_OPTION2 ID_OPTION3 ID_OPTIONA ID_OPTIONB

= = = = =

103; 104; 105; 106; 107;

In the OnActionPerformed() event handler the Option key and Option menu item action events are identified by the action ID, which are registered when the Option key and Option menu are created, and the relevant processing can be implemented. When the event with the action ID associated with the Option key is received, the Option menu is activated and displayed using the SetShowState() and Show() methods. The following code snippet is an example of the MainForm’s OnActionPerformed() method: void MainForm::OnActionPerformed(const Osp::Ui::Control& source, int actionId) { switch(actionId) { case ID_OPTIONKEY: { // Display the OptionMenu pOptionMenu->SetShowState(true); pOptionMenu->Show(); } break; case ID_OPTION1: // Because this item has sub items attached, you // don’t need to do any additional event handling here break; case ID_OPTION2: // Add event handling code here break; case ID_OPTION3: // Add event handling code here break; case ID_OPTIONA: // Add event handling code here

14_974018-gr02.indd 26114_974018-gr02.indd 261

8/31/10 12:39 AM8/31/10 12:39 AM

262

Part II



Recipes break;

case ID_OPTIONB: // Add event handling code here break; default: break; } }

The Option key and Option menu should be created during initialisation of the MainForm (OnInitializing()): 1. Set the action ID of the Form’s Option key control. 2. Register the IActionEventListener implemented by the MainForm class. 3. Create an Option menu and initialise. 4. Add the main items to the Option menu, specifying the text string to be displayed and the item’s action IDs. 5. Add any sub-items to the Option menu, specifying the index of the main item to attach the sub-item to, the text string to be displayed, and the item’s action IDs. 6. Register the IActionEventListener implemented by the MainForm class, with the Option menu object. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method to create the Option key and Option menu: // Create an OptionKey SetOptionkeyActionId(ID_OPTIONKEY); AddOptionkeyActionListener(*this); // Create an OptionMenu pOptionMenu = new OptionMenu(); pOptionMenu->Construct(); pOptionMenu->AddItem(“Option1”,ID_OPTION1); pOptionMenu->AddItem(“Option2”,ID_OPTION2); pOptionMenu->AddItem(“Option3”,ID_OPTION3); // Add a sub items to the first item in the options menu @ index 0 pOptionMenu->AddSubItem(0, “Sub item1”, ID_OPTIONA); pOptionMenu->AddSubItem(0, “Sub item2”, ID_OPTIONB); // Register an event listener pOptionMenu->AddActionEventListener(*this);

14_974018-gr02.indd 26214_974018-gr02.indd 262

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

263

Hints, Pitfalls, and Related Topics The example shown in this recipe has a two-level fixed structure for the Option menu’s menu hierarchy. It is also possible to dynamically add, change, and delete items during runtime. If you want to change the content of the Option menu, there are several methods that can be used to add, change, and delete both main items and sub-items. These methods are: AddItem(), AddSubItem(), SetItemAt(), SetSubItemAt(), RemoveItemAt(), and RemoveSubItemAt(). If you need to determine if there are any sub-items associated with a main item, and how many there are, you can use the GetSubItemCount() method. In the example, the first main item in the menu (ID_OPTION1) has subitems associated with it. In this scenario no code needs to be implemented in the OnActionPerformed() event handler for this action ID, as the display of the sub-items is automatically performed by the Option menu object. But, if there is code for this action ID in the OnActionPerformed() event handler, it will get executed after the sub-items are displayed. When a sub-item, or main item with no associated sub-item is selected by the user, the Option menu object will generate the appropriate event for the form to handle and the menu will be removed from the display. Because of the way in which the Option menu is removed from the display when it has no sub-items to display, dynamically creating any sub-items for a main item on selection of that main item is not recommended. If the item’s text string is too long, it will be truncated when displayed: ■■

A main item will be truncated at two lines of text (in English) and ‘…’ will be added to the end of the string.

■■

A sub-item will be truncated at one line of text (in English) and ‘…’ will be added to the end of the string.

Related Recipes ■■

Add a Form to a Frame-based App

■■

Add a Simple Button Control to a Form

Recipe 2.4: Add a Simple Button Control to a Form Problem Description You want to add a Button control to a Form.

14_974018-gr02.indd 26314_974018-gr02.indd 263

8/31/10 12:39 AM8/31/10 12:39 AM

264

Part II



Recipes

The Recipe The following configuration is required for this recipe: Namespaces used: Osp::Ui, Osp::Ui::Controls, additionally Osp::Media, Osp::Graphics for Button control displaying an image

Header files to #include: FUi.h, FUiControls.h, FMedia.h, additionally FGraphics.h for Button control displaying an image

Required libraries: FUi, FUiControls, additionally FMedia, FGraphics for Button control displaying an image

Required privilege level: Normal

Required privilege groups: IMAGE

A Button is a control provided by the Osp::Ui::Controls namespace. A Button can vary in size and can contain either text or an image. In order to handle the Button control’s events, a listener must be used. The IActionEventListener is the interface class that should be implemented by any class interested in receiving a Button’s action events. This recipe details the steps to add a Button control to a Form and describes the code that needs to be implemented for the Form to receive and handle a Button press event. Examples are provided for a Button containing text and a Button containing an image. This recipe assumes the steps detailed in Method 2 of the ‘Add a Form to a Frame-based App’ recipe have been followed to add a Form to the Application’s Frame. As shown in the ‘Add a Form to a Frame-based App’ recipe the MainForm class is inherited from the Form base class. In order for this Form to handle events from a control such as a Button, an event listener interface has to be implemented. So in this recipe the MainForm class must implement the Osp::Ui::IActionEventListener interface class. Because the IActionEventListener is shared by many controls, each control that uses this listener must be assigned a unique action ID. The action ID is used to identify the relevant control when handling events in the OnActionPerformed() event handler. The following code snippet highlights the changes made to the MainForm class in order to handle a Button control’s events:

14_974018-gr02.indd 26414_974018-gr02.indd 264

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

265

class MainForm : public Osp::Ui::Controls::Form, public Osp::Ui::IActionEventListener { // Construction public: MainForm(void); ~MainForm(void); bool Initialize(void); // Implementation protected: static const int ID_BUTTON_OK = 101; public: result OnInitializing(void); result OnTerminating(void); void OnActionPerformed(const Osp::Ui::Control& source, int actionId); };

In order to handle the Button control action events, the IActionEventListener class’s pure virtual function OnActionPerformed() needs to be implemented in the MainForm class. In this event handler the control’s event is identified by its action ID, which is registered when the control was created, and the relevant processing can be implemented. The following code snippet is an example of the MainForm’s OnActionPerformed() method: void MainForm::OnActionPerformed(const Osp::Ui::Control& source, int actionId) { switch(actionId) { case ID_BUTTON_OK: { // Add button handling functionality here } break; default: break; } }

Example 1: Creating a Button Containing Text In this example a button control with a text label is created on the Form (see Figure R2.4).

14_974018-gr02.indd 26514_974018-gr02.indd 265

8/31/10 12:39 AM8/31/10 12:39 AM

266

Part II



Recipes

Figure R2.4 Button with text.

The Button control should be added to the Form during initialisation of the MainForm (OnInitializing()): 1. Create a Button object and initialise it by setting its size and position using a Rectangle instance. 2. Set the text string to be displayed on the Button control. 3. Assign a unique action ID for the Button control. 4. Register the IActionEventListener implemented by the MainForm class with the Button control. 5. Add the Button control to the form. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method, in order to add a Button control to the form: // Create Button Button* pButton = new Button(); // Set button size and position

14_974018-gr02.indd 26614_974018-gr02.indd 266

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

267

pButton->Construct(Rectangle(10, 100, 460, 60)); // Set button text pButton->SetText(L”Ok”); // Set button Action identifier pButton->SetActionId(ID_BUTTON_OK); // Register an event listener pButton->AddActionEventListener(*this); // Add the button control to the Main Form AddControl(*pButton);

Example 2: Creating a Button Containing an Image In this example a Button control with an image is created on the Form (see Figure R2.5). The Button control should be added to the Form during initialisation of the MainForm (OnInitializing()):

Figure R2.5 Form with image.

14_974018-gr02.indd 26714_974018-gr02.indd 267

8/31/10 12:39 AM8/31/10 12:39 AM

268

Part II



Recipes

1. Create a Button object and initialise it by setting its size and position using a Rectangle instance. 2. Create an Image object and initialise it. 3. Decode the image file into the decoded bitmap container, passing the local file path of the image file and colour format parameters. 4. Set the ‘Normal’ and ‘Pressed’ button images and position them at a point relative to the top left corner of the Button Rectangle. 5. Assign a unique action ID for the Button control. 6. Register the IActionEventListener implemented by the MainForm class with the Button control. 7. Add the Button control to the form. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method to add a Button control to the Form: // Create Button Button* pButton = new Button(); // Set button size and position pButton->Construct(Rectangle(140, 100, 200, 200)); // Create a Bitmap and decode image Bitmap* pBitmap = new Bitmap(); Image* pImage = new Image(); pImage->Construct(); pBitmap = pImage->DecodeN(L”/Res/bada.png”, BITMAP_PIXEL_FORMAT_ARGB8888); delete pImage; // Set button images pButton->SetNormalBitmap(Point(0, 0), *pBitmap); pButton->SetPressedBitmap(Point(0, 0), *pBitmap); delete pBitmap; // Set button Action identifier pButton->SetActionId(ID_BUTTON_OK); // Register an event listener pButton->AddActionEventListener(*this); // Add the button control to the Main Form AddControl(*pButton);

Hints, Pitfalls, and Related Topics All controls must be created on the heap memory. However, once a control has been added to the container, and the container attached to the Frame, the Application Framework is responsible for its deletion when the application terminates.

14_974018-gr02.indd 26814_974018-gr02.indd 268

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

269

If a control is not added to a container, the programmer must explicitly delete it on termination of the application. Controls, such as Buttons, can be added and removed during runtime, depending on UI context, to preserve memory. The methods AddControl() and RemoveControl() are provided to add and remove controls from a container.

Related Recipe ■■

Add a Form to a Frame-based App

Recipe 2.5: Pop Up a Message Box with Dismiss Problem Description You want to prompt the user for confirmation of an action, outside the fixed view or menu structure of your application.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Control

Header files to #include: FUi.h, FUiControls.h

Required libraries: FUi, FUiControls

Required privilege level: Normal

Required privilege groups: None

This recipe shows how to launch and display an acknowledgement Message Box that displays a message to the user and an OK button, and waits for the user to confirm by pressing OK. A Message Box can also have no button, in which case the message is simply displayed, or two or three buttons. Buttons have fixed text, set by the MSGBOX_STYLE parameter. Handling the user response is easy – it is set in the argument passed to the launch method.

14_974018-gr02.indd 26914_974018-gr02.indd 269

8/31/10 12:39 AM8/31/10 12:39 AM

270

Part II



Recipes

Unlike other Control-derived classes that are used as building blocks to populate the Forms from which an application’s UI is constructed, the MessageBox class is a so-called modal control; a MessageBox is instantiated, initialised, and displayed outside the normal event flow of the currently displayed Form and any Controls the Form owns. Unlike other controls, MessageBox derives from the Window class, via the derivation chain: Object -> Control -> Container -> Window -> [ MessageBox | Popup ]

A MessageBox therefore is drawn directly into the window area it defines, on top of the current Form. Conceptually, therefore, a MessageBox defines an additional mode of interaction outside the fixed infrastructure of the application’s Forms; a MessageBox is direct and immediate. To use a MessageBox, #include the following header files and be sure to use the fully qualified names for the objects. #include #include #include

The code to instantiate and launch a MessageBox is almost trivial: /* * Giving a title and message for the popup windows showing to the user */ void Utils::showMessage(const String &title, const String &message) { MessageBox messageBox; messageBox.Construct(title, message, MSGBOX_STYLE_OK, 3000); // Call ShowAndWait - draw, show itself and process events int modalResult = 0; messageBox.ShowAndWait(modalResult); switch(modalResult) { case MSGBOX_RESULT_OK: // TODO break; default: break; } }

The MessageBox constructor is used to set values for the title, message, style, and timeout period of the instance; and then the ShowAndWait(result) method is called, which instantiates and displays the Message Box, sets the user response in the result argument, and manages destruction and cleanup.

Hints, Pitfalls, and Related Topics Forms and menus create the fixed architecture of an interactive application. But a typical application also requires the more dynamic kinds of interaction

14_974018-gr02.indd 27014_974018-gr02.indd 270

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

271

provided by prompts, alerts, messages and notifications based on the specific context of the moment. The MessageBox class is almost trivial to use, but is rather limited in the options it provides; in particular, only a small selection of preset buttons is provided: MSGBOX_STYLE_NONE

Contains no buttons

MSGBOX_STYLE_OK

Contains one button: OK

MSGBOX_STYLE_CANCEL

Contains one button: CANCEL

MSGBOX_STYLE_OKCANCEL

Contains two buttons: OK and CANCEL

MSGBOX_STYLE_YESNO

Contains two buttons: YES and NO

MSGBOX_STYLE_YESNOCANCEL

Contains three buttons: YES, NO, and CANCEL

MSGBOX_STYLE_ABORTRETRYIGNORE

Contains three buttons: ABORT, RETRY, and IGNORE

MSGBOX_STYLE_CANCELTRYCONTINUE

Contains three buttons: CANCEL, TRY, and CONTINUE

MSGBOX_STYLE_RETRYCANCEL

Contains two buttons: RETRY and CANCEL

Where more flexibility is required, the Popup class enables a similar style of dynamic interaction using pop-up dialogs, and is fully customisable – but also requires explicit construction, initialisation, display, and cleanup. Pop-ups can also contain buttons, labels, and other simple controls to enable capturing a richer variety of user choices or selections. On the return of the ShowAndWait() method (which is a synchronous function), the result argument contains the result of the call. The following results are returned by a MessageBox: MSGBOX_RESULT_CLOSE

The message box was closed

MSGBOX_RESULT_OK

The OK button was selected

MSGBOX_RESULT_CANCEL

The CANCEL button was selected

MSGBOX_RESULT_YES

The YES button was selected

MSGBOX_RESULT_NO

The No button was selected

MSGBOX_RESULT_ABORT

The ABORT button was selected

MSGBOX_RESULT_TRY

The TRY button was selected

MSGBOX_RESULT_RETRY

The RETRY button was selected

MSGBOX_RESULT_IGNORE

The IGNORE button was selected

MSGBOX_RESULT_CONTINUE

The CONTINUE button was selected

14_974018-gr02.indd 27114_974018-gr02.indd 271

8/31/10 12:39 AM8/31/10 12:39 AM

272

Part II



Recipes

The MessageBox class is easy to use, but it has one important limitation. ■■

The call to launch a MessageBox is synchronous and blocking; the MessageBox is not dismissed until the user response is received or until it times out.

For this reason a MessageBox should never be launched from a listener callback method, because it will block the callback’s return and disrupt the asynchronous event flow. Therefore, inside a callback method, always use a popup instead.

Recipe 2.6: Pop Up a Keypad and Get Input from It Problem Description You want to pop up a Keypad and get input from it.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Base

Header files to #include:

FUi.h, FUiControls.h, FBase.h

Required libraries:

FUi, FUiControls, FBase

Required privilege level: Normal

Required privilege groups: None

A Keypad control is a UI control that provides a means for the user to input alphanumeric text. A Keypad control can either be used within an application as a standalone keypad or as part of an Edit Field or Edit Area input control. For a standalone keypad, only a full-screen keypad is available. For a keypad automatically created by the system for an Edit Field or Edit Area control, both full-screen and overlay keypads are supported This recipe shows two different methods for making use of the Keypad control. Each method details the steps required to create and use the Keypad, and provides some sample code snippets.

14_974018-gr02.indd 27214_974018-gr02.indd 272

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

273

Both methods in this recipe assume that the steps detailed in Method 2 of the ‘Add a Form to a Frame-based App’ recipe have been followed to add a Form to the application’s Frame.

Method 1: Using the Standalone Keypad Control This recipe creates a standalone keypad using the Osp::Ui:Controls::Keypad class and displays it in the application Frame (see Figure R2.6). Any text events generated by the keypad can be processed by the application by implementing the Osp::Ui::ITextEventListener interface class.

Figure R2.6 Standalone keypad.

When a standalone keypad is used it is not added to any container, so it must be explicitly deleted when it is no longer required. The Application Framework will not delete the keypad when the application terminates.

14_974018-gr02.indd 27314_974018-gr02.indd 273

8/31/10 12:39 AM8/31/10 12:39 AM

274

Part II



Recipes

The ITextEventListener interface receives text events. In order for the application to retrieve any text that has been entered by the user using the Keypad control, this interface must be implemented. The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Ui::ITextEventListener { // Construction public: MainForm(void); ~MainForm(void); bool Initialize(void); private: Osp::Ui::Controls::Keypad *pKeypad; public: result OnInitializing(void); result OnTerminating(void); void ShowKeypad(bool show); void OnTextValueChanged(const Osp::Ui::Control& source); void OnTextValueChangeCanceled(const Osp::Ui::Control& source); };

The Keypad control can be created during initialisation of the MainForm (OnInitializing()): 1. Create a Keypad object. 2. Set the required style and input mode category parameters, for example, normal style with alphabetic input mode. 3. Register the ITextEventListener implemented by the MainForm class to the Keypad control. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method to create a Keypad control: // Create the Keypad member object pKeypad = new Keypad(); // Initialize with specified style and category pKeypad->Construct(KEYPAD_STYLE_NORMAL, KEYPAD_MODE_ALPHA); // Register an event listener pKeypad->AddTextEventListener(*this);

As the Keypad control is not explicitly added to the Form container, it will not automatically be displayed. The keypad’s Show() method must be called

14_974018-gr02.indd 27414_974018-gr02.indd 274

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

275

to display the keypad. For example, the display of the keypad could be triggered by a press of a soft key invoking the ShowKeypad() method: void MainForm::ShowKeypad(bool show) { if(true == show) { pKeypad->Show(); } else // call the Form’s Show() method { Show(); } }

The standalone keypad displays ‘Done’ and ‘Cancel’ command buttons in the soft key area. Although they look like soft keys, they are not soft keys and do not behave in the same way as soft keys. When the ‘Done’ button is tapped, an ITextEventListener action event is triggered and the MainForm’s OnTextValueChanged() method is invoked. When the ‘Cancel’ button is tapped, a ITextEventListener action event is triggered and the MainForm’s OnTextValueChangedCanceled() method is invoked. These methods can be used by an application to retrieve the data that has been entered by the user using the Keypad control. For example, the OnText ValueChanged() method can be implemented to retrieve the text string from the Keypad object: void MainForm::OnTextValueChanged(const Osp::Ui::Control& source) { String string(pKeypad->GetText()); // Retrieve text from Keypad //object }

Method 2: Using an Overlay-style Keypad within an Edit Field This recipe creates an Edit field, which displays one line of editable text to the user. It is implemented in the overlay style, so that when the user taps on the Edit control, an overlay keypad is launched and the Edit control is automatically scrolled so that it does not overlap with the overlay keypad (see Figure R2.7). To use the overlay style of keypad the Form must contain a scroll panel and the Edit field control must be added to the scroll panel. This recipe creates a scroll panel container using the Osp::Ui::Controls::ScrollPanel class and creates an Edit field control using the Osp::Ui::Controls::EditField class.

14_974018-gr02.indd 27514_974018-gr02.indd 275

8/31/10 12:39 AM8/31/10 12:39 AM

276

Part II



Recipes

Figure R2.7 Edit field with overlay keypad.

The IScrollPanelEventListener interface must be implemented in order to handle the events generated when the keypad is opened or closed, for example, for retrieval of the edited text string. The ITextEventListener interface must be implemented if the application needs to be aware of when the cursor moves within the Edit field. The IActionEventListener interface must be implemented if the Edit field is created with the optional keypad command button controls to handle the events generated when these buttons are tapped. The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Ui::IActionEventListener, public Osp::Ui::ITextEventListener, public Osp::Ui::IScrollPanelEventListener { // Construction public: MainForm(void); ~MainForm(void);

14_974018-gr02.indd 27614_974018-gr02.indd 276

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

277

bool Initialize(void); // Implementation protected: static const int ID_BUTTON_EDITFIELD_DONE = 100; static const int ID_BUTTON_EDITFIELD_CANCEL = 101; private: Osp::Ui::Controls::EditField* pEditField; Osp::Ui::Controls::ScrollPanel* pScrollPanel; Osp::Base::String* pEditFieldText; public: result OnInitializing(void); result OnTerminating(void); void OnActionPerformed(const Osp::Ui::Control& source, int actionId); void OnTextValueChanged(const Osp::Ui::Control& source); void OnTextValueChangeCanceled(const Osp::Ui::Control& source); void void void void

OnOverlayControlCreated(const Osp::Ui::Control& source); OnOverlayControlOpened(const Osp::Ui::Control& source); OnOverlayControlClosed(const Osp::Ui::Control& source); OnOtherControlSelected(const Osp::Ui::Control& source);

};

The ScrollPanel container and the EditForm control can be created during initialisation of the MainForm (OnInitializing()): 1. Create the ScrollPanel object and initialise it by setting its size and position using a Rectangle instance. 2. Create the EditField object and initialise it with its size, position, Edit field style, input style, title, input length limit and table view style parameters. 3. Register the IActionEventListener implemented by the MainForm class with the EditField control. 4. Register the ITextEventListener implemented by the MainForm class with EditField control. 5. Register the IScrollPanelEventListener implemented by the MainForm class with the EditField control. 6. Add the EditField’s left and right command buttons. 7. Create a String object to store the edited text. 8. Add the EditField control to the ScrollPanel container. 9. Add the ScrollPanel container to the MainForm. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method, in order to create a overlay style Edit field control:

14_974018-gr02.indd 27714_974018-gr02.indd 277

8/31/10 12:39 AM8/31/10 12:39 AM

278

Part II



Recipes

// Create ScrollPanel pScrollPanel = new ScrollPanel(); pScrollPanel->Construct(Rectangle(0, 0, 480, 712)); // Create EditField pEditField = new EditField(); pEditField->Construct(Rectangle(0, 300, 480, 80), EDIT_FIELD_STYLE_NORMAL, INPUT_STYLE_OVERLAY, true, 20, GROUP_STYLE_SINGLE); pEditField->SetGuideText(L”Edit Field”); // Register event listeners pEditField->AddActionEventListener(*this); pEditField->AddTextEventListener(*this); pEditField->AddScrollPanelEventListener(*this); // Add command buttons pEditField->SetOverlayKeypadCommandButton( COMMAND_BUTTON_POSITION_LEFT, L”Done”, ID_BUTTON_EDITFIELD_DONE); pEditField->SetOverlayKeypadCommandButton( COMMAND_BUTTON_POSITION_RIGHT, L”Cancel”, ID_BUTTON_EDITFIELD_CANCEL); // Create String to store entered text pEditFieldText = new String(); // Add an EditField to the Scroll Panel pScrollPanel->AddControl(*pEditField); // Add a ScrollPanel to the Form AddControl(*pScrollPanel);

When the user taps on the Edit field control the overlay keypad is launched. To receive and process any changes to the overlay keypad, the following IScrollPanelEventListener methods should be implemented: OnOtherControlSelected(), OnOverlayControlClosed(), OnOverlayControlCreated(), and OnOverlayControlOpened(). The following code snippet shows an example of how the Edit field’s text string can be stored in a string member variable when the keypad is opened in the OnOverlayControlOpened() method: void MainForm::OnOverlayControlOpened(const Osp::Ui::Control& source) { pEditFieldText->Clear(); pEditFieldText->Append(pEditField->GetText()); }

When the overlay keypad is active and the user taps either of the Edit field control’s command buttons, an action event is generated and is handled in the OnActionPerformed() method. The following code snippet is an example of the command button event handling in the MainForm’s OnActionPerformed() method:

14_974018-gr02.indd 27814_974018-gr02.indd 278

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

279

void MainForm::OnActionPerformed(const Osp::Ui::Control& source, int actionId) { switch(actionId) { case ID_BUTTON_EDITFIELD_DONE: pScrollPanel->CloseOverlayWindow(); pEditField->Draw(); pEditField->Show(); break; case ID_BUTTON_EDITFIELD_CANCEL: pEditField->SetText(*pEditFieldText); pScrollPanel->CloseOverlayWindow(); pEditField->Draw(); pEditField->Show(); break; default: break; } }

When the ‘Done’ button is tapped the overlay keypad is closed and the Edit field is redrawn. When the ‘Cancel’ button is tapped the original text string, which is stored in the member variable pEditFieldText, is loaded into the Edit field, the overlay keypad is closed and the Edit field redrawn.

Hints, Pitfalls, and Related Topics The ITextEventListener interface receives text events, but the type of text events it receives will differ depending on what type of UI control it is registered with. For example, in Method 1 the OnTextValueChanged() method is invoked when the ‘Done’ button is tapped, but in Method 2 it is invoked each time the cursor moves within the Edit field. By default an overlay-style keypad is not displayed with any command buttons. If these buttons are required, they must be created using the SetOverlayKeypadCommandButton() method. When initialising a ScrollPanel object for the EditField to be placed within, the location and size parameters for the ScrollPanel should be set relative to the top left of the Form’s available client area. So if a Form contains an indicator area and/or a title area, the heights of these areas should be taken into account when setting the ScrollPanel’s height parameter. If these values are not set correctly, the overlay keypad will not be displayed in the correct position. To clear any previous text entered in the standalone keypad the SetText() method can be called with an empty string parameter.

Related Recipe ■■

Add a Form to a Frame-based App

14_974018-gr02.indd 27914_974018-gr02.indd 279

8/31/10 12:39 AM8/31/10 12:39 AM

280

Part II



Recipes

Recipe 2.7: Get Touch Events Problem Description You want to retrieve touch events from the user input.

The Recipe The following configuration is required for this recipe: Namespaces used: Osp::Ui, Osp::Ui::Controls, additionally Osp::Graphics for graphics canvas drawing in the recipe

Header files to #include: FUi.h, FUiControls.h, additionally FGraphics.h for graphics canvas drawing in the recipe

Required libraries: FUi, FUiControls, additionally FGraphics for graphics canvas drawing in the recipe

Required privilege level: Normal

Required privilege groups: None

The bada platform supports both single-point touch and multi-point touch user input. This recipe details the steps to enable single-point touch user input within a Form and describes the code that needs to be implemented for the Form to receive and handle touch events. This recipe assumes the steps detailed in Method 2 of the ‘Add a Form to a Frame-based App’ recipe have been followed to add a Form to the application’s Frame. In this recipe the touch-screen user input is handled by the application and is used to draw lines on a graphics canvas (see Figure R2.8). A line is drawn on the graphics canvas following the motion of the user’s touch input. The double-tap touch input is used to clear the canvas. As shown in the ‘Add a Form to a Frame-based App’ recipe the MainForm class is inherited from the Form base class. In order for this Form to handle events from the touch screen, an event listener interface has to be implemented. So in this recipe the MainForm class must implement the Osp::Ui::ITouchEventListener interface class.

14_974018-gr02.indd 28014_974018-gr02.indd 280

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

281

Figure R2.8 Drawing lines with touch screen input.

The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Ui::ITouchEventListener { public: MainForm(void); ~MainForm(void); bool Initialize(void); private: Osp::Graphics::Canvas* pDrawingCanvas; Osp::Graphics::Point* pStartPoint; public: result OnDraw(void); result OnInitializing(void);

14_974018-gr02.indd 28114_974018-gr02.indd 281

8/31/10 12:39 AM8/31/10 12:39 AM

282

Part II



Recipes

result OnTerminating(void); void OnTouchPressed(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo& touchInfo); void OnTouchLongPressed(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo& touchInfo); void OnTouchReleased(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo& touchInfo); void OnTouchMoved(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo& touchInfo); void OnTouchDoublePressed(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo& touchInfo); void OnTouchFocusIn(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo& touchInfo); void OnTouchFocusOut(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo& touchInfo); };

To receive touch events the MainForm must register the touch event listener using the AddTouchEventListener() method. The creation of the canvas and the registration of the touch event listener should be performed during initialisation of the MainForm (OnInitializing()): 1. Create a graphics canvas and set its size and position based on the available client area. 2. Set the background colour of the MainForm. 3. Set the background colour and foreground colour of the drawing canvas. 4. Set the line width for the drawing canvas. 5. Clear the drawing canvas. 6. Create a Point object to store the touch start position when drawing. 7. Register the ITouchEventListener implemented by the MainForm class. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method to create a graphics canvas and enable the handling of touch events: // Create a member canvas object, and set its size to the // Form’s client area pDrawingCanvas = new Canvas; pDrawingCanvas->Construct(GetClientAreaBounds()); // Set background colour of the Form SetBackgroundColor(Color::COLOR_WHITE); // Set the bg, fg colour and line width of canvas

14_974018-gr02.indd 28214_974018-gr02.indd 282

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

283

pDrawingCanvas->SetBackgroundColor(Color::COLOR_WHITE); pDrawingCanvas->SetForegroundColor(Color::COLOR_RED); pDrawingCanvas->SetLineWidth(3); pDrawingCanvas->Clear(); // Create an instance of a Point to store the touch start position pStartPoint = new Point(); // Register touch event listener AddTouchEventListener(*this);

Because this recipe is using the touch events to create a custom drawing on a graphics canvas, the OnDraw() method must be implemented. The GetCanvasN() method is used within the OnDraw() implementation to retrieve the canvas the MainForm is using; otherwise the default Draw() method of the MainForm will overwrite the custom drawing. In this recipe the OnDraw() method copies the contents of the drawing canvas to the window canvas; this is necessary because the drawing operations are not actually being performed directly on the MainForm’s canvas in the OnDraw() method: result MainForm::OnDraw(void) { result r = E_SUCCESS; // Retrieve the window canvas Canvas* pWindowCanvas = GetCanvasN(); if (pWindowCanvas) { // Copy the contents of the drawing canvas (where the drawing // operations have been performed) to the window canvas pWindowCanvas->Copy(Point(GetClientAreaBounds().x, GetClientAreaBounds().y), *pDrawingCanvas, GetClientAreaBounds()); delete pWindowCanvas; } return r; }

The display will be updated when the MainForm’s Show() method is called; this occurs automatically following the OnDraw() callback. In order to handle the touch events when they occur the following methods have to be implemented by the MainForm: OnTouchDoublePressed(), OnTouchFocusIn(), OnTouchFocusOut(), OnTouchLongPressed(), OnTouchLongPressed(), OnTouchMoved(), OnTouchPressed(), or OnTouchReleased(). Each method is passed information about the source of the event, the current position, the start position and the status of the event. In this recipe only the OnTouchPressed(), OnTouchMoved(), and OnTouchDoublePressed() methods have been implemented.

14_974018-gr02.indd 28314_974018-gr02.indd 283

8/31/10 12:39 AM8/31/10 12:39 AM

284

Part II



Recipes

The TOUCH_PRESSED event occurs when the user touches the screen. This event is handled in the MainForm by the OnTouchPressed() method. In this recipe the OnTouchPressed() method is used to set the touch start position Point object to the current position touched by the user: void MainForm::OnTouchPressed(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo & touchInfo) { // Set the touch start position to the current position pStartPoint->SetPosition(currentPosition); }

This touch start position is used in the OnTouchMoved() method for the line drawing. The TOUCH_MOVED event occurs when the user is touching the screen and they have moved their finger across the screen. The first event is not sent immediately after the user has moved some pixels to compensate inaccurate touches. After this leeway an event is sent for every movement of two pixels or more in either direction. This event is handled in the MainForm by the OnTouchMoved() method. In this recipe the OnTouchMoved() method is used to draw a line from the stored touch start position to the current position: void MainForm::OnTouchMoved(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo & touchInfo) { // Draw a line from stored touch start point to current position pDrawingCanvas->DrawLine(*pStartPoint, currentPosition); // Draw the Form RequestRedraw(); // Set the current position to the touch start point pStartPoint->SetPosition(currentPosition); }

After the line is drawn, the touch start position is set to the current position. This is necessary to draw a line that correctly represents the user’s motion across the screen. The start position passed into this function cannot be used because it is the start position of when the user touched the screen, not the start position of the last movement. The TOUCH_DOUBLE_PRESSED event occurs when the user double-taps on the screen. This event is handled in the MainForm by the OnTouchDoublePressed() method. In this recipe the OnTouchDoublePressed() method is used to clear the graphics canvas:

14_974018-gr02.indd 28414_974018-gr02.indd 284

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

285

void MainForm::OnTouchDoublePressed(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo & touchInfo) { // Clear the canvas pDrawingCanvas->Clear(); // Draw the Form RequestRedraw(); }

Hints, Pitfalls, and Related Topics As would be expected, the TOUCH_PRESSED and TOUCH_RELEASED events occur in pairs when the user touches the screen. These events also occur in conjunction with the TOUCH_MOVED, TOUCH_LONG_PRESSED, and TOUCH_ DOUBLE_PRESSED events. These event sequences need to be taken into account when designing an application’s event processing. The sequence of events for a movement touch event is: 1. TOUCH_PRESSED 2. TOUCH_MOVED (multiple times) 3. TOUCH_RELEASED The sequence of events for a long press touch event is: 1. TOUCH_PRESSED 2. TOUCH_LONG_PRESSED 3. TOUCH_RELEASED The sequence of events for a double-tap touch event is: 1. TOUCH_PRESSED 2. TOUCH_RELEASED 3. TOUCH_DOUBLE_PRESSED 4. TOUCH_RELEASED It might be suitable for an application to only process a TOUCH_PRESSED event when its corresponding TOUCH_RELEASED event has been received. Or alternatively, the application may be designed so that any processing done in the OnTouchPressed() method is reversed if the TOUCH_MOVED, TOUCH_LONG_PRESSED, or TOUCH_DOUBLE_PRESSED event is received in the sequence afterwards. In both these cases it would be necessary to store the status of the previous event(s). It is advisable not to do too much processing in the OnTouchMoved() method, as the sensitivity (two pixels) of movement can result in this method being called many times.

14_974018-gr02.indd 28514_974018-gr02.indd 285

8/31/10 12:39 AM8/31/10 12:39 AM

286

Part II



Recipes

In this recipe, the GetCanvasN() method is used in the OnDraw() method to retrieve the MainForm’s canvas. To prevent memory leaks, if a method has an ‘N’ postfix, the caller must delete the returned instance after they have finished with the instance.

Related Recipe ■■

Add a Form to a Frame-based App

Recipe 2.8: Get Multi-touch Events Problem Description You want to retrieve multiple touch events from the user input.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Graphics1

Header files to #include:

FUi.h, FUiControls.h, FGraphics.h1

Required libraries:

FUi, FUiControls, FGraphics1

Required privilege level: Normal

Required privilege groups: None.

The bada platform supports both single-point and multi-point touch user input. This recipe details the steps to enable multi-point touch user input within a Form and describes the code that needs to be implemented for the Form to receive and handle multiple touch events (see Figure R2.9). The bada platform supports the detection and handling of up to six points2 simultaneously. This recipe assumes the steps detailed in the recipe ‘Get Touch Events’ have been followed to enable touch input and handle touch events.

1

For graphics canvas drawing in the recipe.

2

This can vary according to the hardware specification of the device, some may not support six points.

14_974018-gr02.indd 28614_974018-gr02.indd 286

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

287

In this recipe the touch screen user input is handled by the application and is used to draw lines on a graphics canvas. Lines are drawn on the graphics canvas following the motion of the user’s touch input. The double-tap touch input is used to clear the canvas.

Figure R2.9 Drawing lines with multi-touch input.

This recipe details only the changes made to the ‘Get Touch Events’ recipe to enable the handling of multiple touch events. In the ‘Get Touch Events’ recipe a member variable pointer of type Point was added to store the previous touch position for using in the TOUCH_MOVED event calculations. Because this recipe will be handling multiple touch points, a member variable pointer of type IList will be used to store the event information for each point instead:

14_974018-gr02.indd 28714_974018-gr02.indd 287

8/31/10 12:39 AM8/31/10 12:39 AM

288

Part II



Recipes

Osp::Base::Collection::IList* pStartInfoList;

In addition to the initialisation of the drawing code and the registration of the touch event listener, the OnInitializing() method needs to be modified to enable multi-touch events for the MainForm. Multi-touch for the MainForm control is enabled by creating an instance of a Touch object and enabling it using the SetMultipointEnabled() method. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method, in order to initialise the event position information pointer and enable multi-touch: // Initialise list pointer pStartInfoList = null; // Enable multi-point touch Touch touch; touch.SetMultipointEnabled(*this, true);

In this recipe only the OnTouchPressed() and OnTouchMoved() event handling methods have been modified from the ‘Get Touch Events’ recipe. As described in the ‘Get Touch Events’ recipe, each of these event handling methods are passed information about the position and status of the touch event, and these parameters can be used to implement the required functionality. In this recipe, these parameters can be ignored because they only contain information about a single touch point and not the multiple touch points required. In order to retrieve the information for the multiple touch points, an instance of a Touch object needs to be created. The Touch object provides a method GetTouchInfoListN(), which returns a list of the multi-point touch positions for the MainForm control, each represented by a TouchInfo object. In the ‘Get Touch Events’ recipe, the OnTouchPressed() method was implemented to store the current touch position to the touch start position Point object. In this recipe, the list of the multi-point touch positions are stored in the event position information IList member variable. Each item in this list is of type TouchInfo: void MainForm::OnTouchPressed(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo & touchInfo) { Touch touch; // Set the Start info list to the current touch info list pStartInfoList = touch.GetTouchInfoListN(source); }

In the ‘Get Touch Events’ recipe, the OnTouchMoved() method was implemented to draw a line from the stored touch start position to the current position. In this recipe, the OnTouchMoved() method effectively does the same

14_974018-gr02.indd 28814_974018-gr02.indd 288

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

289

line drawing functionality, but has to do it for the multiple touch points that the user has generated. The OnTouchMoved() method performs the following steps to draw the multiple lines: 1. Retrieves the list of TouchInfo objects for the current multi-touch positions. 2. Ensures that the pointers for the lists of previous and current multitouch positions are valid and have the same number of items in them. 3. Iterates through to the end of the list of touch points and for each step: a. gets the TouchInfo object for the previous touch event; b. gets the TouchInfo object for the current touch event; c. draws a line from the start position to the current position, retrieving the position information for each from their TouchInfo objects; d. sets the start position TouchInfo list item to the current point TouchInfo list item. 4. Deletes the list containing the current multi-touch position TouchInfo objects. 5. Draws the MainForm. void MainForm::OnTouchMoved(const Osp::Ui::Control& source, const Osp::Graphics::Point& currentPosition, const Osp::Ui::TouchEventInfo & touchInfo) { Touch touch; // Get the list of current event information IList *pList = null; pList = touch.GetTouchInfoListN(source); // Check the start info list and current info list exist and // are the same same size if (pStartInfoList && pList && (pStartInfoList->GetCount() == pList->GetCount())) { // Iterate through the list to retrieve the previous and // current TouchInfo objects for each point for(int i=0; iGetCount(); i++ ) { TouchInfo* pStartTouchInfo = static_cast (pStartInfoList->GetAt(i));

14_974018-gr02.indd 28914_974018-gr02.indd 289

8/31/10 12:39 AM8/31/10 12:39 AM

290

Part II



Recipes

TouchInfo* pTouchInfo = static_cast (pList->GetAt(i)); // Draw a line from stored touch start point // to current position pDrawingCanvas->DrawLine(pStartTouchInfo->position, pTouchInfo->position); // Set the Start info item to the current // touch info item pStartInfoList->SetAt(*pTouchInfo, i); } pList->RemoveAll(true); delete pList; // Draw the Form RequestRedraw(); } }

The OnDraw() method for this recipe remains the same as for the ‘Get Touch Events’ recipe.

Hints, Pitfalls, and Related Topics Multi-touch events can be tested in the Simulator as well as on the device. Multi-touch can be simulated by holding down the Ctrl key on the PC keyboard and clicking the mouse at various points on the screen. A grey circle will be displayed on the simulator display to indicate the touch points. To generate multiple TOUCH_PRESSED events, release the Ctrl key after clicking the mouse at all the required points. To generate multiple TOUCH_ MOVED events, keep the Ctrl key pressed and drag each of the grey circles to the required position, and then release the Ctrl key. Figure R2.10 shows some screenshots of simulating multi-touch events in this recipe using the Simulator. The example code in this recipe works for single-point touch as well as multi-point touch event handling.

Related Recipe ■■

Get Touch Events

14_974018-gr02.indd 29014_974018-gr02.indd 290

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

291

Figure R2.10 Simulating multi-touch events.

Recipe 2.9: Create a Custom List Control Problem Description You want to create a custom list control.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Base::Collection, Osp::Media

Header files to #include:

FUi.h, FUiControls.h, FBase.h, FMedia.h

Required libraries:

FUi, FUiControls, FBase, FMedia

Required privilege level: Normal

Required privilege groups: IMAGE

A CustomList is a special type of list with which the developer can configure the style and appearance of all the items in the list. Each item in a CustomList is composed of elements that can be text, bitmaps or custom drawings,

14_974018-gr02.indd 29114_974018-gr02.indd 291

8/31/10 12:39 AM8/31/10 12:39 AM

292

Part II



Recipes

and are represented by CustomListItem objects. The format of any CustomListItem object is defined using the CustomListItemFormat class. Custom drawings can be created and used by the a CustomListItem, by implementing an object using the Osp::Ui::Controls::ICustomListElement interface class. When an item in a custom list is selected or deselected, an item event is generated. In order to process these events the Osp::Ui::ICustomItemEventListener must be implemented. This recipe details the steps to create a custom list and its items, and provides some sample code snippets. This recipe assumes the steps detailed in the recipe ‘Add a Form to a Frame-based App’ have been followed to add a Form to the Application’s Frame. In this recipe two different custom list formats are created: the first contains a picture element and three text elements and the second contains a picture element, a text element and a custom drawing element. A custom list is then created, with an item using each of the custom list format types (see Figure R2.11).

Figure R2.11 Custom List control.

14_974018-gr02.indd 29214_974018-gr02.indd 292

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

293

In order to be able to add a custom element into a custom list item, a new element must be created that implements the specific drawing required by the custom element. Any drawing primitives supported by the Canvas object can be implemented in this custom element. In this recipe a new class CustomListElement is created, inheriting from the ICustomListElement interface class: class CustomListElement : public ICustomListElement { public: CustomListElement(void); ~CustomListElement(void); result DrawElement(const Osp::Graphics::Canvas& canvas, const Osp::Graphics::Rectangle& rect, Osp::Ui::Controls::CustomListItemStatus itemStatus); private: Osp::Base::Collection::IList* CreatePointListN(int xOffset, int yOffset); };

This class’s DrawElement() method is implemented to perform the custom canvas drawing. In this recipe the DrawElement() method draws a green outline hexagon onto the passed in canvas: result CustomListElement::DrawElement(const Osp::Graphics::Canvas& canvas, const Osp::Graphics::Rectangle& rect, Osp::Ui::Controls::CustomListItemStatus itemStatus) { result r = E_SUCCESS; Canvas* pCanvas = const_cast(&canvas); pCanvas->SetLineWidth(3); pCanvas->SetForegroundColor(Color::COLOR_GREEN); IList* pIList1 = CreatePointListN(rect.x, rect.y); pCanvas->DrawPolygon(*pIList1); delete pIList1; return r; }

In this example code snippet, the CreatePointListN() method has been added to the CustomListElement class to create a list of vertices for drawing a six-sided polygon, based on the position offsets passed in: Osp::Base::Collection::IList* CustomListElement::CreatePointListN(int xOffset, int yOffset) {

14_974018-gr02.indd 29314_974018-gr02.indd 293

8/31/10 12:39 AM8/31/10 12:39 AM

294

Part II



Recipes

IList* pPoints = new ArrayList(); pPoints->Add(*(new pPoints->Add(*(new pPoints->Add(*(new pPoints->Add(*(new pPoints->Add(*(new pPoints->Add(*(new

Point(20+xOffset, Point(10+xOffset, Point(20+xOffset, Point(40+xOffset, Point(50+xOffset, Point(40+xOffset,

0+yOffset))); 20+yOffset))); 40+yOffset))); 40+yOffset))); 20+yOffset))); 0+yOffset)));

return pPoints; }

This custom element and the standard picture and text elements can be used by the MainForm to create custom list items to be added to the custom list. The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Ui::ICustomItemEventListener { public: MainForm(void); ~MainForm(void); bool Initialize(void); protected: static static static static static

const const const const const

int int int int int

ID_FORMAT_PICTURE = 100; ID_FORMAT_NAME = 101; ID_FORMAT_NUMBER_TYPE = 102; ID_FORMAT_NUMBER = 103; ID_FORMAT_CUSTOM = 104;

static const int ID_CUSTOM_LIST_ITEM1 = 110; static const int ID_CUSTOM_LIST_ITEM2 = 111; Osp::Ui::Controls::CustomListItemFormat* pNameItemFormat; Osp::Ui::Controls::CustomListItemFormat* pCustomItemFormat; CustomListElement* pCustomListElement;

public: result OnInitializing(void); result OnTerminating(void); void OnItemStateChanged(const Osp::Ui::Control& source, int index, int itemId, int elementId, Osp::Ui::ItemStatus status); void OnItemStateChanged(const Osp::Ui::Control& source, int index, int itemId, Osp::Ui::ItemStatus status); };

The custom list item formats used for the custom list items should be created during initialisation of the MainForm (OnInitializing()). The steps for creating a CustomListItemFormat object with a bitmap element and three vertically arranged text elements are as follows:

14_974018-gr02.indd 29414_974018-gr02.indd 294

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

295

1. Create and initialise a CustomListItemFormat object. 2. Add a bitmap element of type ID_FORMAT_PICTURE at a position specified by a Rectangle object. 3. Add a text element of type ID_FORMAT_NAME at a position specified by a Rectangle object, with the colour of the normal and selected text. 4. Add a text element of type ID_FORMAT_NUMBER_TYPE at a position specified by a Rectangle object, with the colour of the normal and selected text. 5. Add a text element of type ID_FORMAT_NUMBER at a position specified by a Rectangle object, with the colour of the normal and selected text. 6. Enable the elements which are able to handle events (e.g. ID_FORMAT_ PICTURE & ID_FORMAT_NAME). // Create and initialise the Name Item Custom Format pNameItemFormat = new CustomListItemFormat(); pNameItemFormat->Construct(); // Add elements for a picture, the name, the number type and // the number pNameItemFormat-> AddElement(ID_FORMAT_PICTURE, Rectangle(5, 5, 110, 110)); pNameItemFormat->AddElement(ID_FORMAT_NAME, Rectangle(125, 5, 240, 50), 40, Color::COLOR_WHITE, Color::COLOR_GREEN); pNameItemFormat->AddElement(ID_FORMAT_NUMBER_TYPE, Rectangle Rectangle(125, 55, 240, 30), 25, Color::COLOR_WHITE, Color::COLOR_GREEN); pNameItemFormat->AddElement(ID_FORMAT_NUMBER, Rectangle(125, 85, 240, 30), 25, Color::COLOR_WHITE, Color::COLOR_GREEN); // Enable the elements which have actions associated with // them: picture and name pNameItemFormat->SetElementEventEnabled(ID_FORMAT_PICTURE, true); pNameItemFormat->SetElementEventEnabled(ID_FORMAT_NAME, true); pNameItemFormat->SetElementEventEnabled(ID_FORMAT_NUMBER_TYPE, false); pNameItemFormat->SetElementEventEnabled(ID_FORMAT_NUMBER, false);

The steps for creating a CustomListItemFormat object with a bitmap element, a text element and a custom element are as follows: 1. Create and initialise a CustomListItemFormat object. 2. Add a bitmap element of type ID_FORMAT_PICTURE at a position specified by a Rectangle object.

14_974018-gr02.indd 29514_974018-gr02.indd 295

8/31/10 12:39 AM8/31/10 12:39 AM

296

Part II



Recipes

3. Add a text element of type ID_FORMAT_NAME at a position specified by a Rectangle object, with the colour of the normal and selected text. 4. Add a custom element of type ID_FORMAT_CUSTOM at a position specified by a Rectangle object. 5. Enable the elements that are able to handle events (e.g. ID_FORMAT_ PICTURE and ID_FORMAT_NAME). // Create and initialise the Custom Item Custom Format pCustomItemFormat = new CustomListItemFormat(); pCustomItemFormat->Construct(); // Add elements for a picture, the name and the custom drawing pCustomItemFormat->AddElement(ID_FORMAT_PICTURE, Rectangle(5, 5, 70, 70)); pCustomItemFormat->AddElement(ID_FORMAT_NAME, Rectangle(85, 20, 280, 70), 40, Color::COLOR_WHITE, Color::COLOR_GREEN); pCustomItemFormat->AddElement(ID_FORMAT_CUSTOM, Rectangle(375, 20, 100, 70)); // Enable the elements which have actions associated with // them: picture and name pCustomItemFormat->SetElementEventEnabled(ID_FORMAT_PICTURE, true); pCustomItemFormat->SetElementEventEnabled(ID_FORMAT_NAME, true); pCustomItemFormat->SetElementEventEnabled(ID_FORMAT_CUSTOM, false);

Once the custom list items formats have been created, a custom list can be created and the items added to it using the formats specified. The custom list should be created during initialisation of the MainForm (OnInitializing()): 1. Create an Image object and initialise. 2. Decode the image file into the decoded bitmap container, passing the local file path of the image file and colour format parameters. 3. Create a CustomList and initialise it with the size and position of the list, the style of the list and whether to display an item divider. 4. Create the first custom list item: a. Create an instance of a CustomListItem object and initialise it with the required height of the item. b. Set the format of the custom item, using the CustomListItemFormat object previously created. c. Set the bitmap element (ID_FORMAT_PICTURE) with the normal and focussed decoded bitmap containers.

14_974018-gr02.indd 29614_974018-gr02.indd 296

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

297

d. Set the first text element (ID_FORMAT_NAME) string. e. Set the second text element (ID_FORMAT_NUMBER_TYPE) string. f. Set the third text element (ID_FORMAT_NUMBER) string. 5. Create the second custom list item: a. Create an instance of the custom list element previously created: CustomListElement. b. Create an instance of a CustomListItem object and initialise it with the required height of the item. c. Set the format of the custom item, using the CustomListItemFormat object previously created. d. Set the bitmap element (ID_FORMAT_PICTURE) with the normal and focused decoded bitmap containers. e. Set the text element (ID_FORMAT_NAME) string. f. Set the custom element (ID_FORMAT_CUSTOM) with the custom list element previously created. 6. Add the items to the custom list. 7. Add the custom list event handler. 8. Add the custom list control to the MainForm. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method, in order to create custom list items and add them to a custom list: Bitmap* pBitmap = new Bitmap; Image* pImage = new Image; pImage->Construct(); pBitmap = pImage->DecodeN(L”/Res/bada.png”, BITMAP_PIXEL_FORMAT_ARGB8888); // Create and initialise custom list CustomList* pCustomList = new CustomList(); pCustomList->Construct(Rectangle(0, 0, GetClientAreaBounds().width, GetClientAreaBounds().height), CUSTOM_LIST_STYLE_NORMAL, false); // Create first list item of type pNameItemFormat CustomListItem* pItem1 = new CustomListItem(); pItem1->Construct(120); pItem1->SetItemFormat(*pNameItemFormat); pItem1->SetElement(ID_FORMAT_PICTURE, *pBitmap, pBitmap); pItem1->SetElement(ID_FORMAT_NAME, “Name 1”); pItem1->SetElement(ID_FORMAT_NUMBER_TYPE, “Home”); pItem1->SetElement(ID_FORMAT_NUMBER, “01234567890”); // Create second list item of type pCustomItemFormat pCustomListElement = new CustomListElement(); CustomListItem* pItem2 = new CustomListItem(); pItem2->Construct(80);

14_974018-gr02.indd 29714_974018-gr02.indd 297

8/31/10 12:39 AM8/31/10 12:39 AM

298

Part II



Recipes

pItem2->SetItemFormat(*pCustomItemFormat); pItem2->SetElement(ID_FORMAT_PICTURE, *pBitmap, pBitmap); pItem2->SetElement(ID_FORMAT_NAME, “Name 1”); pItem2->SetElement(ID_FORMAT_CUSTOM, *(static_cast(pCustomListElement))); // Add items to the list pCustomList->AddItem(*pItem1, ID_CUSTOM_LIST_ITEM1); pCustomList->AddItem(*pItem2, ID_CUSTOM_LIST_ITEM2); // Add Custom Item Event listener pCustomList->AddCustomItemEventListener(*this); // Add custom list to the Form AddControl(*pCustomList); delete pBitmap; delete pImage;

In this recipe the picture and name elements of the custom list items have been enabled to handle events. These events can be handled in the MainForm by implementing the two OnItemStateChanged() methods from the ICustomEventListener interface class. These two methods notify when the state of an item or an element within the item has changed.

Hints, Pitfalls, and Related Topics Any CustomListItem and CustomListItemFormat objects need to be created on the heap memory. CustomListItem objects will be deleted automatically when the CustomList is destroyed. Any CustomListItemFormat and CustomListElement objects should be deleted by the application. The CustomList::RemoveItemAt() method can be used to remove items from the custom list.

Related Recipe ■■

Add a Form to a Frame-based App

Recipe 2.10: Implement a Form Manager Problem Description You want to create a Form Manager to control the display of Forms within your application.

The Recipe The following configuration is required for this recipe:

14_974018-gr02.indd 29814_974018-gr02.indd 298

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

299

Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Media

Header files to #include:

FUi.h, FUiControls.h, FMedia.h

Required libraries:

FUi, FUiControls, FMedia

Required privilege level: Normal

Required privilege groups: IMAGE

The bada platform does not provide a control for managing Forms within an application. So if an application has multiple forms that the user can switch between or that are controlled by system events, it may be useful to implement a Form Manager. This recipe details the steps to create and use a Form Manager (see Figure R2.12), and provides some sample code snippets. It uses some of the steps detailed in the recipe ‘Add a Form to a Frame-based App’ to add the Form Manager to the application’s Frame. A Form Manager can be created by implementing a new class, which inherits from the Osp::Ui::Controls::Form class. The Form Manager should be created at application start-up, and is used to create and control the display of all the other Forms in the application. The Form Manager does not contain any controls and does not directly display any content. The Control class, which a Form inherits from, provides a mechanism for inter-control communication using the Control::SendUserEvent() method. This mechanism can be used by a Form to communicate with the Form Manager, to request the display of another Form within the application. This recipe contains the steps for creating the following: ■■

FormMgr – which creates and manages the display of all the Forms within the application.

■■

MainForm – the main form of the application, which displays an icon list with icons numbered 1–9.

■■

BaseForm – a common form, used to display a tab area with nine tabs, a title bar and a right soft key.

When an icon is selected in the MainForm the appropriate BaseForm is displayed with corresponding number tab selected.

14_974018-gr02.indd 29914_974018-gr02.indd 299

8/31/10 12:39 AM8/31/10 12:39 AM

300

Part II



Recipes

Figure R2.12 Form Manager.

14_974018-gr02.indd 30014_974018-gr02.indd 300

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

301

Step 1: Create the BaseForm class The first step is to create a BaseForm that can be used to display the tabbed Forms. As the functionality of each of the nine Forms is the same in this recipe, it is more efficient to create a single Base Form and pass in any customisation for it in the Initialize() method. The following code snippet shows an example of the BaseForm class definition: class BaseForm : public Osp::Ui::Controls::Form, public Osp::Ui::IActionEventListener { public: BaseForm(void); ~BaseForm(void); bool Initialize(int actionId); protected: static const int ID_SOFTKEY_RIGHT = 110; private: int id; public: static const int ID_TAB_ONE = 100; static const int ID_TAB_TWO = 101; // ... static const int ID_TAB_NINE = 108; result OnInitializing(void); result OnTerminating(void); void OnActionPerformed(const Osp::Ui::Control& source, int actionId); };

In the Initialize() method the BaseForm is constructed as a normal Form with a title area, indicator area, tab area and a right soft key, and the passed in actionId is stored in a member variable for later use: bool BaseForm::Initialize(int actionId) { Form::Construct(FORM_STYLE_NORMAL|FORM_STYLE_TITLE| FORM_STYLE_INDICATOR|FORM_STYLE_SOFTKEY_1| FORM_STYLE_TEXT_TAB); id = actionId; return true; }

The tab control is created, with the right soft key, within the BaseForm’s OnInitializing() method:

14_974018-gr02.indd 30114_974018-gr02.indd 301

8/31/10 12:39 AM8/31/10 12:39 AM

302

Part II



Recipes

1. Set the text for the right soft key. 2. Assign the soft key actionId and register the soft key event listener. 3. Get the pointer to the BaseForm’s tab control. 4. Add the tab items to the tab control – in this recipe the tab controls contain text labels. 5. Set the selected tab index, using the actionId parameter passed in to the Initialize() method. 6. Register the action event listener with the tab control. SetSoftkeyText(SOFTKEY_1, “Back”); SetSoftkeyActionId(SOFTKEY_1, ID_SOFTKEY_RIGHT); AddSoftkeyActionListener(SOFTKEY_1, *this); Tab* pTab = GetTab(); if(pTab) { // Add the tabs pTab->AddItem(L”One”, ID_TAB_ONE); pTab->AddItem(L”Two”, ID_TAB_TWO); // ... pTab->AddItem(L”Nine”, ID_TAB_NINE); // Set the selected tab pTab->SetSelectedItem( pTab->GetItemIndexFromActionId(id)); // Add the action event listener pTab->AddActionEventListener(*this); }

The event handling for the soft key and for navigating between the tabs is described later in Step 6.

Step 2: Create the MainForm class The MainForm displays a list of icons. Depending on which icon the user selects, the relevant tabbed Form will be displayed. The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Ui::IItemEventListener { public: MainForm(void); ~MainForm(void);

14_974018-gr02.indd 30214_974018-gr02.indd 302

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

303

bool Initialize(void); protected: static const int ID_ICON_LIST_ITEM1 = 121; static const int ID_ICON_LIST_ITEM2 = 122; // ... static const int ID_ICON_LIST_ITEM9 = 129; Osp::Graphics::Bitmap* pBitmapNormal1; Osp::Graphics::Bitmap* pBitmapNormal2; // ... Osp::Graphics::Bitmap* pBitmapNormal9; result CreateBitmaps(void); result DeleteBitmaps(void); public: result OnInitializing(void); result OnTerminating(void); void

OnItemStateChanged (const Osp::Ui::Control &source, int index, int itemId, Osp::Ui::ItemStatus status);

};

The list of icons is created using the IconList control during the initialisation of the MainForm (OnInitializing()): 1. Create bitmaps for display in the IconList – a description of how to decode an image and store in a bitmap container can be found in the recipe ‘Add a Form to a Frame-based App’. Note: These bitmap containers must be deleted in the OnTerminating() method of the MainForm. 2. Create an instance of the IconList control. 3. Initialise the IconList object with the size and position of the control, the list style and the size of each icon. 4. Register the item event listener with the IconList control. 5. Remove the margins from the top and left side of the list. 6. Add the items to the IconList control. 7. Add the IconList control to the MainForm. CreateBitmaps(); // Create Icon List IconList* pIconList = new IconList(); pIconList->Construct(Rectangle(0, 0, GetClientAreaBounds().width, GetClientAreaBounds().height), ICON_LIST_STYLE_NORMAL, 160, 160); pIconList->AddItemEventListener(*this); // Remove margins from top and left of the icons pIconList->SetMargin(0, 0); // Add the icons to the list

14_974018-gr02.indd 30314_974018-gr02.indd 303

8/31/10 12:39 AM8/31/10 12:39 AM

304

Part II



Recipes

pIconList->AddItem(null, pBitmapNormal1, null, ID_ICON_LIST_ITEM1); pIconList->AddItem(null, pBitmapNormal2, null, ID_ICON_LIST_ITEM2); // ... pIconList->AddItem(null, pBitmapNormal9, null, ID_ICON_LIST_ITEM9); // Add icon list control to the Form AddControl(*pIconList);

In this recipe, the default focus animation provided by the IconList control is used when an item is selected. Alternatively, a specific bitmap can be used to indicate the focus, by adding a focused bitmap parameter in the AddItem() method. If a focused bitmap is used, the default focus animation must be disabled by calling the IconList::SetFocusAnimationEnabled() method with the enable parameter set to false. The event handling for icon selection is described in Step 5.

Step 3: Create the FormMgr class The FormMgr is a Form control that is used to manage the creation and display of all the Forms in the application; it does not display any controls itself. Requests from the MainForm or from the BaseForms are sent to the FormMgr using the Control class’s SendUserEvent() method. The following code snippet shows an example of the FormMgr class definition: class FormMgr : public Osp::Ui::Controls::Form { public: FormMgr(void); virtual ~FormMgr(void); bool Initialize(void); protected: Osp::Ui::Controls::Form* pPreviousForm; MainForm* pMainForm; public: virtual result OnInitializing(void); virtual result OnTerminating(void); static static static // ... static

const RequestId REQUEST_MAINFORM = 100; const RequestId REQUEST_ITEM1 = 101; const RequestId REQUEST_ITEM2 = 102; const RequestId REQUEST_ITEM9 = 109;

bool SetStarterForm(RequestId requestId, Osp::Base::Collection::IList* pArgs);

14_974018-gr02.indd 30414_974018-gr02.indd 304

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

305

void SwitchToForm(RequestId requestId, Osp::Base::Collection::IList* pArgs); void OnUserEventReceivedN(RequestId requestId, Osp::Base::Collection::IList* pArgs); };

In the Initialize() method the FormMgr is constructed as a normal Form and given the name ‘FormMgr’. The name is important, because it is used by the MainForm and the BaseForms to identify the control to send user events to: bool FormMgr::Initialize() { Form::Construct(FORM_STYLE_NORMAL); Form::SetName(“FormMgr”); return true; }

When a user event is received from either the MainForm or any of the BaseForms, the OnUserEventReceivedN() method is called. In this method the SwitchToForm() method is called to process the event: void FormMgr::OnUserEventReceivedN(RequestId requestId, Osp::Base::Collection::IList* pArgs) { SwitchToForm(requestId, pArgs); }

The SwitchToForm() method is responsible for the creation and display of the requested Form. In this recipe the MainForm is created only once and exists throughout the lifetime of the application, but the BaseForms are created and destroyed as required. For each BaseForm display request the following steps are performed: 1. Create an instance of a BaseForm and initialise it, passing in the relevant actionId. 2. Set the text to be displayed in the BaseForm’s Title area. 3. Add the BaseForm to the application’s Frame. 4. Set the BaseForm as the current Form of the Frame. 5. Draw and Show the Form. 6. Remove the previous BaseForm control and store a reference to the current BaseForm. A MainForm display request follows the same steps, with the exception that if it already exists it does not need to be created and added to the application frame again.

14_974018-gr02.indd 30514_974018-gr02.indd 305

8/31/10 12:39 AM8/31/10 12:39 AM

306

Part II



Recipes

void FormMgr::SwitchToForm(RequestId requestId, Osp::Base::Collection::IList* pArgs) { BaseForm* pForm = null; Frame *pFrame = Application::GetInstance()->GetAppFrame()->GetFrame(); switch(requestId) { case REQUEST_MAINFORM: { if(pMainForm == null) { pMainForm = new MainForm(); pMainForm->Initialize(); pFrame->AddControl(*pMainForm); } pFrame->SetCurrentForm(*pMainForm); pMainForm->Draw(); pMainForm->Show(); if(pPreviousForm != null && pPreviousForm != pMainForm) { pFrame->RemoveControl(*pPreviousForm); } pPreviousForm = pMainForm; return; } break; case REQUEST_ITEM1: pForm = new BaseForm(); pForm->Initialize(BaseForm::ID_TAB_ONE); pForm->SetTitleText(“Tab 1”); break; case REQUEST_ITEM2: pForm = new BaseForm(); pForm->Initialize(BaseForm::ID_TAB_TWO); pForm->SetTitleText(“Tab 2”); break; // ... case REQUEST_ITEM9: pForm = new BaseForm(); pForm->Initialize(BaseForm::ID_TAB_NINE); pForm->SetTitleText(“Tab 9”); break; default: break; } if(pForm) { pFrame->AddControl(*pForm); pFrame->SetCurrentForm(*pForm); pForm->Draw(); pForm->Show(); if(pPreviousForm != null && pPreviousForm != pMainForm) { pFrame->RemoveControl(*pPreviousForm);

14_974018-gr02.indd 30614_974018-gr02.indd 306

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

307

} pPreviousForm = pForm; } }

The display of the MainForm is requested by a user event either during application start-up or when the Back soft key is selected from a BaseForm. The display of a BaseForm is requested by a user event either from the selection of an icon in the MainForm or the selection of a tab in a BaseForm.

Step 4: Application launch The FormMgr is created and added to the application’s Frame during the application initialisation phase (OnAppInitializing()). The same steps as described in the recipe ‘Add a Form to a Frame-based App’ are followed, with the additional step of requesting that the FormMgr displays the MainForm, with a call to the SetStarterForm() method. // Create a form FormMgr *pFormMgr = new FormMgr(); pFormMgr->Initialize(); // Add the form to the frame Frame *pFrame = GetAppFrame()->GetFrame(); pFrame->AddControl(*pFormMgr); // Request the Form Manager to display the MainForm pFormMgr->SetStarterForm(FormMgr::REQUEST_MAINFORM, null);

The SetStarterForm() method checks whether the currently active form is the FormMgr and then requests that the MainForm is displayed with a call to the SwitchToForm() method. bool FormMgr::SetStarterForm(RequestId requestId, Osp::Base::Collection::IList* pArgs) { Form *pCurrentForm = Application::GetInstance()-> GetAppFrame()->GetFrame()->GetCurrentForm(); if (pCurrentForm == this) SwitchToForm(requestId, pArgs); else return false; return true; }

Step 5: Implement the MainForm event handling When an item in the IconList is selected the MainForm’s implementation of the IItemEventListener::OnItemStateChanged() method is called to

14_974018-gr02.indd 30714_974018-gr02.indd 307

8/31/10 12:39 AM8/31/10 12:39 AM

308

Part II



Recipes

handle the event. In this recipe, the event is handled by sending a user event request to the FormMgr, which will create and display the appropriate BaseForm. void MainForm::OnItemStateChanged (const Osp::Ui::Control &source, int index, int itemId, Osp::Ui::ItemStatus status) { Frame *pFrame = Application::GetInstance()-> GetAppFrame()->GetFrame(); FormMgr *pFormMgr = static_cast (pFrame->GetControl(“FormMgr”)); switch(itemId) { case ID_ICON_LIST_ITEM1: pFormMgr->SendUserEvent(FormMgr::REQUEST_ITEM1, null); break; case ID_ICON_LIST_ITEM2: pFormMgr->SendUserEvent(FormMgr::REQUEST_ITEM2, null); break; // ... case ID_ICON_LIST_ITEM9: pFormMgr->SendUserEvent(FormMgr::REQUEST_ITEM9, null); break; default: break; } }

Step 6: Implement the BaseForm event handling When the right soft key or a tab in the BaseForm is selected the BaseForm’s implementation of the IActionEventListener::OnActionPerformed() method is called to handle the event. In this recipe, the event is handled by sending a user event request to the FormMgr, which will create and display the MainForm or the appropriate BaseForm. void BaseForm::OnActionPerformed(const Osp::Ui::Control& source, int actionId) { Frame *pFrame = Application::GetInstance()-> GetAppFrame()->GetFrame(); FormMgr *pFormMgr = static_cast (pFrame->GetControl(“FormMgr”)); switch(actionId) { case ID_SOFTKEY_RIGHT: pFormMgr->SendUserEvent(FormMgr::REQUEST_MAINFORM, null); break; case ID_TAB_ONE: pFormMgr->SendUserEvent(FormMgr::REQUEST_ITEM1, null); break; case ID_TAB_TWO: pFormMgr->SendUserEvent(FormMgr::REQUEST_ITEM2, null); break;

14_974018-gr02.indd 30814_974018-gr02.indd 308

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

309

// ... case ID_TAB_NINE: pFormMgr->SendUserEvent(FormMgr::REQUEST_ITEM9, null); break; default: break; } }

Hints, Pitfalls, and Related Topics It is not possible to remove the border that is displayed around the icons in the IconList. When creating the IconList, it is important to be aware that the IconList adds margins and spacing around the icons, so more space needs to be allocated for the control than the size of the icons. By default, the margin set at the top and the left of the IconList is 2 and 5 pixels respectively.

Related Recipe ■■

Add a Form to a Frame-based App

Recipe 2.11: Get Soft Key and Hard Key Events Problem Description You need to get key pressed events.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls

Header files to #include: FUi.h, FUiControls.h

Required libraries: FUi, FUiControls

Required privilege level: Normal

Required privilege groups: None

14_974018-gr02.indd 30914_974018-gr02.indd 309

8/31/10 12:39 AM8/31/10 12:39 AM

310

Part II



Recipes

In addition to the soft key functionality provided in the bada platform, a bada device usually also has some hard keys. There are default hard keys that perform critical tasks, such as Power and Menu, and optional hard keys that are device dependent, such as Camera and Volume. Figure R2.13 shows these keys on the bada Wave device.

Figure R2.13 Wave hardware keys overview.

This recipe assumes the steps detailed in the recipe ‘Add Soft Keys to a Form and Get Actions’ have been followed to add soft keys and soft key event handling to an application’s Form. In this recipe the key events are received and an appropriate log message is printed to the output terminal. As shown in the ‘Add Soft Keys to a Form and Get Actions’ recipe, the MainForm class is inherited from the Form base class and the IActionEventListener class is implemented to handle the soft key events. Hard key events are not received and handled in the same way as soft key events, and a separate listener interface must be implemented to receive key events. So additionally, the MainForm class must implement the Osp:: Ui::IKeyEventListener interface class. The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Ui::IActionEventListener, public Osp::Ui::IKeyEventListener { public: MainForm(void); ~MainForm(void); bool Initialize(void); protected: static const int ID_SOFTKEY_LEFT = 101;

14_974018-gr02.indd 31014_974018-gr02.indd 310

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

311

static const int ID_SOFTKEY_RIGHT = 102; Osp::Ui::KeyCode prevKeyCode; Osp::Ui::KeyState prevKeyState; public: result OnInitializing(void); result OnTerminating(void); void OnActionPerformed(const Osp::Ui::Control& source, int actionId); void OnKeyPressed (const Osp::Ui::Control &source, Osp::Ui::KeyCode keyCode); void OnKeyReleased (const Osp::Ui::Control &source, Osp::Ui::KeyCode keyCode); void OnKeyLongPressed (const Osp::Ui::Control &source, Osp::Ui::KeyCode keyCode); };

To receive key events the MainForm must register the key event listener in the OnInitializing() method, using the AddKeyEventListener() method: // Register MainForm with key event listener AddKeyEventListener(*this);

To handle the key events when they occur the following methods must be implemented by the MainForm: OnKeyPressed(), OnKeyReleased(), and OnKeyLongPressed(). Each method is passed information about the source of the event and the key code of the hard key the event is related to. The following code snippets show examples of these methods: void MainForm::OnKeyPressed(const Control &source, Osp::Ui::KeyCode keyCode) { switch(keyCode) { case Osp::Ui::KEY_SIDE_UP: AppLog(“Side key up pressed \n”); break; case Osp::Ui::KEY_SIDE_DOWN: AppLog(“Side key down pressed \n”); break; case Osp::Ui::KEY_CAMERA: AppLog(“Camera key pressed \n”); break; case Osp::Ui::KEY_SWITCH: AppLog(“Task switcher key pressed \n”); break; default: AppLog(“Invalid key pressed \n”); break; } prevKeyCode = keyCode; prevKeyState = KEY_PRESSED;

14_974018-gr02.indd 31114_974018-gr02.indd 311

8/31/10 12:39 AM8/31/10 12:39 AM

312

Part II



Recipes

}

void MainForm::OnKeyReleased(const Control &source, Osp::Ui::KeyCode keyCode) { switch(keyCode) { // Handle the various keys however you need it } prevKeyCode = keyCode; prevKeyState = KEY_RELEASED; }

void MainForm::OnKeyLongPressed (const Control &source, Osp::Ui::KeyCode keyCode) { switch(keyCode) { // Handle the various keys however you need it } prevKeyCode = keyCode; prevKeyState = KEY_LONGPRESSED; }

Hints, Pitfalls, and Related Topics When the user presses and releases a hard key, two events are generated: 1. KEY_PRESSED 2. KEY_RELEASED When the user presses and holds a hard key before releasing it, an additional event is generated for the long press: 1. KEY_PRESSED 2. KEY_LONGPRESSED 3. KEY_RELEASED (this is invoked when the key is released) When designing an application, you must consider whether the functionality associated with a hard key is going to be invoked when the key is pressed or released. Additionally, you must consider whether any long press functionality is to be implemented for a hard key. These factors will help determine how the key event handling methods are implemented.

14_974018-gr02.indd 31214_974018-gr02.indd 312

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

313

In this recipe the key state (PRESSED, RELEASED, or LONGPRESSED) and the key code are stored each time an event is received. These values can be used by MainForm to determine what action to perform when an event is received, based on what the previous event received was. The following code snippet shows an example of how these values can be used in the OnKeyReleased() method to perform some functionality when the Side key up hard key is released: case Osp::Ui::KEY_SIDE_UP: if (prevKeyState == KEY_PRESSED && prevKeyCode == Osp::Ui::KEY_SIDE_UP) AppLog(“Process Side key up released \n”); else AppLog(“Don’t process Side key up released \n”); break;

In this example some functionality should be performed when the hard key is released, but only if the previous event was the hard key pressed event, that is, the user did not press and hold the key for a long time. It is important to note that in some cases some events of particular keys are reserved for the Application Framework (or for selected native apps) only, such as the Menu key on the Wave device for which the LONGPRESSED event is not available. It is reserved for the Task Manager. The Dial and Power/End keys do generate events but the the bada app key code is KEY_INVALID. It was a design decision not to offer the possibility of accessing these two keys because it might well be that other bada devices might not have these two buttons at all.

Related Recipe ■■

Add Soft Keys to a Form and Get Actions

Recipe 2.12: Use a Web Control Problem Description You want to use web content within an application.

The Recipe The following configuration is required for this recipe:

14_974018-gr02.indd 31314_974018-gr02.indd 313

8/31/10 12:39 AM8/31/10 12:39 AM

314

Part II



Recipes

Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Web::Controls

Header files to #include:

FUi.h, FUiControls.h, FWeb.h

Required libraries:

FUi, FUiControls, FWebControls

Required privilege level: Normal

Required privilege groups: WEB_SERVICE

The Web control can be used to add a web browser to an application to load web pages, download content and run JavaScript inside the browser. The Web control is based on Webkit (webkit.org). This recipe shows the two different ways that the Web control can be used. Each example details the steps required to create and use the Web control, and provides some sample code snippets. Both examples in this recipe assume the steps detailed in Method 2 of the recipe ‘Add a Form to a Frame-based App’ have been followed to add a Form to the application’s Frame.

Example 1: Loading a Web Page This example creates a Web control to display a web page using the Osp::Web::Controls::Web class, and displays it in a form with a landscape orientation (see Figure R2.14).

Figure R2.14 Web control.

14_974018-gr02.indd 31414_974018-gr02.indd 314

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

315

A member variable pointer of type Web is added to the MainForm class to hold a reference to the created Web control: Osp::Web::Controls::Web* pWeb;

The Web control can be created during initialisation of the MainForm (OnInitializing()): 1. Set the orientation of the MainForm to landscape. 2. Create the Web control. 3. Initialise the Web control with the size and position of the available screen area. 4. Add the Web control to the MainForm. 5. Load the specified URL into the Web control. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method, in order to create a Web control: // Set the orientation of the Form to landscape SetOrientation(ORIENTATION_LANDSCAPE); // Create Web control object pWeb = new Web(); // Initialise the Web control pWeb->Construct(Rectangle(0, 0, GetClientAreaBounds().width, GetClientAreaBounds().height)); // Add the Web control to the Form AddControl(*pWeb); // Load the specified URL in the Web control pWeb->LoadUrl(L”http://developer.bada.com”);

Example 2: Downloading a File This example creates a Web control using the Osp::Web::Controls::Web class and uses it to download a file from the Web. The file is saved to the application’s /Home directory and can be used as required by the application. To download a file from a remote server the Osp::Web::Controls::Web control is used to embed a browser within the application. The Osp::Web::Controls::ILoadingListener interface class is implemented to listen to events occurring during an loading operation and inform the web control that the application wants to handle the data by itself. The Osp::Web::Controls::IWebDownloadListener interface class is used to download data to the application.

14_974018-gr02.indd 31514_974018-gr02.indd 315

8/31/10 12:39 AM8/31/10 12:39 AM

316

Part II



Recipes

The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Web::Controls::ILoadingListener, public Osp::Web::Controls::IWebDownloadListener { public: MainForm(void); ~MainForm(void); bool Initialize(void); protected: Osp::Io::File* pFile; Osp::Web::Controls::Web* pWeb; String serverFilePath; String fileName; String localFilePath; void WriteDownloadFile(Osp::Io::File* file, const Osp::Base::ByteBuffer& chunk); void CloseDownloadFile(Osp::Io::File* file); public: result OnInitializing(void); result OnTerminating(void); void void bool

OnEstimatedProgress(int progress) {}; OnHttpAuthenticationCanceled(void) {}; OnHttpAuthenticationRequestedN( const Osp::Base::String &host, const Osp::Base::String &realm, const Osp::Web::Controls::AuthenticationChallenge &authentication) {return false;}; void OnLoadingCanceled(void) {}; void OnLoadingCompleted(void) {}; void OnLoadingErrorOccurred ( Osp::Web::Controls::LoadingErrorType error, const Osp::Base::String &reason) {}; bool OnLoadingRequested(const Osp::Base::String &url, Osp::Web::Controls::WebNavigationType type) {return false;}; void OnLoadingStarted(void) {}; void OnPageTitleReceived(const Osp::Base::String &title) {}; Osp::Web::Controls::DecisionPolicy OnWebDataReceived ( const Osp::Base::String &mime, const Osp::Net::Http::HttpHeader &httpHeader); void

void void

OnWebChunkedDataReceived ( const Osp::Base::ByteBuffer& chunk); OnWebDataDownloadCompleted(void); OnWebDownloadFailed ( Osp::Web::Controls::LoadingErrorType error);

};

14_974018-gr02.indd 31614_974018-gr02.indd 316

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

317

The creation of the Web control and the registration of the listeners should be done in the OnInitializing() method: 1. Define the filename, the server filepath for the file to be downloaded from, and the local filepath for the file to be stored. 2. Create a Web control and initialise it to the size of the client area. 3. Add the Web control to the MainForm. 4. Register the ILoadingListener. 5. Register the IWebDownloadListener. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method: fileName.Append(L”somefile”); serverFilePath.Append(L”http://www.somewebsite.com/”); serverFilePath.Append(fileName); localFilePath.Append(L”/Home/”); localFilePath.Append(fileName); // Create web control and add to form pWeb = new Web(); pWeb->Construct(GetClientAreaBounds()); AddControl(*pWeb); // Register loading & download listeners with the web control pWeb->SetLoadingListener(this); pWeb->SetDownloadListener(this);

// Load the URL pWeb->LoadUrl(serverFilePath);

The ILoadingListener interface class provides several methods to monitor the events occurring during a loading operation. This example only implements one of these methods: OnWebDataReceived(). The OnWebDataReceived() method is called as soon as the first chunk of data is received and notifies an application of the content type of the data to be downloaded. In this example, rather than the web engine handling the data, the application handles the data itself. The OnWebDataReceived() method should return WEB_DECISION_DOWNLOAD, so that the data is routed to the IWebDownloadListener registered by the application: Osp::Web::Controls::DecisionPolicy MainForm::OnWebDataReceived(const Osp::Base::String &mime, const Osp::Net::Http::HttpHeader &httpHeader) { return WEB_DECISION_DOWNLOAD; }

14_974018-gr02.indd 31714_974018-gr02.indd 317

8/31/10 12:39 AM8/31/10 12:39 AM

318

Part II



Recipes

The IWebDownloadListener provides several methods for handling the download of data: OnWebChunkedDataReceived(), OnWebDataDownload Completed(), and OnWebDownloadFailed(). The data is downloaded in chunks, and for each chunk received the IWeb DownloadListener::OnWebChunkedDataReceived() method is called. In this example the chunk of data is written to a local file using the MainForm::WriteDownloadFile() method: void MainForm::OnWebChunkedDataReceived(const Osp::Base::ByteBuffer& { WriteDownloadFile(pFile, chunk); }

chunk)

If the download fails, the IWebDownloadListener::OnWebDownload Failed() method is called. In this example the reference to the local file is destroyed using the MainForm::CloseDownloadFile() method, so no further data can be written to it. void MainForm::OnWebDownloadFailed(Osp::Web::Controls::LoadingErrorType error) { CloseDownloadFile(pFile); }

When the data download is complete, the IWebDownloadListener::OnWebDataDownloadCompleted() method is called. In this example the reference to the local file is destroyed: void MainForm::OnWebDataDownloadCompleted(void) { CloseDownloadFile(pFile); // File download complete – file can now be used by application }

The WriteDownloadFile() method writes the downloaded chunks of data to the local file specified during initialisation: void MainForm::WriteDownloadFile(Osp::Io::File* file, const Osp::Base::ByteBuffer& chunk) { if(file == null) { file = new Osp::Io::File(); file->Construct(localFilePath, L”a+”); } file->Write(chunk); file->Flush(); }

14_974018-gr02.indd 31814_974018-gr02.indd 318

8/31/10 12:39 AM8/31/10 12:39 AM

Group 2



UI Basics

319

The CloseDownloadFile() destroys the reference to the local file so that no further data can be written to it: void MainForm::CloseDownloadFile(Osp::Io::File* file) { if(file) { delete file; file = null; } }

When the file has been successfully downloaded, it can be used by the application as required.

Hints, Pitfalls, and Related Topics The WEB_SERVICE group privilege must be set in the application’s manifest file in order to use the Web control.

Related Recipe ■■

Add a Form to a Frame-based App

14_974018-gr02.indd 31914_974018-gr02.indd 319

8/31/10 12:39 AM8/31/10 12:39 AM

14_974018-gr02.indd 32014_974018-gr02.indd 320

8/31/10 12:39 AM8/31/10 12:39 AM

GROUP

3 Extended UI and Sensors

Recipe 3.1: Use Gesture Input and Motion UI Problem Description You want to use gesture and motion events to control the UI.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Uix

Header files to #include:

FUi.h, FUiControls.h, FUix.h

Required libraries:

FUi, FUiControls, FUix

Required privilege level: Normal

Required privilege groups: None

321

15_974018-gr03.indd 32115_974018-gr03.indd 321

8/31/10 12:40 AM8/31/10 12:40 AM

322

Part II



Recipes

A user can interact with their bada device using a variety of different gestures (motion UI) and can rotate the display so that the orientation of the application changes. This recipe details the steps to enable motion and orientation control within an application and describes the code that needs to be implemented for the Form to receive and handle motion and orientation changed events. The three types of motion events supported are: ■■

Double-tap: Occurs when any part of the device is tapped twice. Tapping uses the acceleration sensor, so any part of the device can be tapped, including the screen.

■■

Shake: Occurs when the device is quickly moved back and forth multiple times. Shake can last a long time. To accurately capture this behaviour, both the start and the end of shake are reported as two separate events.

■■

Snap: Occurs when the device is moved along one axis and back.

This recipe assumes the steps detailed in the recipe ‘Add a Form to a Framebased App’ (which you can find in the second group of recipes, “UI Basics”) have been followed to add a Form to the application’s Frame. In this recipe a Flash animation is created and played on the display. The user can control the state of the animation, the visibility, and the size and position of the animation by using motion events. As shown in the ‘Add a Form to a Frame-based App’ recipe, the MainForm class is inherited from the Form base class. For this form to handle motion and orientation events the motion and orientation event listener interfaces have to be implemented. So in this recipe the MainForm class must implement the Osp::Uix::IMotionEventListener and the Osp::Ui::IOrientation EventListener interface classes. The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Uix::IMotionEventListener, public Osp::Ui::IOrientationEventListener { public: MainForm(void); ~MainForm(void); bool Initialize(void); protected: Osp::Uix::Motion* pMotion; public: Osp::Ui::Controls::Flash* pFlash; result OnInitializing(void);

15_974018-gr03.indd 32215_974018-gr03.indd 322

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

323

result OnTerminating(void); void OnShakeDetected(Osp::Uix::MotionState motionState); void OnDoubleTapDetected(void); void OnSnapDetected(Osp::Uix::MotionSnapType snapType); void OnOrientationChanged(const Osp::Ui::Control &source, OrientationStatus orientationStatus); };

The creation of the Flash animation, the enabling of motion and orientation support, and the registration of the motion and orientation event listeners should be performed in the OnInitializing() method: 1. Create a motion object. 2. Initialise the motion object with the associated listener. 3. Set the types of motion to be enabled (e.g. double-tap, shake and snap). 4. Create a Flash object. 5. Construct the Flash object: set the size and position of the control, the style of Flash playback and the filename and path of the SWF file. 6. Add the Flash control to the MainForm. 7. Set the orientation of the MainForm (e.g. four-directional orientation style). 8. Draw the MainForm. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method: // Create Motion instance and set to detect all types of events pMotion = new Motion(); pMotion->Construct(*this); pMotion->SetEnabled(MOTION_TYPE_DOUBLETAP|MOTION_TYPE_SHAKE| MOTION_TYPE_SNAP); // Create new Flash object pFlash = new Flash(); pFlash->Construct(Rectangle(40, 40, 400, 400), FLASH_STYLE_PLAY_WITHOUT_FOCUS, String(L”/Res/Bada.swf”)); // Add flash object to form AddControl(*pFlash); // Set Orientation of the form SetOrientation(ORIENTATION_AUTOMATIC_FOUR_DIRECTION); // Register Orientation listener AddOrientationEventListener(*this); // Draw the controls Draw(); Show();

15_974018-gr03.indd 32315_974018-gr03.indd 323

8/31/10 12:40 AM8/31/10 12:40 AM

324

Part II



Recipes

In order to start the flash animation playback the Flash control’s Play() method must be called. If immediate playback is required in an application, the Flash control’s Play() method should be called after the application has entered the Foreground state. In a simple application, this can be achieved by calling the Flash control’s Play() method in the application’s OnForeground() method. If immediate playback is not required, the Flash control’s Play() method can be called by the MainForm when a user or system event is handled. The following code snippet is an example of code that would be added to the application’s OnForeground() method, in order to start playing the Flash control: Frame *pFrame = GetAppFrame()->GetFrame(); MainForm *pForm = static_cast(pFrame->GetCurrentForm()); pForm->pFlash->Play();

Shake motions are reported to the application in the IMotionEventListener::OnShakeDetected() method. In this recipe the shake motion is used to pause or resume the Flash animation. When the MOTION_ENDED notification is received the animation is paused or resumed, depending on the current animation status: void MainForm::OnShakeDetected(Osp::Uix::MotionState motionState) { switch (motionState) { case MOTION_STARTED: AppLog(“OnShakeDetected: Motion started\n”); break; case MOTION_INPROGRESS: AppLog(“OnShakeDetected: Motion in progress\n”); break; case MOTION_ENDED: { AppLog(“OnShakeDetected: Motion ended\n”); if(pFlash->GetStatus() == FLASH_PLAYING) pFlash->Pause(); else if(pFlash->GetStatus() == FLASH_PAUSED) pFlash->Resume(); } break; default: break; } RequestRedraw(); }

Double-tap motions are reported to the application in the IMotionEventListener::OnDoubleTapDetected() method. In this recipe the double-tap motion is used to show or hide the flash animation. When this event is received the flash control is either shown or hidden, depending on the current state:

15_974018-gr03.indd 32415_974018-gr03.indd 324

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

325

void MainForm::OnDoubleTapDetected(void) { if(pFlash->GetShowState() == true) pFlash->SetShowState(false); else pFlash->SetShowState(true); RequestRedraw(); }

Snap motions are reported to the application in the IMotionEventListener::OnSnapDetected() method. In this recipe the snap motion is used to move or change the size of the Flash animation on the display. When the snap event is received the snapType parameter is checked to determine the plane in which the snap motion has been made: ■■

If the device has been moved in the x-plane, the flash animation’s x-coordinate is either incremented or decremented by 20 pixels, depending on the direction (positive or negative) of the snap motion.

■■

If the device has been moved in the y-plane, the flash animation’s y-coordinate is either incremented or decremented by 20 pixels, depending on the direction (positive or negative) of the snap motion.

■■

If the device has been moved in the z-plane, the flash animation’s size is either incremented or decremented by 20 pixels, depending on the direction (positive or negative) of the snap motion.

void MainForm::OnSnapDetected(Osp::Uix::MotionSnapType snapType) { Point currentPosition = pFlash->GetPosition(); Dimension currentSize = pFlash->GetSize(); switch(snapType) { case MOTION_SNAP_X_POSITIVE: pFlash->SetPosition(Point(currentPosition.x+20, currentPosition.y)); break; case MOTION_SNAP_X_NEGATIVE: pFlash->SetPosition(Point(currentPosition.x-20, currentPosition.y)); break; case MOTION_SNAP_Y_POSITIVE: pFlash->SetPosition(Point(currentPosition.x, currentPosition.y+20)); break; case MOTION_SNAP_Y_NEGATIVE: pFlash->SetPosition(Point(currentPosition.x, currentPosition.y-20)); break; case MOTION_SNAP_Z_POSITIVE: pFlash->SetSize(Dimension(currentSize.width+20, currentSize.height+20)); break;

15_974018-gr03.indd 32515_974018-gr03.indd 325

8/31/10 12:40 AM8/31/10 12:40 AM

326

Part II



Recipes

case MOTION_SNAP_Z_NEGATIVE: pFlash->SetSize(Dimension(currentSize.width-20, currentSize.height-20)); break; default: break; } RequestRedraw(); }

Orientation-changed events are reported to the application in the IOrientationEventListener::OnOrientationChanged() method. In this recipe the orientation-changed event causes a display redraw request to be made, so that the MainForm is drawn correctly for the selected orientation: void MainForm::OnOrientationChanged(const Control &source, OrientationStatus orientationStatus) { RequestRedraw(); }

Hints, Pitfalls, and Related Topics Motion events and orientation changes can be tested on the Simulator as well as on the device. The motion events can be simulated by using the Event Injector. The Event Injector can be launched by right clicking on the Simulator and selecting Event Injector. The motion event buttons are located within the Accelerometer tab on the Sensors tab. Figure R3.1 shows the motion event options in the Event Injector. Rotation events can be simulated by right-clicking on the Simulator and selecting Rotate and then selecting the option for whichever rotation is required (e.g. Landscape). An application will only respond to these motion and orientation-change events if the relevant event listeners and event handling functions have been implemented, as described in this recipe. If an application has been developed that detects and handles the motion double-tap event and implements functionality for the double-pressed touch event, the following behaviour will occur: ■■

If the user double-taps the screen gently, only the double-pressed touch event will be generated and processed.

■■

If the user double-taps the screen firmly (so that the accelerometer detects the taps), both the double-pressed touch event and the motion double-tap events will be generated and processed.

■■

If the user double-taps any other part of the device, the motion doubletap events will be generated and processed as expected.

15_974018-gr03.indd 32615_974018-gr03.indd 326

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

327

Figure R3.1 Event Injector – motion events.

This behaviour should be considered when designing an application’s response to both motion and touch events.

Related Recipe ■■

Add a Form to a Frame-based App

Recipe 3.2: Get Device Orientation from the Magnetometer (Compass) Problem Description You want to obtain data from the magnetometer (compass sensor) to interpret that information for various applications (e.g. determine device orientation or metal detection).

The Recipe The following configuration is required for this recipe:

15_974018-gr03.indd 32715_974018-gr03.indd 327

8/31/10 12:40 AM8/31/10 12:40 AM

328

Part II



Recipes

Namespaces used: Osp::Uix

Header files to #include:

FUixSensorManager.h, FUixSensorTypes.h

Required libraries: FUix

Required privilege level: Normal

Required privilege groups: None

This recipe is related to the namespace Osp::Uix. Uix stands for UI extension, which provides additional novel ways for the user to interface with a device. These are not covered in basic UIs. Traditional UI approaches mostly depend on oral or visual input and output for providing information, or they take commands or information from the user through buttons. UI extension is intended to improve the user’s experience in interacting with a mobile phone. This recipe covers one particular part of that namespace. It makes use of the magnetometer (magnetic sensor). This sensor is a three-axis electronic compass that can also be used for determining the orientation. The magnetic sensor measures the magnetic field strength. The measurements are split into the X, Y, and Z axis and the unit is Micro-Tesla (μT). Note that several factors can have an impact on the data coming from this sensor: weather, your current location on the planet, and, most influentially, nearby magnetic fields, such as magnets or electric coils. The magnetic sensor uses the phone as a fixed frame of reference as indicated in Figure R3.2, and models this into the three-axis Cartesian space coordinate system.

Figure R3.2 Magnetic field related to the device.

15_974018-gr03.indd 32815_974018-gr03.indd 328

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

329

For this example we use the SensorManager class and the ISensorEventListener interface, both from the namespace Osp::Uix. The SensorManager class provides the functionality for adding and removing sensor listeners, checking if a sensor is available, setting intervals, and getting the maximum and minimum intervals. A bada device can have various physical sensors (e.g. an acceleration sensor or proximity sensor). The SensorManager supports simple access to built-in sensors in a device. By registering a listener to the SensorManager, an application can get sensor data with a timestamp based on definable intervals. In our example we define a class that inherits from the ISensorEventListener interface. Below is a sample header file that contains all the signatures for the methods we show in this recipe. //… class YourClassName : public Osp::Uix::ISensorEventListener { private: Osp::Uix::SensorManager sensorMgr; // … public: // … bool RegisterSensor(); bool UnRegisterSensor(); void OnDataReceived(Osp::Uix::SensorType sensorType, Osp::Uix::SensorData& sensorData, result r); private: void DrawArrow(); float GetDegree(float rad); float CalculateAngle(float f1, float f2); };

Because we inherit from an interface, we need to overwrite the respective method with the following signature: void OnDataReceived(Osp::Uix::SensorType sensorType, Osp::Uix::SensorData& sensorData, result r);

The implementation of our class also provides two methods that help to resister and unregister a sensor type. bool RegisterSensor() { result r = E_SUCCESS; // Construct the sensor manager instance r = sensorMgr.Construct(); if(IsFailed(r))

15_974018-gr03.indd 32915_974018-gr03.indd 329

8/31/10 12:40 AM8/31/10 12:40 AM

330

Part II



Recipes

{ return false; } long interval = 0; // Activate the sensor type SENSOR_TYPE_MAGNETIC r = sensorMgr.GetMinInterval(SENSOR_TYPE_MAGNETIC, interval); if(IsFailed(r)) { return false; } if (interval < 50) { interval = 50; } // Register our listener to this sensor r = sensorMgr.AddSensorListener(*this, SENSOR_TYPE_MAGNETIC, interval, false); if(IsFailed(r)) { return false; } return true; }

bool UnRegisterSensor() { result r = E_SUCCESS; // Deactivate our compass sensor r = sensorMgr.RemoveSensorListener(*this); if(IsFailed(r)) { return false; } return true; }

In the body of the overwritten OnDataReceived() method we get the X, Y, and Z values and can process them as needed. In this example we simply calculate the 3D vector of the Earth’s magnetic field (assuming that there are no other sources of severe interference). For this purpose we have defined a member of type float called magField into which we store the length of this vector. Void OnDataReceived(Osp::Uix::SensorType sensorType, Osp::Uix::SensorData& sensorData, result r) { float x=0, y=0, z=0; AppLog(“DataReceived: Get Magnetic Sensor Data”);

15_974018-gr03.indd 33015_974018-gr03.indd 330

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

331

sensorData.GetValue((SensorDataKey)MAGNETIC_DATA_KEY_X, x); sensorData.GetValue((SensorDataKey)MAGNETIC_DATA_KEY_Y, y); sensorData.GetValue((SensorDataKey)MAGNETIC_DATA_KEY_Z, z); // Calculate the length of our vector determined by the three axis magField = Math::Sqrt((Math::Pow(x,2)+ Math::Pow(y,2)+ Math::Pow(z,2))); }

Hints, Pitfalls, and Related Topics Once your code compiles without errors, you can run it in the Simulator. A very convenient feature of the bada Simulator is the Event Injector tool. To get this, right-click the Simulator screen, select the Event Injector, and choose the Sensors tab. In the row below choose the Magnetic tab. There you can freely choose the μ;T values per X, Y, and Z axis. Click on the Send button to send these as events to your application running on the bada Simulator. This tool is very useful for testing. For some use-cases you might be interested in getting the angle between two vectors. The following code snippet should help: float CalculateAngle(float f1, float f2) { float angle = 0; // angle in rad if (f1==0 && f2==0){ angle = 0; return angle; }else{ angle = Math::Asin(f1 / Math::Sqrt((Math::Pow(f1,2) + Math::Pow(f2,2)))); } return angle; }

The SDK calculates the angle in rad. For converting this into degrees you may find the following code useful: float GetDegree(float rad) { return Math::Abs(rad * 180/Math::GetPi()); }

15_974018-gr03.indd 33115_974018-gr03.indd 331

8/31/10 12:40 AM8/31/10 12:40 AM

332

Part II



Recipes

Recipe 3.3: Get Readings from the Tilt Sensor Problem Description You want to make use of the azimuth, pitch, and roll values from tilt sensor and display them on the screen.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Uix

Header files to #include: FUi.h, FUix.h

Required libraries:

FUi, FUiControls, FUix

Required privilege level: None.

Required privilege groups: None

The tilt sensor measures the angle of your mobile device at each position. The sensor combines acceleration and magnetic sensor to determine values of azimuth, pitch, and roll (see Figure R3.3). The range of values that the tilt sensor supports are shown in Table R3.1. Table R3.1 Range of values supported by the tilt sensor Measurement

Type

Range

Unit

Timestamp

long



Milliseconds

Azimuth

float

Max. value = 360

Degrees (°)

Min. value = 0 Pitch

float

Max. value = +180

Degrees (°)

Min. value = -180 Roll

float

Max. value = +180

Degrees (°)

Min. value = -180

These are angular positions based on a fixed frame reference.

15_974018-gr03.indd 33215_974018-gr03.indd 332

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

333

Figure R3.3 Azimuth, pitch and roll.

In this recipe we are going to: 1. Construct a base Form and Label. 2. Construct the SensorManager and add the required listener for tilt sensor. 3. Inherit from the ISensorEventListener interface. 4. Implement the OnDataReceived() method. As a result, the values of the tilt sensor will be displayed on the screen (see Figure R3.4).

Figure R3.4 Values of the tilt sensor on the Simulator.

15_974018-gr03.indd 33315_974018-gr03.indd 333

8/31/10 12:40 AM8/31/10 12:40 AM

334

Part II



Recipes

To display sensor values that we get from the ISensorEventListener, we’ll start with a frame-based application project in the bada IDE. Our Tilt class is defined as follows: class Tilt : public Osp::App::Application, public Osp::System::IScreenEventListener, public Osp::Uix::ISensorEventListener //inherit ISensorEvent Listener { public: // [Tilt] application must have a factory method that creates an instance of itself. static Osp::App::Application* CreateInstance(void); public: Tilt(); ~Tilt(); Osp::Ui::Controls::Form* pForm; Osp::Ui::Controls::Label* pLabel; Osp::Base::String str;

//Form //Label for display //String for text

Osp::Uix::SensorManager* SManager;

//Sensor manager

//a float for each value float azimuth; float pitch; float roll; public: bool OnAppInitializing(Osp::App::AppRegistry& appRegistry); // Called when the application is terminating. bool OnAppTerminating(Osp::App::AppRegistry& appRegistry, bool forcedTermination = false); // for readability we leave out the other member methods // // ...

// callback function to receive sensor data virtual void OnDataReceived(Osp::Uix::SensorType sensorType, Osp::Uix::SensorData& sensorData , result r); };

The OnDataReceived() method is called when the sensor manager receives sensor data. There are several sensor types available. Here, we focus on the use of the tilt sensor. For this, we select the tilt type (SENSOR_TYPE_TILT) as argument. The following code snippet is a basic Form and a Label for displaying each value of the tilt sensor in OnAppInitializing():

15_974018-gr03.indd 33415_974018-gr03.indd 334

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

335

pForm = new Form(); pForm->Construct(FORM_STYLE_NORMAL); GetAppFrame()->GetFrame()->AddControl(*pForm); pLabel = new Label; pLabel->Construct(pForm->GetClientAreaBounds(),L”Empty”); pForm->AddControl(*pLabel); pLabel->SetTextHorizontalAlignment(ALIGNMENT_CENTER); pLabel->SetTextVerticalAlignment(ALIGNMENT_MIDDLE); pLabel->SetTextColor(Color::COLOR_WHITE); pLabel->SetBackgroundColor(Color::COLOR_BLACK);

To get tilt sensor data we need to add a listener of type SENSOR_TYPE_ TILT to the SensorManager. First, we need to construct the SensorManager object: SManager = new SensorManager(); SManager->Construct(); long interval=10; SManager->AddSensorListener(*this,SENSOR_TYPE_TILT,interval,false);

The AddSensorListener() method has many arguments that can be passed, as its method signature indicates: result AddSensorListener(const ISensorEventListener& listener, SensorType sensorType, long interval, bool dataChanged);

The first argument is const ISensorEventListener& listener and is an object that implements the ISensorEventListener interface. In our code example, the class implements the listener itself so that a pointer to *this can be used. The second argument is SensorType sensorType and represents the sensor type such as tilt or magnetic. In this code it is set to SENSOR_ TYPE_TILT to get tilt sensor data. The third argument is the interval that defines the time period after which sensor value updates happen. The unit is millisecond. The last argument is the bool dataChanged, which is the condition necessary to invoke OnDataReceive(). If true, OnDataReceive() is called when a value from the sensor is changed. If false, it is called on the defined interval of time. Finally, let us look at the implementation of the OnDataReceived() method, which is the callback function to receive data from the sensor manager. The OnDataReceived() method is called when the sensor receives sensor data. In this code it receives of tilt sensor data through AddSensorListener. This code snippet shows the output of the sensor values simply as a string in Label UI control:

15_974018-gr03.indd 33515_974018-gr03.indd 335

8/31/10 12:40 AM8/31/10 12:40 AM

336

Part II



Recipes

void Tilt::OnDataReceived(SensorType sensorType, SensorData& sensorData, result r) { if(sensorType==SENSOR_TYPE_TILT) { sensorData.GetValue((SensorDataKey)TILT_DATA_KEY_AZIMUTH, azimuth); sensorData.GetValue((SensorDataKey)TILT_DATA_KEY_PITCH, pitch); sensorData.GetValue((SensorDataKey)TILT_DATA_KEY_ROLL, roll); } str.Format(100,L”azimuth : %f\npitch : %f\nroll : %f\n-The Tilt” ,azimuth,pitch,roll); pLabel->SetText(str); pForm->Draw(); pForm->Show(); }

If the sensorType matches with SENSOR_TYPE_TILT, we can get sensor values via the GetValue() interface, which is a member method of the SensorData class. As you can see in this code, the first argument of GetValue() needs to be cast into SensorDataKey. Each sensor has an identical value as data key. A type conversion is necessary because it is not possible to use each sensor key directly in the method. You can use the Event Injector to simulate tilt sensor values for testing if you do not have a real mobile device available.

Hints, Pitfalls, and Related Topics Note that when you set the interval value for each sensor it should always be smaller then the maximum value and larger than the minimum value, otherwise you will encounter unexpected behaviours. There is a convenient API for finding out the maximum and minimum values of each sensor using one of the following methods: result Osp::Uix::SensorManager::GetMinInterval (SensorType sensorType, long& interval); result Osp::Uix::SensorManager::GetMaxInterval (SensorType sensorType, long& interval);

15_974018-gr03.indd 33615_974018-gr03.indd 336

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

337

Recipe 3.4: Detect a Face from Video Problem Description You want to detect a face that appears on a video stream from the camera preview.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls ,Osp::Uix, Osp::Media

Header files to #include: FUi.h, FUix.h FMedia.h

Required libraries:

FUi, FUiControls FUix FMedia

Required privilege level: Normal (Media::Camera)

Required privilege groups: CAMERA

In this recipe we take a look at the face detection functionality of bada to find the position of a face within a video stream. The FaceDetector class enables you to find a face in a still image or video stream. A maximum of five different faces can be detected at one time. We can, however, handle the number of face detections by using the SetProperty() method. To use a video stream, we must construct and use an object of type Camera. The manifest file must have the privilege set, which allows access to the camera device. So, when you generate the manifest file, make sure you set the CAMERA privilege. The recipe ‘Recognise a Face’ shows how to use the face recognition API after a face has been detected. In this recipe, we show you how to find a face on a video and draw rectangle around the face. The steps are as follows: 1. Set the orientation to landscape. 2. Construct a FaceDetector object. 3. Construct the Camera object and invoke PowerOn(). 4. Construct an OverlayPanel to display the video stream. 5. Set the resolution and PixelFormat accordingly.

15_974018-gr03.indd 33715_974018-gr03.indd 337

8/31/10 12:40 AM8/31/10 12:40 AM

338

Part II



Recipes

6. Invoke StartPreview() of Camera and do not forget to turn the Camera off. 7. Implement the OnCameraPreviewed() method. After we have successfully built and run the project, faces should be recognised in the video stream (indicated by the box effect in Figure R3.5).

Figure R3.5 Detect a face from video on the Simulator.

The code snippet below represents the declaration (header file) of our main class, which we have called Form1. It derives from the class Form and the interfaces Osp::Ui::IActionEventListener and Osp::Media::ICameraEventListener. class Form1 public public public {

: Osp::Ui::Controls::Form, Osp::Ui::IActionEventListener, Osp::Media::ICameraEventListener

//camera listener

// Construction public: Form1(void); virtual ~Form1(void); bool Initialize(void); // Implementation protected: Osp::Ui::Controls::OverlayPanel* pPanel; Osp::Media::Camera* pCamera ; Osp::Graphics::BufferInfo bufferInfo; Osp::Uix::FaceDetector* pFDetect; Osp::Graphics::PixelFormat format; Osp::Graphics::Dimension resolution; Osp::Graphics::Rectangle* pRect;

//for displaying

//camera format //camera resolution //rectangle for face

public: result OnInitializing(void); result OnTerminating(void); void OnActionPerformed(const Osp::Ui::Control& source, int actionId); // the below 4 functions are of ICameraEventListener

15_974018-gr03.indd 33815_974018-gr03.indd 338

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

339

void OnCameraAutoFocused(bool completeCondition); void OnCameraPreviewed(Osp::Base::ByteBuffer& previewedData, result r); void OnCameraErrorOccurred(Osp::Media::CameraErrorReason r); // Get the preview data of Camera void OnCameraCaptured (Osp::Base::ByteBuffer& capturedData, result r); };

In the C++ source file we first have to set the screen layout to landscape orientation: bool Form1::Initialize() { // Construct a Form control Construct(FORM_STYLE_NORMAL||FORM_STYLE_TITLE); SetOrientation(ORIENTATION_LANDSCAPE); return true; }

Now we switch to the OnInitializing() method. We first construct the FaceDetector with two-phase construction: pFDetect = new FaceDetector(); pFDetect->Construct();

Bear in mind that a primary camera and a secondary camera are available as options. In this recipe we only use the primary camera, which is the camera on the back of the device. After constructing the Camera, we invoke PowerOn() to start up the hardware. Then we create a rectangle, which we use to construct the OverlayPanel. Our BufferInfo object holds data from the camera that is then shown in the OverlayPanel. pCamera = new Camera(); pCamera->Construct(*this,CAMERA_PRIMARY); pCamera->PowerOn(); Rectangle rect=GetClientAreaBounds(); //rectangle for OverlayPanel pPanel = new OverlayPanel(); pPanel->Construct(rect); pPanel->GetBackgroundBufferInfo(bufferInfo); //enable to display AddControl(* pPanel);

Next, we set the resolution and format for the preview. The pixel format and resolution will be stored as member variables for reuse in OnCamera Previewed(). pCamera->SetPreviewResolution(*pPreviewResolution); pCamera->SetPreviewFormat(pixelFormat);

15_974018-gr03.indd 33915_974018-gr03.indd 339

8/31/10 12:40 AM8/31/10 12:40 AM

340

Part II



Recipes

Now, we want to check whether the format and resolution of the video are supported. In our snippet, the maximum resolution should be the last element in the list we get directly from the camera. With regard to pixelFormat, we can assume that each device has at least one format, so we select the first element. IList* pPreviewResolutionList = null; IListT* pPreviewFormatList = null; pPreviewResolutionList = pCamera-> GetSupportedPreviewResolutionListN(); // supported max resolution Dimension* pPreviewResolution = (Dimension*)pPreviewResolutionList->GetAt( pPreviewResolutionList->GetCount()-1 ); pPreviewFormatList = pCamera->GetSupportedPreviewFormatListN(); PixelFormat pixelFormat; pPreviewFormatList->GetAt(0, pixelFormat); //first element

pCamera->SetPreviewResolution(*pPreviewResolution); pCamera->SetPreviewFormat(pixelFormat);

resolution = *pPreviewResolution; format = pixelFormat;

//store in member variable

Then we invoke the preview of the camera by issuing the StartPreview() method. Its first argument holds a data buffer for the camera preview. The second argument is a bool, where true means to trigger the callback function OnCameraPreviewed(). False would disable this callback function. pCamera->StartPreview(&bufferInfo, true);

If you are using the camera preview, make sure that you turn it off when your app is terminating in the OnTerminating() method as shown below: result Form1::OnTerminating(void) { result r = E_SUCCESS; if(r = pCamera->GetState() == CAMERA_STATE_PREVIEW) { pCamera->StopPreview(); pCamera->PowerOff(); delete pCamera; } return r; }

15_974018-gr03.indd 34015_974018-gr03.indd 340

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

341

Finally, we implement our detection logic in the OnCameraPreviewed(). In this callback method a rectangle should be drawn that surrounds the face detected by the FaceDetector from the camera preview (i.e. the ByteBuffer previewedData). For this we invoke the DetectFacesFromVideoStreamN (previewedData, resolution, format) method from our member pFDetect object. This method returns positions of faces in a list. After a cast you can get rectangles out of this list. In the code below we slightly shift the position of x to adjust it to the actual coordinate position on the OverlayPanel. We also set the background to clear by using transparent colour. Then we draw the rectangle: void Form1::OnCameraPreviewed(ByteBuffer& previewedData, result r) { IList* pList = pFDetect->DetectFacesFromVideoStreamN (previewedData, resolution, format); if(pList->GetCount()>0) { pRect = (Rectangle *)pList->GetAt(0); pRect->x += 80; Canvas* pCan = GetCanvasN(); pCan->SetBackgroundColor(Color(0,0,0,0)); pCan->Clear(); pCan->DrawRectangle(*pRect); pCan->Show(); delete pCan; } if(pList!=null) { pList->RemoveAll(true); delete pList; pList = null; } }

Hints, Pitfalls, and Related Topics Let’s have a more in-depth look at the StartPreview() method of the Camera class and its options. There are two arguments: the first is the buffer that holds the data coming from the camera and the second is a bool primitive, which enables or disables the callback function OnCameraPreviewed(). So, there are four combinations possible, as shown in Table R3.2.

15_974018-gr03.indd 34115_974018-gr03.indd 341

8/31/10 12:40 AM8/31/10 12:40 AM

342

Part II



Recipes

Table R3.2 Four options for the StartPreview()method Case

Camera state

Preview

Callback

StartPreview (OverlayPanel, callback)

Previews are displayed automatically

Call-back N/A is called to process data

StartPreview (no Overlay Panel, no callback)

No preview is displayed

You can use this case to take No callback is pictures in a power-saving called to mode. process data

StartPreview (OverlayPanel, no callback)

Previews are displayed automatically

Only the visuals are working. No callback is called to process data

No preview is displayed

Call-back is called to process data

Camera is in PowerOn

StartPreview (no Overlay Panel, callback)

notes

Even though no picture is shown, you can manually display one through the OnCameraPreviewed() event handler. Get the buffer information through Ui::Controls:: Overlay Panel::GetBackground BufferInfo(). The application must set the callback parameter to true so that the preview data is sent to the event handler.

Related Recipe ■■

Recognise a Face

Recipe 3.5: Recognise a Face Problem Description Given an image of a face, you want to determine whether this face is present in the camera’s previewed video stream.

The Recipe The following configuration is required for this recipe:

15_974018-gr03.indd 34215_974018-gr03.indd 342

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

343

Namespaces used:

Osp::Base::Collection, Osp::Uix, Osp::Media, Osp::Graphics

Header files to #include: FUix.h, FMedia.h

Required libraries: FUix, FMedia

Required privilege level: Normal

Required privilege groups: CAMERA, IMAGE

Facial recognition software is becoming more and more popular, as users demand more advanced applications to speed up tasks such as tagging friends in photos. Handily, the bada platform includes an in-built class to perform face recognition and comparison. This recipe details the steps needed to set up and make use of the FaceRecognizer class. The target application analyses a face from a still image, and then analyses each frame from a video (in this case supplied by the device’s camera preview) to check if any of the faces in the video match the one in the image. The recipe assumes that the user has set up a Camera object, as detailed in the recipe ‘Open the Camera and Get and Display Live Frames’, and has created a bitmap of the still image as detailed in the recipe ‘Use Bitmaps and Images’. An OverlayPanel is not required for this recipe but could be useful for testing the target application – see the recipe ‘Use an Overlay Panel’. The key class in our recipe is the MainForm class, which will control all the features in the recipe. The class must implement the OnCameraPreviewed() method from Osp::Media::ICameraEventListener in order to perform face recognition on each frame. This method, together with the OnInitializing() method, will be where the recipe does most of its processing. The following class declaration shows the basic functionality needed by a facial recognition application: class MainForm : public Osp::Ui::Controls::Form, public Osp::Media::ICameraEventListener { public: MainForm(void); virtual ~MainForm(void); bool Initialize(void); protected: // Face recognizer members Osp::Uix::FaceRecognizer* pFaceRecognizer; Osp::Uix::FaceRecognitionInfo* pTargetFaceInfo; // Camera data members

15_974018-gr03.indd 34315_974018-gr03.indd 343

8/31/10 12:40 AM8/31/10 12:40 AM

344

Part II



Recipes

Osp::Media::Camera* pCamera; Osp::Graphics::PixelFormat cameraFormat; Osp::Graphics::Dimension cameraResolution; public: result OnInitializing(void); result OnTerminating(void); // These functions override those in ICameraEventListener void OnCameraAutoFocused(bool completeCondition); void OnCameraPreviewed(Osp::Base::ByteBuffer &previewedData, result r); void OnCameraErrorOccurred(Osp::Media::CameraErrorReason r); void OnCameraCaptured(Osp::Base::ByteBuffer &capturedData, result r); };

The creation and configuration of the FaceRecognizer object should be performed during the OnInitializing() method. For performing face recognition on the image, the FaceRecognizer is configured to look for only one face, and to set the scale to the value 1. This allows detection of the smallest faces, at the expense of more processing power. As the video stream might contain more than one face, the recipe should check as many faces as possible against the target face. This is done using the GetRange() method to get information about the acceptable range of the MAXNUMBER_VIDEO property, and then set this property to its maximum value. The scale is set to the value 2 (the middle value), which is a trade-off between processing time and minimum face size. result MainForm::OnInitializing(void) { /* Setup the camera.... */ // Create a FaceRecognizer object and set its properties. pFaceRecognizer = new FaceRecognizer(); pFaceRecognizer->Construct(); pFaceRecognizer->SetProperty(FACERECOGNIZER_MAXNUMBER_IMAGE, 1); pFaceRecognizer->SetProperty(FACERECOGNIZER_SCALE_IMAGE, 1); long minFaces, maxFaces, step, initial; pFaceRecognizer->GetRange(FACERECOGNIZER_MAXNUMBER_VIDEO, minFaces, maxFaces, step, initial); pFaceRecognizer->SetProperty(FACERECOGNIZER_MAXNUMBER_VIDEO, maxFaces); pFaceRecognizer->SetProperty(FACERECOGNIZER_SCALE_VIDEO, 2);

Next the recipe needs to perform face recognition on the still image that is pointed to by pBitmap. The various ExtractFaceInfo...() methods will always return a pointer to an IList object, even if only one face is detected. In order to get a pointer to the FaceRecognitionInfo object the GetAt() method is called on the first (and only) element in the list, which is then cast to the correct type. // Perform face recognition on the bitmap image, // and get a pointer to the result.

15_974018-gr03.indd 34415_974018-gr03.indd 344

8/31/10 12:40 AM8/31/10 12:40 AM

Group 3



Extended UI and Sensors

345

IList* pTargetList = null; pTargetList = pFaceRecognizer->ExtractFaceInfoFromStillImageN( *pBitmap); pTargetFaceInfo = static_cast (pTargetList->GetAt(0));

The last thing the recipe needs to do in OnInitializing() is to store the resolution and image format of the camera preview in member variables, because these variables are needed for every call to ExtractFaceInfoFromVideo StreamN(), that is, once per frame. Finally, the StartPreview() method is called with its second argument as true – enabling the OnCameraPreviewed() callback routine. // Get the camera parameters now, // to avoid doing this every frame. cameraResolution = pCamera->GetPreviewResolution(); cameraFormat = pCamera->GetPreviewFormat(); // Start the preview with callback but no OverlayPanel. pCamera->StartPreview(null, true);

}

return r; // End of MainForm::OnInitializing()

In this recipe the facial comparisons are done in the OnCameraPreviewed() callback routine, which is called when a new frame is available. The first task is to call the FaceRecognizer’s ExtractFaceInfoFromVideoStreamN() method and get a list of FaceRecognitionInfo objects. As this method has an ‘N’ postfix, the FaceRecognitionInfo objects must be de-allocated when they are no longer required (at the end of OnCameraPreviewed()), or the memory will be leaked. Once the face list has been populated, the FaceRecognitionInfo objects can be taken from the list using GetAt() and compared with the TargetFaceInfo that was obtained earlier via the IsMatching() method of FaceRecognizer. As this takes place within a callback routine, you should not invoke lengthy processing methods. To stop the routine from being called again invoke the Camera::StopPreview() method. void MainForm::OnCameraPreviewed(Osp::Base::ByteBuffer &previewedData, result r) { // Get a list containing all the FaceRecognitionInfo // objects in the video stream. IList* pFaceList = null; pFaceList = pFaceRecognizer->ExtractFaceInfoFromVideoStreamN( previewedData, cameraResolution, cameraFormat); // For each FaceRecognitionInfo object, // compare it to our target face. FaceRecognitionInfo* pThisFace; for (int i = 0; i < pFaceList->GetCount(); i++) { pThisFace = static_cast

15_974018-gr03.indd 34515_974018-gr03.indd 345

8/31/10 12:40 AM8/31/10 12:40 AM

346

Part II



Recipes (pFaceList->GetAt(i)); if (pFaceRecognizer->IsMatching(*pTargetFaceInfo, *pThisFace)) { // We’ve found the target face // Perform desired output here. }

} // Deallocate the instances of FaceRecognitionInfo // that we don’t want any more. pFaceList->RemoveAll(true); }

Hints, Pitfalls, and Related Topics In this recipe it has been assumed that the device in question is able to devote a large chunk of its processor time to the methods in the FaceRecognizer class and consequently that the recipe can process the maximum number of faces at a medium scale. In reality, of course, these methods may have to share processor time with other computationally demanding application features such as video processing and display. Developers should therefore pay close attention to the time taken to execute the face recognition methods, and consider adjusting the properties of the FaceRecognizer if this time is excessive for the application in question. This could be done by reducing the maximum number of faces to look for or increasing the value of the Scale property to stop the FaceRecognizer looking for smaller faces. Caution should be exercised after calls to the various ExtractFaceInfo...() methods, because these methods have the postfix ‘N’. The caller must make sure that the returned instances (in this case the FaceRecognitionInfo objects) are deleted once they are no longer of use. Users should bear in mind that simply deleting the IList of the objects will just delete the pointers and not the objects themselves. The FaceRecognizer is designed to use information obtained from previous frames in determining where to look for faces in a video stream. Therefore, the first five calls to ExtractFaceInfoFromVideoStreamN() will return null, even if faces are present in the video. Users should take care not to construct a new FaceRecognizer every frame; otherwise their application may not detect any faces at all.

Related Recipes ■■

Detect a Face from Video

■■

Open the Camera and Get and Display Live Frames

■■

Use Bitmaps and Images

■■

Use an Overlay Panel

15_974018-gr03.indd 34615_974018-gr03.indd 346

8/31/10 12:40 AM8/31/10 12:40 AM

GROUP

4 Multimedia Content

Recipe 4.1: Use Bitmaps and Images Problem Description You want to download an image and save it to file or display it on the screen.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Media, Osp::Graphics, Osp::Content, Osp::Base::Utility

Header files to #include:

FUi.h, FUiControls.h, FMedia.h, FGraphics.h, FContent.h, FBase.h

Required libraries:

FUi, FUiControls, FMedia, FGraphics, FContent, FBase

Required privilege level: Normal

Required privilege groups: IMAGE, LOCAL_CONTENT

347

16_974018-gr04.indd 34716_974018-gr04.indd 347

8/31/10 12:41 AM8/31/10 12:41 AM

348

Part II



Recipes

The Osp::Media namespace provides an Image class that can be used for decoding, encoding, converting, and compressing images. It is used by applications in conjunction with the Osp::Graphics namespace’s Bitmap class. The Bitmap class encapsulates a bitmap that consists of the pixel data for an image and its attributes. This recipe shows two examples for using the Image and Bitmap classes within an application. Each method details the steps required to create and use image and bitmap data, and provides some sample code snippets. Both examples in this recipe assume the steps detailed in the recipe ‘Add a Form to a Frame-based App’ (which you can find in the second group of recipes, “UI Basics”) have been followed to add a Form to the Application’s Frame.

Example 1: Downloading Image from a Remote URL and Saving it to the Filesystem This recipe downloads a JPEG image file from a remote location and saves it to the /Media/Images/ folder in the device’s filesystem. The Image class provides functionality to download an image file from a specified URL, so it is not necessary for the application to create and use a Web control for downloading the file. This DecodeUrl() method works asynchronously, so the Osp::Media::IImageDecodeUrlEventListener must be implemented to ensure that the decoding operates correctly. The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Media::IImageDecodeUrlEventListener { public: MainForm(void); ~MainForm(void); bool Initialize(void); protected: Osp::Graphics::Bitmap* pBmp; Osp::Media::Image* pImage; RequestId decodeRequestId; public: result OnInitializing(void); result OnTerminating(void); void

OnImageDecodeUrlReceived (RequestId reqId, Osp::Graphics::Bitmap *pBitmap, result r, const Osp::Base::String errorCode, const Osp::Base::String errorMessage);

};

16_974018-gr04.indd 34816_974018-gr04.indd 348

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

349

The creation of the image object and the request for downloading the image should be done in the OnInitializing() method: 1. Create a URI instance and set the image location string to be parsed into a URI. 2. Create and initialise an Image object. 3. Start the decode URL operation by calling the DecodeURL method with the following parameters: location of image file, bitmap pixel format, decoded bitmap dimensions, request ID, event listener interface, and the timeout period in milliseconds. Because the DecodeUrl() method is asynchronous, both the image object (created in step 2) and the request ID (step 3) must be defined as member variables of the class or as pointers so that they still exist after the OnInitializing() method has exited. Any memory allocated can be deleted in the MainForm class’s OnTerminating() method. The following code snippet is an example of code that would be added to the MainForm’s OnInitializing() method: // Create URI object and set image path Uri decodeURI; decodeURI.SetUri(String(L”http://www.pathtofile.com/file.jpg”)); // Create Image object pImage = new Image(); pImage->Construct(); // Request the retrieval of the image from remote URL pImage->DecodeUrl(decodeURI, BITMAP_PIXEL_FORMAT_ARGB8888, 400, 400, decodeRequestId, *this, Osp::Media::Image::TIMEOUT_INFINITE);

The IImageDecodeUrlEventListener interface class receives events associated with the DecodeUrl() operation. The OnImageDecodeUrlReceived() method notifies the application that the DecodeUrl() operation has completed and that the decoded bitmap has been downloaded from the remote location. In this recipe the following operations are performed in the OnImageDecodeUrlReceived() method: 1. Check the reported request ID is the same as the one returned by the original DecodeUrl() method. 2. Create a bitmap container and initialise it by copying the bitmap downloaded from the remote location into the container. 3. Create and initialise an image object. 4. Encode the bitmap data into a file: in this example the JPG file is encoded to a file located in the /Media/Images/ folder in the filesystem.

16_974018-gr04.indd 34916_974018-gr04.indd 349

8/31/10 12:41 AM8/31/10 12:41 AM

350

Part II



Recipes

5. Create a ContentManager instance and initialise it. 6. Create an ImageContentInfo instance and initialise it with the image file that has just been stored in the filesystem. 7. Create a content entry for the file in the content database. void MainForm::OnImageDecodeUrlReceived (RequestId reqId, Osp::Graphics::Bitmap *pBitmap, result r, const Osp::Base::String errorCode, const Osp::Base::String errorMessage) { if(reqId == decodeRequestId) { // Create bitmap pBmp = new Bitmap(); // Copy the bitmap pBmp->Construct(*pBitmap, Rectangle(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight())); // Create image object pImage = new Image(); pImage->Construct(); // Encode the bitmap to a file pImage->EncodeToFile(pBmp, IMG_FORMAT_JPG, String(L”/Media/Images/img1.jpg”), true); // Use Content Manager to add file to content database // so that image will appear in My files -> Images folder ContentManager contentManager; contentManager.Construct(); ImageContentInfo imageContent; imageContent.Construct(String(L”/Media/Images/img1.jpg”)); contentManager.CreateContent(imageContent); } }

The downloaded image file can now be found in the /My files/Images/ folder.

Example 2: Displaying a Bitmap from a Stored Image File This recipe retrieves a file from the filesystem and decodes it into a bitmap container for display on the screen. This recipe assumes that the specified file exists within the filesystem.

16_974018-gr04.indd 35016_974018-gr04.indd 350

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

351

The image decoding and display of the bitmap can be performed in the MainForm’s OnDraw() method: 1. Retrieve the window canvas. 2. Create and initialise an Image object. 3. Decode the specified image file into the bitmap container, specifying the bitmap pixel format. 4. Draw the decoded bitmap on the canvas at the position set using a Point object. The following code snippet is an example of code that would be added to the OnDraw() method. To create a canvas decode the image to a bitmap container and draw it on the screen: // Get the window canvas Canvas* pCanvas = GetCanvasN(); // Create image object pImage = new Image(); pImage->Construct(); // Decode image file into bitmap container pBmp = pImage->DecodeN(String(L”/Media/Images/img1.jpg”), BITMAP_PIXEL_FORMAT_ARGB8888); // Draw the bitmap pCanvas->DrawBitmap(Point(10, 400), * pBmp); // Delete canvas delete pCanvas;

Hints, Pitfalls, and Related Topics Although the Image class’s EncodeToFile() method will create a valid file in the filesystem, it is not visible to the user in the /My files/Images/ folder unless the ContentManager class is used to create a file in the content database. The LOCAL_CONTENT group privilege must be set in the application’s manifest file in order to use to the functionality of the ContentManager class. The IMAGE group privilege must be set in the application’s manifest file in order to use the functionality of the Image class. In this recipe, the GetCanvasN() and the DecodeN() methods are used in the OnDraw() method. Both these methods have an ‘N’ postfix, so to prevent memory leaks the caller must delete the returned instance after they are finished with the instance.

Related Recipe ■■

Add a Form to a Frame-based App

16_974018-gr04.indd 35116_974018-gr04.indd 351

8/31/10 12:41 AM8/31/10 12:41 AM

352

Part II



Recipes

Recipe 4.2: Draw Graphics Primitives Problem Description You want to draw graphics primitives on a canvas.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Media, Osp::Graphics, Osp::Base::Collection

Header files to #include:

FUi.h, FMedia.h, FGraphics.h, FBase.h

Required libraries:

FUi,FMedia,FGraphics, FBase

Required privilege level: Normal

Required privilege groups: IMAGE

Using the bada platform you can draw basic shapes, text and bitmaps on the screen using the Canvas class, which you can find in the namespace Osp::Graphics. This recipe details the steps required to create a canvas and describes the code that needs to be implemented to draw some basic shapes, text, and bitmaps on it. This recipe assumes the steps detailed in the recipe ‘Add a Form to a Framebased App’ have been followed to add a Form to the Application’s Frame. In this recipe the Form’s OnDraw() method is overridden, so that custom drawing can be performed on the window canvas. Prior to doing any drawing, we need to create a canvas on which to draw. In this recipe the canvas is created by retrieving the window canvas from the Form using the GetCanvasN() method. Additionally, background colours have to be set before clearing the display, and the line width and foreground colours can be set before drawing primitives. The following code snippet is an example of code that would be added to the OnDraw() method to create a canvas and initialise the drawing parameters: // Get the window canvas Canvas* pCanvas = GetCanvasN(); // Set line width

16_974018-gr04.indd 35216_974018-gr04.indd 352

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

353

pCanvas->SetLineWidth(2); // Set the bg and fg colours for drawing pCanvas->SetBackgroundColor(Color::COLOR_BLACK); pCanvas->SetForegroundColor(Color::COLOR_GREEN); // Clear canvas pCanvas->Clear();

Drawing Shapes Rectangles can be drawn with an outline or filled with colour, and with straight or rounded edges. The size and position of the rectangle is determined by the bounds of a Rectangle object. The width and height of the rounded edges of the rectangle are set using a Dimension object: // Draw rectangles pCanvas->DrawRectangle(Rectangle(10, 110, 60, 40)); pCanvas->FillRectangle(Color::COLOR_GREEN, Rectangle(80, 110, 60, 40)); // Draw rectangles with rounded edges pCanvas->DrawRoundRectangle(Rectangle(10, 200, 60, 40), Dimension(5,5)); pCanvas->FillRoundRectangle(Color::COLOR_GREEN, Rectangle(80, 200, 60, 40), Dimension(5,5));

Circles or ellipses can be drawn with an outline or filled with colour. The diameter and position of the circle or ellipse is determined by the bounds of a Rectangle object: // Draw circles pCanvas->DrawEllipse(Rectangle(150, 110, 40, 40)); pCanvas->FillEllipse(Color::COLOR_GREEN, Rectangle(200, 110, 40, 40));

Triangles can be drawn with an outline or filled with colour. The locations of the triangle vertices are set using Point objects: // Draw triangles pCanvas->DrawTriangle(Point(280, 110), Point(260, 150), Point(300, 150)); pCanvas->FillTriangle(Color::COLOR_GREEN, Point(330, 110), Point(310, 150), Point(350, 150));

Lines can be drawn between two points. The locations of the start and end points of the line are set using Point objects: // Draw line pCanvas->DrawLine(Point(0, 170), Point(480, 170));

Polygons can be drawn with an outline or filled with colour. The locations of the polygon vertices are set using an IList collection of Point objects:

16_974018-gr04.indd 35316_974018-gr04.indd 353

8/31/10 12:41 AM8/31/10 12:41 AM

354

Part II



Recipes

// Draw polygons IList* pIList1 = CreatePointListN(150, 200); pCanvas->DrawPolygon(*pIList1); delete pIList1; IList* pIList2 = CreatePointListN(220, 200); pCanvas->FillPolygon(Color::COLOR_GREEN, *pIList2); delete pIList2;

In this example, the CreatePointListN() method has been added to the MainForm class. This method creates a list of vertices for drawing a six-sided polygon, based on the position offsets passed in: Osp::Base::Collection::IList* MainForm::CreatePointListN(int xOffset, int yOffset) { IList* pPoints = new ArrayList(); pPoints->Add(*(new pPoints->Add(*(new pPoints->Add(*(new pPoints->Add(*(new pPoints->Add(*(new pPoints->Add(*(new

Point(20+xOffset, Point(10+xOffset, Point(20+xOffset, Point(40+xOffset, Point(50+xOffset, Point(40+xOffset,

0+yOffset))); 20+yOffset))); 40+yOffset))); 40+yOffset))); 20+yOffset))); 0+yOffset)));

return pPoints; }

Drawing Text The canvas object can also be used for drawing text. The location of the text to be drawn is set using a Point object: // Draw Text pCanvas->DrawText(Point(250, 260), L”text”);

Drawing Bitmaps The canvas object can be used for drawing bitmaps on the screen. In this example, the bitmap is created from an image file stored in the application’s resource directory: // Create a Bitmap and decode image Bitmap* pBadaBitmap = new Bitmap(); Image* pImage = new Image(); pImage->Construct(); pBadaBitmap = pImage->DecodeN(L”/Res/bada.png”, BITMAP_PIXEL_FORMAT_ARGB8888); pBadaBitmap->Scale(Dimension(80, 80));

A bitmap can be drawn on the canvas, with a Point object used to define the position of the top left corner of the bitmap:

16_974018-gr04.indd 35416_974018-gr04.indd 354

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

355

// Draw bitmap pCanvas->DrawBitmap(Point(10, 350), *pBadaBitmap);

A bitmap can also be displayed rotated about a pivot. In this example, the bitmap is drawn rotated about a pivot by 45 degrees counter-clockwise: // Draw rotated bitmap pCanvas->DrawBitmap(Point(100, 350), *pBadaBitmap, Point(0, 0), 45);

The pivot point is defined as the centre of the rotation and in this example, the pivot point (Point(0, 0)) is defined as the upper-left corner of the bitmap. At the end of the OnDraw() method all allocated instances have to be released: // Delete canvas delete pBadaBitmap delete pImage delete pCanvas;

The example shapes, text, and bitmaps described in this recipe are shown in Figure R4.1.

Figure R4.1 Drawing graphics.

16_974018-gr04.indd 35516_974018-gr04.indd 355

8/31/10 12:41 AM8/31/10 12:41 AM

356

Part II



Recipes

Hints, Pitfalls, and Related Topics In this recipe, the GetCanvasN() method is used in the OnDraw() method to retrieve the window canvas, and a new method CreatePointListN() is added to create a list of vertices for drawing a polygon. Both these methods have an ‘N’ postfix, so to prevent memory leaks the caller must delete the returned instance after they are finished with the instance.

Related Recipe ■■

Add a Form to a Frame-based App

Recipe 4.3: Open the Camera and Get and Display Live Frames Problem Description You want to start the camera and get live frames from it to display a live preview.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Media, Osp::Ui::Controls

Header files to #include: FUi.h, FMedia.h

Required libraries: FUi, FMedia

Required privilege level: Normal

Required privilege groups: CAMERA

To display a live camera preview in your application you must consider where the live preview will be played back. To use the camera, an OverlayPanel control must be used into which the camera frames are embedded. An OverlayPanel consists of two main components, a foreground layer and a background buffer. The background buffer is

16_974018-gr04.indd 35616_974018-gr04.indd 356

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

357

where the camera frames will be stored. The foreground layer of the OverlayPanel can be used to superimpose graphic controls over the camera preview if required. Because the OverlayPanel is a control, you will normally add it to a Form. The Osp::Media::Camera class is used to create a camera instance. The camera instance must be configured with a pointer to the OverlayPanel buffer. This recipe shows how to display a live preview of the camera full-screen on a bada device. 1. We need to set up for the camera preview display, as follows: // create camera form pCameraForm = new Form(); if (pCameraForm) { // construct the form to be of normal style with no visible // attributes pCameraForm->Construct(FORM_STYLE_NORMAL); // add the new created form the application’s Frame GetAppFrame()->GetFrame()->AddControl(*pCameraForm); } // Initialize the overlay panel pCameraPanel = new Osp::Ui::Controls::OverlayPanel(); pCameraPanel->Construct(Rectangle(0,0,480,800)); // Add camera OverlayPanel to form pCameraForm->AddControl(*pCameraPanel); #if defined(BUILD_FOR_TARGET) // if we are embedding the camera preview on the target device // it is necessary to rotate the overlay panel through 90 degrees Osp::Ui::Controls::OverlayPanel::Rotation rotate; rotate = Osp::Ui::Controls::OverlayPanel::ROTATION_90; pCameraPanel->SetRendererRotation(rotate); #endif

2. Now we can create a camera instance and connect it to the overlay panel via the background buffer: pPrimaryCamera = new Camera(); if (pPrimaryCamera) { // construct the camera instance to use the primary camera // also, the ‘this’ argument informs the application frame// work that the virtual methods associated with the // ICameraEventListener interface class are implemented within

16_974018-gr04.indd 35716_974018-gr04.indd 357

8/31/10 12:41 AM8/31/10 12:41 AM

358

Part II



Recipes

// this class pPrimaryCamera->Construct(*this, CAMERA_PRIMARY); // on the camera panel, we need to obtain the buffer info pCameraPanel>GetBackgroundBufferInfo(bufferInfo); // we can now power on the camera. Note, although powered on // we have not started the camera preview yet pPrimaryCamera->PowerOn(); }

3. Now that the camera is powered on, we can query and change a number of configurable attributes associated with the camera, although in many cases the defaults should be acceptable: ■■

preview resolutions supported;

■■

preview formats supported;

■■

Frame rates supported.

Each query synchronously returns a linked list, in which each entry is a relevant camera attribute that can be applied to the camera instance. For example, querying what frame rates the camera supports might result in a list being returned with the values 7, 15, and 30. Each of these values represents a value in ‘fps’ that can then be applied to the camera instance. The following code shows how to query the camera for its supported preview formats: pPreviewFormatList = pPrimaryCamera-> GetSupportedPreviewFormatListN(); if ( pPreviewFormatList != null ) { if ( pPreviewFormatList->Contains(PIXEL_FORMAT_YCbCr420_PLANAR)) { r = pPrimaryCamera-> SetPreviewFormat(PIXEL_FORMAT_YCbCr420_PLANAR); if (IsFailed(r)) { AppLog(“Setting preview format failed PIXEL_FORMAT_YCbCr420_PLANAR .”); return false; } } else if ( pPreviewFormatList->Contains(PIXEL_FORMAT_RGB565) ) { r = pPrimaryCamera->SetPreviewFormat(PIXEL_FORMAT_RGB565);

16_974018-gr04.indd 35816_974018-gr04.indd 358

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

359

if (IsFailed(r)) { AppLog(“Setting preview format failed - PIXEL_FORMAT_RGB565.”); return false; } } else { PixelFormat pixelFormat = PIXEL_FORMAT_MIN; pPreviewFormatList->GetAt(0, pixelFormat); r = pPrimaryCamera->SetPreviewFormat( pixelFormat ); if (IsFailed(r)) { AppLog(“Setting preview format failed - PIXEL_FORMAT_MIN.”); return false; } } pPreviewFormatList->RemoveAll(); delete pPreviewFormatList; pPreviewFormatList = null; }

4. As our camera instance is fully configured, we can enable the preview. Note that in this call we pass the address of the buffer info obtained from the OverlayPanel. This has the effect of linking the frames produced by the camera to the OverlayPanel in which they are displayed: r = pPrimaryCamera->StartPreview(&bufferInfo, false); if (E_SUCCESS == r) { // keep screen continuously lit with no dimming Osp::System::PowerManager::KeepScreenOnState(true, false); }

5. The false argument passed to the StartPreview() method indicates that the OnCameraPreviewed() method associated with the Osp::Media::ICameraEventListener class will not be called. If no processing of the frames created by the camera is required, this ability to not have the OnCameraPreviewed() can reduce the processing requirements of the application. 6. The Osp::Media::ICameraEventListener class provides an interface through which the camera can report events to the application. For example, the OnCameraPreviewed() callback allows the application to obtain a periodic byte buffer containing frames of the

16_974018-gr04.indd 35916_974018-gr04.indd 359

8/31/10 12:41 AM8/31/10 12:41 AM

360

Part II



Recipes

previewed data. The ICameraEventListener class provides the following event reporting methods: ■■

OnCameraPreviewed(): notifies periodically, after the Camera::StartPreview() method is called, at the speed of the camera’s frame rate so as to receive the preview data.

■■

OnCameraAutoFocused(): notifies when the Camera::SetAutoFocus() method is completed.

■■

OnCameraCaptured(): notifies when the Camera::Capture() method is completed.

■■

OnCameraErrorOccurred(): notifies that an error occurred in the camera, such as: ■■

CAMERA_ERROR_OUT_OF_MEMORY: insufficient memory;

■■

CAMERA_ERROR_DEVICE_FAILED: the camera device failed.

Hints, Pitfalls, and Related Topics It is advisable to implement the Osp::Media::ICameraEventListener class, even if you do not wish to process camera frames in the OnCameraPreviewed() method. This is simply because of the OnCameraErrorOccurred() method. At any time the camera could report an error. Implementing the ICameraEventListener interface class will allow to be informed of the error and take appropriate action. Only subscribe to receive the camera frames in the OnCameraPreviewed() method, if you want to do any post-processing on the camera frames. Such processing could the affect the performance of your application. Currently, working on the target requires that you rotate through 90 degrees the OverlayPanel that will be used to display the camera frames. No such rotation is required when working on the Simulator.

Related Recipes ■■

Add a Form to a Frame-based App

■■

Add a Simple Button Control to a Form

Recipe 4.4: Use an Overlay Panel Problem Description You want to display an image overlaid on the camera preview screen.

16_974018-gr04.indd 36016_974018-gr04.indd 360

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

361

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Graphics, Osp::Media

Header files to #include:

FUi.h, FUiControls.h, FGraphics.h, FMedia.h

Required libraries:

FUi, FUiControls, FGraphics, FMedia

Required privilege level: Normal

Required privilege groups:

IMAGE, CAMERA, SYSTEM_SERVICE

The OverlayPanel is a special type of panel that is used to specify a region where the developer can play back video or display the preview image from the camera. It is called an overlay because it is possible to overlay other graphics and controls on top of the video or camera preview. The OverlayPanel consists of two layers: the foreground panel and background buffer, which supports hardware accelerated rendering. The video playback or camera preview is displayed in the background buffer and any custom graphics or controls are displayed in the foreground panel. The overlay panel can manipulate the rotation, the aspect ratio, and the size of the input buffer. As a result of the implementation of the OverlayPanel, any Form that contains an OverlayPanel can only have a black, opaque background. This recipe details the steps to create and use the OverlayPanel, and provides some sample code snippets. This recipe assumes the steps detailed in Method 2 of the recipe ‘Add a Form to a Frame-based App’ have been followed to add a Form to the Application’s Frame. In this recipe a custom image is displayed as overlay on the camera preview image. In the bada platform, if a developer needs to do any custom drawing in a control, it must be done in the control’s OnDraw() method. This recipe shows the steps to create a custom overlay panel class and to implement the custom drawing in the OnDraw() method. A new class CameraOverlayPanel is created, inheriting from the OverlayPanel class, with the OnDraw() method overridden. Below is the class declaration:

16_974018-gr04.indd 36116_974018-gr04.indd 361

8/31/10 12:41 AM8/31/10 12:41 AM

362

Part II



Recipes

class CameraOverlayPanel : public Osp::Ui::Controls::OverlayPanel { public: CameraOverlayPanel(void); ~CameraOverlayPanel(void); bool Initialize(const Osp::Graphics::Rectangle &rect); protected: public: result OnInitializing(void); result OnTerminating(void); result OnDraw(void); };

An Initialize() method is implemented, for the construction of the overlay panel: bool CameraOverlayPanel::Initialize(const Osp::Graphics::Rectangle &rect) { OverlayPanel::Construct(rect); return true; }

The custom drawing for the custom overlay panel is done in the CameraOverlayPanel’s OnDraw() method. The following steps are executed: 1. Create the canvas for the overlay panel and clear it. 2. Create an Image object and initialise. 3. Decode the image file into the decoded bitmap container, passing the local file path of the image file and colour format parameters. 4. Scale the bitmap container to the required size. 5. Set the masking colour so that any pixels of this colour will be treated as transparent. 6. Draw the bitmap on the overlay panel’s canvas. The following code snippet is an example of the CameraOverlayPanel’s OnDraw() method: result CameraOverlayPanel::OnDraw(void) { result r = E_SUCCESS; // Retrieve panel canvas and clear Canvas* pCanvas = GetCanvasN(); pCanvas->Clear(); // Create bitmap from image data and scale to required size Image* pImage = new Image();

16_974018-gr04.indd 36216_974018-gr04.indd 362

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

363

pImage->Construct(); Bitmap* pBitmap = new Bitmap(); pBitmap = pImage->DecodeN(String(L”/Res/image.jpg”), BITMAP_PIXEL_FORMAT_RGB565); pBitmap->Scale(Dimension(200, 120)); // In this example we use white as the masking colour. Any white // pixels in the bitmap will be treated as transparent. Color maskColour(Color::COLOR_WHITE); pBitmap->SetMaskingColor(&maskColour); // Draw bitmap on panel canvas pCanvas->DrawBitmap(Point(140, 140),*pBitmap); delete pCanvas; delete pBitmap; delete pImage; return r; }

This CameraOverlayPanel class can be used by the MainForm for creating the overlay panel for the camera preview image. The Camera class provides several methods for controlling the camera device, some of which work asynchronously. So when the camera device is used in an application, the Osp::Media::ICameraEventListener listener must be implemented to receive events associated with the camera. The following code snippet shows an example of the MainForm class definition: class MainForm : public Osp::Ui::Controls::Form, public Osp::Media::ICameraEventListener { public: MainForm(void); ~MainForm(void); bool Initialize(void); protected: Osp::Media::Camera* pCamera; public: result OnInitializing(void); result OnTerminating(void); void void void void

OnCameraAutoFocused (bool completeCondition); OnCameraCaptured (Osp::Base::ByteBuffer &capturedData, result r); OnCameraErrorOccurred (Osp::Media::CameraErrorReason r); OnCameraPreviewed (Osp::Base::ByteBuffer &previewedData, result r);

};

In this recipe only the preview functionality of the camera device is used and the display of the preview image is performed by the camera engine, so none of the ICameraEventListener methods need to be implemented.

16_974018-gr04.indd 36316_974018-gr04.indd 363

8/31/10 12:41 AM8/31/10 12:41 AM

364

Part II



Recipes

The camera device and the overlay panel can be created during initialisation of the MainForm (OnInitializing()): 1. Create an instance of the primary camera device and initialise it with the camera event listener. 2. Power on the camera. 3. Create an instance of the custom overlay panel CameraOverlayPanel. 4. Construct the panel to the required size using a Rectangle object. 5. Set the render rotation for the panel to portrait mode. 6. Add the panel to the MainForm. 7. Retrieve the information of the background buffer in which the camera preview image will be displayed. 8. Start displaying the preview image from the camera. In this example the camera device displays the preview image and the OnCamera Previewed() listener callback is disabled. 9. Set the device screen to remain on and not be dimmed. The following code snippet is an example of the MainForm’s Oninitializing() method: result MainForm::OnInitializing(void) { result r = E_SUCCESS; // Create an instance of the primary Camera and register listener pCamera = new Camera(); pCamera->Construct(*this, CAMERA_PRIMARY); // Power on the camera pCamera->PowerOn(); Osp::Graphics::BufferInfo buffer_info; // Create an instance of the CameraOverlayPanel and initialise CameraOverlayPanel* pCameraPanel = new CameraOverlayPanel(); pCameraPanel->Initialize(Rectangle(0, 0, 480, 800)); // Set the panel’s renderer rotation - for portrait mode pCameraPanel->SetRendererRotation(OverlayPanel::ROTATION_90); // Add panel to MainForm AddControl(*pCameraPanel); // Get the information of the background buffer pCameraPanel->GetBackgroundBufferInfo(buffer_info); // Start displaying preview image from camera // Image will be drawn by camera object pCamera->StartPreview(&buffer_info, false); // Set the display to remain permanently on and not be dimmed

16_974018-gr04.indd 36416_974018-gr04.indd 364

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

365

Osp::System::PowerManager::KeepScreenOnState(true, false); return r; }

When the application terminates, the camera device must be shut down correctly in the MainForm’s OnTerminating() method: 1. Check the camera is powered on. 2. Stop displaying the preview image from the camera. 3. Power off the camera. The following code snippet is an example of the MainForm’s OnTerminating() method: result MainForm::OnTerminating(void) { result r = E_SUCCESS; // Check if camera is powered on if(pCamera->IsPoweredOn()) { // Stop displaying the preview image and power off // the camera pCamera->StopPreview(); pCamera->PowerOff(); } delete pCamera; pCamera = null; return r; }

Hints, Pitfalls, and Related Topics The CAMERA group privilege must be set in the application’s manifest file in order to use the camera device. The SYSTEM_SERVICE group privilege must be set in the application’s manifest file in order to use the Power Manager functionality to keep the display permanently on and prevent it from dimming. The IMAGE group privilege must be set in the application’s manifest file in order to use the DecodeN() method from the Image class. This recipe can also be tested in the simulator environment if there is a webcam connected to your computer. The camera control will display the preview from the webcam. In the current version of the SDK and firmware of the Wave device during writing of this recipe there is a slight discrepancy between the behaviour of the simulator and the Wave target device, which you should be aware of. By default, the CAMERA_PRIMARY on the target device is started in Landscape mode, so it is necessary to rotate the panel to Portrait

16_974018-gr04.indd 36516_974018-gr04.indd 365

8/31/10 12:41 AM8/31/10 12:41 AM

366

Part II



Recipes

mode. In the simulator environment, the camera starts in Portrait mode so the function call is not needed. See below: // Set the panel’s renderer rotation - for portrait mode pCameraPanel->SetRendererRotation(OverlayPanel::ROTATION_90);

If any controls such as buttons or labels need to be added to the custom overlay panel, they should be created and added in the CameraOverlay Panel::OnInitializing() method. Setting the transparency colour of a bitmap, using the SetMasking Color() method, is only supported for bitmap containers with a bitmap pixel format of BITMAP_PIXEL_FORMAT_RGB565. The preview format of the camera control can be set using the Camera::SetPreviewFormat() method. But the value set in this method must be one of the formats supported by the camera device. The formats supported by the camera can be queried using the Camera::GetPreviewFormat() method.

Related Recipe ■■

Add a Form to a Frame-based App

Recipe 4.5: Record Audio from the Microphone or Audio Input Device Problem Description You want to record audio from the microphone and save the recording to a file.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Media, Osp::Ui::Controls

Header files to #include: FUi.h, FMedia.h

Required libraries: FUi, FMedia

Required privilege level: Normal

Required privilege groups: RECORDING

16_974018-gr04.indd 36616_974018-gr04.indd 366

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

367

The AudioRecorder class records audio data from an input source to storage. The selection of input device source depends on the current device status. For example, if a headset mic device is connected, it is automatically selected as an input source. The audio recording format, the maximum recording time, and the maximum recording size can be set using the methods in this class. Having created an AudioRecorder instance, you will want to implement a listener to be informed of appropriate events during the recording process. The Osp::Media::IAudioRecorderEventListener interface class is available for this. When inheriting from this class you will be required to implement methods that will be called in your application to inform of recording events. This recipe will show how to create one such listener and how this can be combined with an AudioRecoder instance to record audio to a file. First, we will create an audio recorder listener. This will be tied to the AudioRecorder instance to inform our application of AudioRecorder events: #include #include class MyAudioRecorderListener: public Osp::Media::IAudioRecorderEventListener { public: void void void void void

OnAudioRecorderStopped(result r); OnAudioRecorderCanceled(result r); OnAudioRecorderPaused(result r); OnAudioRecorderStarted(result r); OnAudioRecorderEndReached( Osp::Media::RecordingEndCondition endCondition); void OnAudioRecorderClosed(result r); void OnAudioRecorderErrorOccurred( Osp::Media::RecorderErrorReason r);

};

Each method declared above will be implemented for the MyAudioRecorderListener class. Let’s now create the AudioRecorder instance and provide it with a handle to our listener. result MyApp::CreateAudioRecorder(void) { result r = E_SUCCESS; pAudioRecorder = new AudioRecorder(); pListener = new MyAudioRecorderListener; r = pAudioRecorder->Construct(*pListener); if (!IsFailed(r)) { r = pAudioRecorder->CreateAudioFile(path, true); if (!IsFailed(r)) {

16_974018-gr04.indd 36716_974018-gr04.indd 367

8/31/10 12:41 AM8/31/10 12:41 AM

368

Part II



Recipes pAudioRecorder->Record(); }

} if (r != E_SUCCESS) { if (pAudioRecorder) delete pAudioRecorder; if (pListener) delete pListener; } return r; }

After issuing the Record() method on the AudioRecorder instance (pAudioRecorder), the listener’s OnAudioRecorderStarted() method will be called. The recording is considered to have started only when this method is called, and not on the return of the call made to the asynchronous Record() method. In a similar fashion, asynchronous methods in the listener will be called to confirm success when basic functions such as Stop(), Pause(), Close() and Cancel() are called on pAudioRecorder. During the recording process, an error could occur. This too will be reported to the registered listener through the calling of OnAudioRecorderErrorOccurred(). An error will be reported through this call and the application will be expected to take the appropriate action. Errors associated with this call are: ■■

RECORDER_ERROR_OUT_OF_STORAGE: insufficient storage.

■■

RECORDER_ERROR_STORAGE_FAILED: storage access failed.

■■

RECORDER_ERROR_DEVICE_FAILED: the recording device failed.

While recording, the audio data being captured will be written to a file. This file’s path is passed in the call to CreateAudioFile(). This can be the path to a new file or an existing file. In fact, the second argument passed in this call informs that if the file already exists, that it can be overwritten. The application can exercise control over how the data is recorded in terms of data encoding type and also how large the resulting file will be. The following code extract shows how the recorder instance could be instructed to record to an .amr file, and restrict the resulting file to either 70 seconds of recording time, or a file no larger than 500Kb. pAudioRecorder->SetFormat(AUDIORECORDING_FORMAT_AMR); pAudioRecorder->SetMaxRecordingSize(500); pAudioRecorder->SetMaxRecordingTime(70000);

16_974018-gr04.indd 36816_974018-gr04.indd 368

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

369

With these recording requirements now set, recording can commence. Your listener will be informed when one of these conditions have been reached. Within the listener, the OnAudioRecorderEndReached() method will be called. This will report the condition under which the recording has ceased. The conditions are: ■■

RECORDING_ENDOF_MAX_SIZE: the end of file size.

■■

RECORDING_ENDOF_MAX_TIME: the end of time.

Hints, Pitfalls, and Related Topics It is possible to get the state of the AudioRecorder at any time. It might be worth tracking the states of the recorder to take the necessary action in the event of errors. For example you may wish to display an error pop-up when the user attempts to perform an operation while the recorder is in the wrong state. By calling Osp::Media::AudioRecorder::GetState() on your AudioRecorder instance, your application will be informed of the current recorder state. The following are available: ■■

RECORDER_STATE_INITIALIZED: the recorder is now initialised.

■■

RECORDER_STATE_OPENED: the file to write to is now opened.

■■

RECORDER_STATE_ENDOF_FILE: the recorder has reached the end of size or time.

■■

RECORDER_STATE_STOPPING: processing stop behaviour now.

■■

RECORDER_STATE_STOPPED: stopped and has no current record-time, however, media content is opened and initialised.

■■

RECORDER_STATE_PAUSING: pausing record at one specific position.

■■

RECORDER_STATE_PAUSED: the recording paused.

■■

RECORDER_STATE_STARTING: the recording operation is now starting.

■■

RECORDER_STATE_RECORDING: the recording media content.

■■

RECORDER_STATE_CLOSING: processing closing behaviour now.

■■

RECORDER_STATE_CLOSED: the file is now closed.

■■

RECORDER_STATE_ERROR: an error occurred in the recorder.

Recipe 4.6: Play a Sound Problem Description You want to play a sound from within your application.

16_974018-gr04.indd 36916_974018-gr04.indd 369

8/31/10 12:41 AM8/31/10 12:41 AM

370

Part II



Recipes

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Media, Osp::Base, Osp::Base::Collection, Osp::App1

Header files to #include:

FMedia.h, FBase.h, FApp.h2

Required libraries:

FMedia, FApp [.lib | .so]

Required privilege level: Normal

Required privilege groups: None

bada supports playing sounds locally on the device in all of the popular output formats, including AAC, MP3, WAV, and WMA. AAC content can also be streamed remotely from a server. To play a sound you have two options: ■■

use the classes in the Media namespace;

■■

use the device’s built in media player application which can be accessed using AppControl.

This recipe concentrates on the Media namespace because it offers more flexibility, but as you may also want to make use of the built in player sometimes, we’ve included code for that too.

Example 1: Playing a Sound using Media::Player In this recipe, we’ve assumed that you’ve created a form (see the recipe ‘Add a Form to a Frame-based App’) and are playing a sound as a result of some user action, such as clicking a button. The Osp::Media::Player class is used for playing both audio and video content, either stored locally on the device or streamed from a remote server. Player also includes methods for the kind of features you’d expect when playing media such as setting the volume, pausing, seeking and looping, but we’ll concentrate on just playing the sound in this recipe. Osp::Base::Collection and Osp::App are only needed if you are playing a sound using the built in player AppControl. 1

FApp.h is only needed as an include file and FApp as a library file if you are playing the sound using the built in player AppControl. 2

16_974018-gr04.indd 37016_974018-gr04.indd 370

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

371

Our example consists of the following steps: 1. Create the new Media::Player object. 2. Construct the Media::Player object with the form as the IPlayerEventListener. 3. Open the audio file using Media::Player::OpenFile. 4. Play the audio. 5. Close the Media::Player. Let’s see how we do this in code: // Create and construct the media player pAudioPlayer = new Player(); pAudioPlayer->Construct(*this); // Open the audio filed stored locally on the device // The first parameter specifies the path // The second parameter specifies whether we should open the file // synchronously or asynchronously. We pass true for asynchronously pAudioPlayer->OpenFile(L”/Res/bell_effect.wav”, true);

You have a choice of three methods to choose the audio or video content: OpenFile to open a file stored locally on the device, OpenUrl to open a file to stream remotely from a server and OpenBuffer to play content from a ByteBuffer. Each of these methods can be used synchronously or asynchronously. When dealing with small files stored locally on the device, you will probably choose to open the content synchronously, whereas with remote content or large files stored locally, it makes more sense to open the content asynchronously, to ensure that your application stays responsive while the media content is being opened. In our example we’re using the form as the listener, so we need to set up our form to derive from IPlayerEventListener to receive and handle media player events: class AudioPlayerForm : public Osp::Ui::Controls::Form, public Osp::Ui::IActionEventListener, public Osp::Media::IPlayerEventListener,

We need to implement the following methods of IPlayerEvent Listener: virtual void OnPlayerBuffering(int percent); virtual void OnPlayerEndOfClip(); virtual void OnPlayerErrorOccurred( Osp::Media::PlayerErrorReason r); virtual void OnPlayerInterrupted(); virtual void OnPlayerOpened(result r); virtual void OnPlayerReleased(); virtual void OnPlayerSeekCompleted(result r);

16_974018-gr04.indd 37116_974018-gr04.indd 371

8/31/10 12:41 AM8/31/10 12:41 AM

372

Part II



Recipes

We called Player::OpenFile asynchronously, so we need to actually start the audio player when we know the content is successfully opened. The method to use is the OnPlayerOpened method of IPlayerEventListener: void AudioPlayerForm::OnPlayerOpened(result r) { // The content is successfully opened, start playing pAudioPlayer->Play(); }

When the audio has finished playing the OnPlayerEndOfClip method is invoked. We’ll close the player in this method. pAudioPlayer will be deleted in our form’s destructor. void AudioPlayerForm::OnPlayerEndOfClip() { pAudioPlayer->Close(); }

Other IPlayerEventListener methods

In our example we implemented two IPlayerEventListener methods: OnPlayerOpened and OnPlayerEndOfClip. IPlayerEventListener also contains a number of other methods, listed in Table R4.1. Table R4.1 Other IPlayerEventListener methods Method

Description

OnPlayerInterrupted

Called when the player is interrupted as a result of an event such as receiving a call. The player will be automatically stopped. Note this handler is only invoked when the player is interrupted while playing some content

OnPlayerReleased

Called when the external event that interrupted the player in OnPlayerInterrupted has completed. It is the responsibility of the application to start the sound playing again by calling the Play() method of Player

OnPlayerBuffering

Called to notify the application that streaming data is being buffered. You could update your user interface at this point to let the user know why audio playback is not as smooth

OnPlayerErrorOccured

This method is sent a Media::PlayerErrorReason specifying errors such as out of memory or connection errors with streaming data

OnPlayerSeekCompleted

Called when moving to a certain position in audio or video is completed

16_974018-gr04.indd 37216_974018-gr04.indd 372

8/31/10 12:41 AM8/31/10 12:41 AM

Group 4



Multimedia Content

373

Example 2: Using the Player Base Application An alternative approach to playing a sound is to use the built-in media player, which can be accessed using the App::AppControl class. More information about accessing base applications can be found in the ‘Create an AppControl to interact with a base application’ recipe. Figure R4.2 shows a sound playing in the built in player. The built in media player can be launched using the following code: ArrayList* pDataList = null; pDataList = new ArrayList(); pDataList->Construct(); String* pData = null; pData = new String(L”type:audio”); pDataList->Add(*pData); String* pData2 = null; pData2 = new String(L”path:/Res/CanYouHearMe.mp3”); pDataList->Add(*pData2); AppControl* pAc = AppManager::FindAppControlN (APPCONTROL_AUDIO, OPERATION_PLAY); if(pAc) { pAc->Start(pDataList, null); delete pAc; } pDataList->RemoveAll(true); delete pDataList;

Figure R4.2 Playing a sound using the built-in media player base application.

Hints, Pitfalls, and Related Topics In this example we’ve played an audio file stored in the application’s /Res directory. We add this file to the project’s /Res directory in the bada IDE and this will be copied to the application’s /Res directory on the device or in the simulator. bada supports up to 10 simultaneous player Media::Player instances, although the number of players that can actually be opened at one time will depend on the resources of the device. Note that when playing a sound using both the Media::Player namespace and the built-in player application, bada does not check whether the device is

16_974018-gr04.indd 37316_974018-gr04.indd 373

8/31/10 12:41 AM8/31/10 12:41 AM

374

Part II



Recipes

set to Silent Mode. The application needs to check whether Silent Mode is set using the System::SettingInfo class, and ask the user how they want to proceed.

Related Recipes ■■

Add a Form to a Frame-based App

■■

Create an AppControl to Interact with a Base App

16_974018-gr04.indd 37416_974018-gr04.indd 374

8/31/10 12:41 AM8/31/10 12:41 AM

GROUP

5 Networking

Recipe 5.1: Create a Network Connection Problem Description You need to send or receive data over the network, for which you need a network connection.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Net

Header files to #include: FNet.h

Required libraries: FNet

Required privilege level: System

Required privilege groups: For custom connections only, NET, NET_ACCOUNT

375

17_974018-gr05.indd 37517_974018-gr05.indd 375

8/31/10 12:41 AM8/31/10 12:41 AM

376

Part II



Recipes

A network connection is a runtime session for a data network service, configured with network account settings. This recipe explains how to create either a default or custom network connection.

Example 1: Create a Default Network Connection To reduce the difficulties in setting up network connections, bada manages the default network connection (see Figure R5.1). If you do not specify a network connection when your application uses features such as sockets or HTTP, the default connection will be used.

Figure R5.1 Create a default network connection.

The following are the steps for creating and using a default network connection: 1. Request network services without specifying a network connection. 2. The network services receive the request and start the default network connection. 3. The network services access a remote network. bada handles all of the work in creating a default network connection and all you need to do is use the APIs provided by classes such as Net::Socket and Net::Http without specifying a network connection. Using the default network connection does not require the NET privilege to be set; you only need to ensure that the appropriate privileges are set for any services you use such as SNS_SERVICE to use the SNS Gateway and HTTP to set up HTTP sessions.

Example 2: Create a Custom Network Connection If you need to specify a particular configuration in place of the defaults, you should create a custom network connection (see Figure R5.2). The workflow for creating a custom network connection is as follows: 1. Use a NetAccountManager and NetAccountInfo object to configure the required connection settings. 2. Create and start a custom network connection using the custom settings.

17_974018-gr05.indd 37617_974018-gr05.indd 376

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

377

3. Request network services with the network connection. 4. Network services accesses the remote network.

Figure R5.2 Creating a custom network connection.

The classes required to create a custom connection are part of the Net namespace. NetAccountManager and NetAccountInfo encapsulate the information necessary for the NetConnection class to create a connection. NetAccountManager is used to get the list of NetAccountIds that are later used to construct the NetConnection. The NET and NET_ACCOUNT privileges are required to create a custom net connection. This recipe consists of the following steps: 1. Implement an INetConnectionEventListener. 2. Construct NetAccountManager object. 3. Get the list of NetAccountIds from NetAccountManager object. 4. You can now start the connection with any of the NetAccountIds provided by this list. Now we’ll look at the code. 1. Derive your class from INetConnectionEventListener. #include class MyClass : public Osp::Net::INetConnectionEventListener { Osp::Net::NetConnection* pNetConnection; void InitiateNetConnection(); void CloseNetConnection(); //NetConnection void OnNetConnectionStarted(Osp::Net::NetConnection& netConnection, result r);

17_974018-gr05.indd 37717_974018-gr05.indd 377

8/31/10 12:41 AM8/31/10 12:41 AM

378

Part II



Recipes

void OnNetConnectionStopped(Osp::Net::NetConnection& netConnection, result r){} void OnNetConnectionSuspended(Osp::Net::NetConnection& netConnection){} void OnNetConnectionResumed(Osp::Net::NetConnection& netConnection) {} };

2. Call the InitiateNetConnection( ) function: a. Construct a NetAccountManager object. b. Get the list of NetAccountIds via the NetAccountManager. c. Create the net connection instance with the NetAccountId of the desired net account. d. Register with NetConnectionListener. e. Call the start function of NetConnection. Note that this is an asynchronous function, and you will get a response in the callback function OnNetConnectionStarted(). void MyClass::InitiateNetConnection() { result r; NetAccountManager netMgr; r = netMgr.Construct(); NetAccountId id; id = netMgr.GetNetAccountId(NET_BEARER_WIFI); pNetConnection = new NetConnection(); r = pNetConnection->Construct(id); pNetConnection->AddNetConnectionListener(*this); pNetConnection->Start(); if (null != pNetAccIdList) { pNetAccIdList->RemoveAll(); delete pNetAccIdList; pNetAccIdList = null; } }

3. As a result of calling pNetConnection->Start(), when the connection is started you will get a response in OnNetConnectionStarted().

17_974018-gr05.indd 37817_974018-gr05.indd 378

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

379

void MyClass::OnNetConnectionStarted(Osp::Net::NetConnection& netConnection, result r) { if (E_SUCCESS == r) { AppLog(“Net connection established”); } }

4. You can close the connection by calling Close(). void MyClass:: CloseNetConnection() { pNetConnection->Close(); }

Recipe 5.2: Use Secure Sockets Problem Description You want to use secure sockets.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Base, Osp::Net, Osp::Net::Sockets

Header files to #include: FBase.h, FNet.h

Required libraries: FNet

Required privilege level: Normal

Required privilege groups: NET

This recipe demonstrates how to use secure sockets for sending and receiving data. The Osp::Net::Sockets namespace provides a set of classes, methods, and properties for TCP (Transmission Control Protocol) or UDP (User Datagram Protocol) socket programming. The SecureSocket class is also provided by this

17_974018-gr05.indd 37917_974018-gr05.indd 379

8/31/10 12:41 AM8/31/10 12:41 AM

380

Part II



Recipes

namespace. To receive asynchronous notifications of SecureSocket events, you must register and maintain an event listener ISecureSocketEventListener. The ISecureSocketEventListener interface specifies the methods used for responding to different kinds of socket events. These events are only sent out when using a secure socket in a non-blocking mode. An event listener is added by calling AddSecureSocketListener(). When a secure socket event is generated, one of these methods is called. This recipe consists of the following steps: 1. Derive a class from ISecureSocketEventListener. 2. Create secure client socket and connect it with server. 3. Send data over the connected socket. 4. Receive data over the connected socket. 5. Close the socket at the end. Now we’ll look at the code. 1. Derive a class from ISecureSocketEventListener interface. #include class SocketsSecureExample : public Osp::Net::Sockets::ISecureSocketEventListener { public: SocketsSecureExample(void) {} ~SocketsSecureExample(void) {} public: void CreateSecureSocket(void); void CloseSecureSocket(void); void SecureSendData(void); void SecureReceiveData(void); // ISecureSocketEventListener void OnSecureSocketConnected(Osp::Net::Sockets::SecureSocket& socket); void OnSecureSocketClosed(Osp::Net::Sockets::SecureSocket& socket, Osp::Net::Sockets::NetSocketClosedReason reason); void OnSecureSocketReadyToReceive(Osp::Net::Sockets::SecureSocket& socket); void OnSecureSocketReadyToSend(Osp::Net::Sockets::SecureSocket& socket); void OnSecureSocketServCertFailed(Osp::Net::Sockets::SecureSocket& socket); private: Osp::Net::Sockets::SecureSocket* pSocket; };

17_974018-gr05.indd 38017_974018-gr05.indd 380

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

381

2. The CreateSecureSocket method does the following: a. Create a secure socket. b. Add a socket listener to listen for socket events. c. Initialise the secure socket server port and IP. d. Create a peer end point. e. Connect the server socket. void SocketsSecureExample::CreateSecureSocket(void) { result r = E_SUCCESS; // Create a Secure(based on TCP) socket pSocket = new SecureSocket(); pSocket->Construct(NET_SOCKET_AF_IPV4, NET_SOCKET_TYPE_STREAM, NET_SOCKET_PROTOCOL_SSL); // Add a Socket Listener to listen to socket event pSocket->AddSecureSocketListener(*this); // Set the socket as select an interested event. pSocket>AsyncSelectByListener( NET_SOCKET_EVENT_CONNECT|NET_SOCKET_EVENT_WRITE |NET_SOCKET_EVENT_READ|NET_SOCKET_EVENT_CLOSE); // Connect to a Secure Server Ip4Address peerAddr(“127.0.0.1”); // server socket address unsigned short peerPort = 8080; // port NetEndPoint peerEndPoint(peerAddr, peerPort); pSocket->Connect(peerEndPoint); }

3. The data is sent in the SecureSendDataMethod. void SocketsSecureExample::SecureSendData(void) { result r = E_SUCCESS; const char* pSendData = “Send”; ByteBuffer txBuffer; txBuffer.Construct(strlen(pSendData) + 1); txBuffer.SetArray((byte*)pSendData, 0, strlen(pSendData));

17_974018-gr05.indd 38117_974018-gr05.indd 381

8/31/10 12:41 AM8/31/10 12:41 AM

382

Part II



Recipes

txBuffer.Flip(); r = pSocket->Send(txBuffer); if (r == E_SUCCESS) { // Release resource txBuffer.Clear(); } }

4. Receive secure data: a. Prepare a buffer for receiving data. b. Get the size of the data to be received. c. Receive the data. d. Call the SecureReceiveData function shown below from the OnSecureSocketReadyToReceive method to receive the data. void SocketsSecureExample::SecureReceiveData(void) { result r = E_SUCCESS; ByteBuffer rxBuffer; int capacity = MAX_BUFFER_SIZE; char data[MAX_BUFFER_SIZE]; rxBuffer.Construct(capacity); // Receive data r =pSocket->Receive(rxBuffer); if(r == E_SUCCESS) { // Release resource rxBuffer.Flip(); rxBuffer.GetArray((byte*)data, 0, capacity); data[capacity]=’\0’; AppLog(data); rxBuffer.Clear(); } }

5. Close the secure socket service using the Close() method. void SocketsSecureExample::CloseSecureSocket(void) {

17_974018-gr05.indd 38217_974018-gr05.indd 382

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

383

result r = E_SUCCESS; // Close socket r = pSocket->Close(); if(r == E_SUCCESS) { //Release resource delete pSocket; pSocket = null; } }

Hints, Pitfalls, and Related Topics An instance of SecureSocket can only be created and used in the asynchronous (non-blocking) mode. It can only be used for the TCP client socket functionality. The secure socket feature of bada supports a CipherSuite mechanism, which is a combination of certain certificate types, ciphers, MACs, key exchange algorithms, and compression methods.

Recipe 5.3: Establish Normal and Pipeline Connection Modes for HTTP Sessions Problem Description You want to establish HTTP normal and pipeline connection modes.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Base, Osp::Net:Http, Osp::Net

Header files to #include: FBase.h, FNet.h

Required libraries: FNet

Required privilege level: Normal

Required privilege groups: NET

17_974018-gr05.indd 38317_974018-gr05.indd 383

8/31/10 12:41 AM8/31/10 12:41 AM

384

Part II



Recipes

The HTTP client architecture provides a generalised mechanism for HTTP-like protocols that operate over various transports. Using this namespace, a client can choose an HTTP protocol, encode the data, and then transport it. The default operation provides plain-text HTTP operating over a TCP/IP connection. The Net::Http provides the implementation of the HTTP data communication protocol. Using this namespace correctly makes the application a conditional HTTP 1.1-compliant client. An HTTP session encapsulates the client’s HTTP activity over the duration of the client’s execution. It consists of a set of transactions using the same connection settings, such as a proxy or a host. There are two HTTP session modes (see Figure R5.3): ■■

normal mode;

■■

pipelining mode.

In the normal mode, all the transactions within a session share the same connection. One session has one connection, and only one transaction is processed at a time. The pipelining mode is similar to the normal mode in that it shares the connection, but multiple requests can be submitted concurrently without having to wait for each response.

Figure R5.3 Normal and pipelining modes.

This recipe details the steps to create an HTTP connection, as follows: 1. Derive a class from IHttpTransactionEventListener. 2. Create an HttpSession, open a transaction and send a request. 3. Respond to the request in OnTransactionReadyToRead. Now we’ll look at the code.

17_974018-gr05.indd 38417_974018-gr05.indd 384

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

385

1. Derive from IHttpTransactionEventListener in order to receive HTTP transaction events in your application. class MyHttpClass : public Osp::Net::Http::IHttpTransactionEventListener { public: MyHttpClass(); virtual ~MyHttpClass(); void SendRequestGet(Osp::Base::String requestUrl); private: void OnTransactionReadyToRead(Osp::Net::Http::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction, int availableBodyLen); void OnTransactionAborted(Osp::Net::Http::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction, result r); void OnTransactionReadyToWrite(Osp::Net::Http::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction, int recommendedChunkSize); void OnTransactionHeaderCompleted(Osp::Net::Http::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction, int headerLen, bool rs); void OnTransactionCompleted(Osp::Net::Http::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction); void OnTransactionCertVerificationRequiredN(Osp::Net::Http::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction, String* pCert);

private: Osp::Net::Http::HttpSession* pSession; };

In this class we have created a pointer to the HttpSession. A session encapsulates the client’s HTTP activity over the duration of the client’s execution.

17_974018-gr05.indd 38517_974018-gr05.indd 385

8/31/10 12:41 AM8/31/10 12:41 AM

386

Part II



Recipes

2. Make an HTTP request: a. Create an instance of HttpSession. b. Construct an instance of HttpSession specifying normal or pipeline mode. c. Open transaction for the HttpSession. d. Add an HttpTransactionListener. e. Get the HTTPRequest pointer by calling GetRequest. The HTTPRequest pointer is used to set the actual URI, method, request header, etc. f. Submit the HTTP request. void MyHttpClass::SendRequestGet(Osp::Base::String requestUrl) { result r = E_SUCCESS; HttpTransaction* pTransaction = null; HttpRequest* pRequest = null; String hostAddr(requestUrl); if (null != pSession) { delete pSession; pSession = null; } pSession = new HttpSession(); r = pSession->Construct(NET_HTTP_SESSION_MODE_NORMAL, null, hostAddr, null); if (IsFailed(r)) { AppLog(“Fail to HttpSession::Construct. [%s]”, GetErrorMessage(r)); return; } pTransaction = pSession->OpenTransactionN(); if (pTransaction) { pTransaction->AddHttpTransactionListener(*this); pRequest = pTransaction->GetRequest(); if (pRequest)

17_974018-gr05.indd 38617_974018-gr05.indd 386

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

387

{ pRequest->SetUri(requestUrl); pRequest->SetMethod(NET_HTTP_METHOD_GET); r = pTransaction->Submit(); if (IsFailed(r)) { AppLog(“Fail to HttpRequest::Submit. [%s]”, GetErrorMessage(r)); } } else { delete pTransaction; pTransaction = null; } } }

3. As a result of the request above, you get the response in OnTransaction ReadyToRead(), an implementation of which is shown below. MyHttpClass::OnTransactionReadyToRead(HttpSession& httpSession, HttpTransaction& httpTransaction, int availableBodyLen) { // Get the response from the HTTP HttpResponse* pHttpResponse = httpTransaction.GetResponse();    if(pHttpResponse->GetStatusCode() == NET_HTTP_STATUS_OK)    { // Get buffer received ByteBuffer* pBuffer = pHttpResponse->ReadBodyN(); // Add null termination char at the end pBuffer->SetByte(pBuffer->GetLimit()-1 , ‘\0’); // Use this buffer as per developer need. delete pBuffer; pBuffer = null; } }

Hints, Pitfalls, and Related Topics Currently the server side of the HTTP protocol service is not implemented. To use pipeline mode, the developer just needs to specify NET_HTTP_SESSION_MODE_PIPELINING when constructing the HttpSession: pSession->Construct(NET_HTTP_SESSION_MODE_PIPELINING, null, hostAddr, null);

17_974018-gr05.indd 38717_974018-gr05.indd 387

8/31/10 12:41 AM8/31/10 12:41 AM

388

Part II



Recipes

In the NORMAL and PIPELINING session mode, all the transactions within this session will be submitted through the same connection. While only one transaction is processed at a time in the normal mode, multiple transactions can be pipelined in the pipelining mode. In the normal mode, you need to wait for the end of the previous transaction to submit the next transaction. The maximum number of HttpSessions that can be constructed per application is six.

Recipe 5.4: Use Bluetooth Profiles Problem Description Use different Bluetooth profiles, depending on the type of connection or you require.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Base, Osp::Net

Header files to #include: FUi.h, FBase.h, FNet.h

Required libraries: FUi, FBase, FNet

Required privilege level: Normal

Required privilege groups: BLUETOOTH

Bluetooth provides quick and easy connections to other devices, and supports many different use-cases, including one-off file transfers and wirelessly connecting peripheral devices such as headsets and keyboards. Standard usecases are specified as Bluetooth profiles. The Bluetooth profiles supported by bada include: ■■

General Access Profile (GAP)

■■

Object Push Profile (OPP)

GAP is the most basic Bluetooth profile and it provides the basis for all other profiles. All other profiles, including OPP, are built upon GAP. The purpose of GAP is to make sure that all devices can successfully establish a baseband link.

17_974018-gr05.indd 38817_974018-gr05.indd 388

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

389

OPP is a basic profile for sending ‘objects’, such as images, virtual business cards, or any type of file. The name includes ‘Push’ because the transactions are always initiated by the sender (client), not the receiver (server). In this recipe we show you how to use Bluetooth OPP. Before we look at code, let’s summarise the most important classes and methods of the Osp::Net::Bluetooth namespace: ■■

BluetoothDevice: encapsulates device identity and type.

■■

BluetoothManager: provides APIs to manage Bluetooth features, for example activation and deactivation of the Bluetooth hardware.

■■

IBluetoothManagerEventListener: an interface class that specifies the methods used for notifying different kinds of Bluetooth Manager events, for which appropriate listener methods are called.

■■

BluetoothOppClient: provides APIs to use the OPP profile.

■■

IBluetoothOppClientEventListener: an interface class that specifies the methods used for notifying different kinds of Bluetooth OppClient events, for which appropriate listener methods are called.

■■

IBluetoothOppServerEventListener: an interface class that specifies the methods used for notifying different kinds of Bluetooth OppServer events.

To demonstrate OPP in this recipe, we are going to: 1. Define a Bluetooth client class and a Bluetooth server class. 2. Create a basic application with a Form and a button for an OPP client. Bluetooth client:

1. Construct a BluetoothManager instance and select a target Bluetooth device from the Bluetooth manager. 2. Implement OnActionPerformed() to handle user events to send a file or cancel the file. 3. Send a file to the target device (OPP). 4. Display transfer progress. 5. Implement IBluetoothManagerEventListener and IBluetoothOppClientEventListener. Bluetooth server:

1. Create an OPP server and implement IBluetoothOppServerEventListener for working as a OPP server. 2. Receive a file from a remote OPP client.

17_974018-gr05.indd 38917_974018-gr05.indd 389

8/31/10 12:41 AM8/31/10 12:41 AM

390

Part II



Recipes

After following the process above, the application looks as shown in Figure R5.4.

Figure R5.4 Sending and receiving a file using Bluetooth.

Let’s look at the code. First we define the OPP client and server classes. #include #include #include class BtClient : public Osp::Ui::IActionEventListener, public Osp::Net::Bluetooth::IBluetoothManagerEventListener, public Osp::Net::Bluetooth::IBluetoothOppClientEventListener, { public: BtClient(); ~BtClient(); void Initialize(); void SendFileToTargetUsingOPP(); protected: void OnActionPerformed(const Osp::Ui::Control& source, int actionId); // Override virtual functions of IBluetoothManagerEventListener void OnBluetoothActivated(result r) {} void OnBluetoothDeactivated(result r) {}

17_974018-gr05.indd 39017_974018-gr05.indd 390

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

391

// Override virtual functions of IBluetoothOppClientEventListener void OnOppPushResponded(result r){} void OnOppTransferDone(const Osp::Base::String& fileName, int fileSize, bool isCompleted); void OnOppTransferInProgress(int percent); private: void ShowTransferProgress(Osp::Base::String &titleMsg); private: static const int ID_BTN_OPP = 101; static const int ID_BTN_CANCEL = 102; Osp::Net::Bluetooth::BluetoothManager* pBtManager; Osp::Net::Bluetooth::BluetoothDevice* pBtDevice; Osp::Net::Bluetooth::BluetoothOppClient* pBtOppClient; Osp::Base::String strFileName; Osp::Ui::Controls::Popup* pProgPopup; Osp::Ui::Controls::Progress* pTranProg; };

We recommend making separate classes for the Bluetooth client and Bluetooth server. #include #include #include class BtServer: Osp::Net::Bluetooth::IBluetoothOppServerEventListener { public: // Construction BtServer(); ~BtServer(void); bool Initialize(void); // Stop and Start server service result StartService(void); result StopService(void); protected: // OPP Server void OnOppPushRequested(const Osp::Net::Bluetooth::BluetoothDevice& device); void OnOppTransferDone(const Osp::Base::String &fileName, int fileSize, bool isCompleted); void OnOppTransferInProgress(int percent); static const int ID_PROGRESS_BAR = 201; private: void ShowTransferProgress(Osp::Base::String &titleMsg); // for recipe Osp::Ui::Controls::Popup* pProgPopup; Osp::Ui::Controls::Progress* pTranProg; Osp::Net::Bluetooth::BluetoothOppServer* pBtOppServer; };

17_974018-gr05.indd 39117_974018-gr05.indd 391

8/31/10 12:41 AM8/31/10 12:41 AM

392

Part II



Recipes

The creation of BluetoothManager BluetoothOppClient, and obtaining a target BluetoothDevice is done in the OnInitializing method of our form. Make sure that you clean up (delete) all those variables that are created (new) on the heap, in the destructor or OnTerminating() method of the Form. The target Bluetooth device is obtained from the paired device list maintained by the BluetoothManager. Pass an integer value as parameter to the GetPairedDeviceAt() method of the BluetoothManager to obtain the BluetoothDevice at that location. You can also use APPCONTROL_BT to search for and select Bluetooth devices that are not already paired. void BtForm::OnInitializing() { // make a new Form Form::Construct(FORM_STYLE_NORMAL | FORM_STYLE_TITLE | FORM_STYLE_INDICATOR); SetTitleText(L”Bluetooth OPP”); // create send button Button* pButton = null; pButton = new Button(); pButton->Construct(Rectangle(0, 200, 480, 100), L”Send File ?”); pButton->SetActionId(ID_BTN_SEND); pButton->AddActionEventListener(*this); AddControl(*pButton); // Create OPP Client pBtClient = new BtClient(); pBtClient->Initialize(); // Create OPP Server pBtServer = new BtServer(); pBtServer->Initialize(); }

The Initialize() method encapsulates the steps required to construct a manager instance and an OPP client instance. result BtClient::Initialize() { pBtManager = new BluetoothManager(); pBtManager->Construct(*this); pBtDevice = pBtManager->GetPairedDeviceAt(0); pBtOppClient = new BluetoothOppClient(); pBtOppClient->Construct(*this); // Hard coded file path for sending a file. strFileName = L”/Home/Media/Sounds/Samsung.mp3”; return E_SUCCESS; }

17_974018-gr05.indd 39217_974018-gr05.indd 392

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

393

Please take note of the *this parameter passed on to the Construct() method of the BluetoothManager and BluetoothOppClient classes. All these construct methods take reference to the object implemented as their respective event handlers. Given below is the function definition of the IActionEventListener, OnActionPerformed(). This is the function that receives events on the UI controls. Here, it receives the button press events. In the Form, if the Send button is clicked, the Bluetooth client will send a file by calling SendFileToTargetUsingOPP(). The client can’t push a file while the Bluetooth server is using a Bluetooth device. To prevent this, stop the Bluetooth server service before pushing a file and restart the server service after the client finishes to push a file. void BtForm::OnActionPerformed(const Control& source, int actionId) { switch (actionId) { case ID_BTN_SEND: { // stop OPP server service if(pBtServer) pBtServer->StopService(); // send a file to peer BT device using OPP profile. pBtClient->SendFileToTargetUsingOPP(); // start OPP server service if(BtServer) pBtServer->StartService(); } break; default: break; } }

It’s time to send the file. See the function definition below to understand how to transfer a file from one device to another through the Bluetooth OPP. The SetMinProgressInterval() method specifies the minimum invocation interval of the IBluetoothOppClientEventListener interface’s OnOppTransferInProgress() listener method. The unit is percentage and the default value is 5. void BtClient::SendFileToTargetUsingOPP() { // make a Popup to show the progressing of the transfer ShowTransferProgress(); // send a file to server pBtOppClient->SetMinProgressInterval(5); pBtOppClient->PushFile(*pBtDevice, strFileName); }

17_974018-gr05.indd 39317_974018-gr05.indd 393

8/31/10 12:41 AM8/31/10 12:41 AM

394

Part II



Recipes

We omit the code used to display progress while transferring the file. Note that we should also implement the OnActionPerformed() method of IActionEventListener to enable the transfer to be cancelled, for example if the user presses the Cancel button. In this case we would call the client’s CancelPush() method. Once you have called the BluetoothOppClient class’s PushFile() method, the underlying Bluetooth hardware will start sending the file you have selected (strFileName), chunk by chunk to the target device (pBtDevice). A number of control communications or ‘handshakes’ take place between the source and target Bluetooth devices when you try to push a file. All the responses or results of these communications are handled by the application in the IBluetoothOppClientEventListener class’s three event handlers. One of these methods, OnOppTransferInProgress(), gives an update about how much the file has been sent so far, at regular intervals (this value is set using the method SetMinProgressInterval() ). This value is used to update the transfer progress bar. Another IBluetoothOppClientEvent Listener method is OnOppTransferDone(), which notifies that the file transfer has finished. The code for this is below. void BtClient::OnOppTransferInProgress(int percent) { if (pTranProg) { pTranProg->SetValue(percent); pTranProg->Draw(); pTranProg->Show(); } } void BtClient::OnOppTransferDone(const Osp::Base::String &fileName, int fileSize, bool isCompleted) { if (pProgPopup) delete pProgPopup; }

From now on we have to create the OPP server. The following code snippet shows what we have to do to create and start the service of the OPP server: bool BtServer::Initialize() { pBtOppServer = new BluetoothOppServer(); pBtOppServer->Construct(*this); String destPath = L”/Media/Images”; pBtOppServer->StartService(destPath); return true; }

17_974018-gr05.indd 39417_974018-gr05.indd 394

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

395

We need to implement the IBluetoothOppServerEventListener to get the file from a remote OPP client. The OnOppPushRequested method is invoked when the OPP server gets a request from a remote client. The code snippet below shows IBluetoothOppServerEventListener. void BtServer::OnOppPushRequested(const Osp::Net::Bluetooth::BluetoothDevice& device) { // show the status of receiving a file. String title = L”Receiving.....”; ShowTransferProgress(title); pBtOppServer->AcceptPush(); }

If you want to accept the file, call AcceptPush(). If you want to reject the file, call RejectPush(). As with receiving a file, it is helpful to display progress to the user, and to enable cancellation.

Recipe 5.5: Use Non-blocking and Blocking TCP and UDP Sockets Problem Description You want to use sockets.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Net::Sockets

Header files to #include: FNet.h

Required libraries: FNet

Required privilege level: Normal

Required privilege groups: SOCKET

17_974018-gr05.indd 39517_974018-gr05.indd 395

8/31/10 12:41 AM8/31/10 12:41 AM

396

Part II



Recipes

The Net::Sockets namespace provides a set of classes, methods, and properties for TCP (Transmission Control Protocol) or UDP (User Datagram Protocol) socket programming. The Socket class is the base class for connecting, sending, and receiving data over a network. Socket, by default, is created and used in asynchronous (non-blocking) mode. To receive asynchronous socket events you need to register and maintain an ISocketEventListener. This recipe demonstrates: 1. Creating a server socket. 2. Creating a client socket. 3. Communication via sockets. Let’s walk through the code to accomplish this, step by step: 1. Implement ISocketEventListener. #include class MyClass: public Osp::Net::Sockets::ISocketEventListener { Osp::Net::Sockets::Socket* pServerSocket; Osp::Net::Sockets::Socket* pCommunicatorSocket; Osp::Net::Sockets::Socket* pClientSocket; Osp::Base::ByteBuffer* pByteBuffer; CreateServerSocket(void); CreateClientSocket(Osp::Base::String serverIP); SendData(); ReceiveData(); CreateBlockingSocket(); // ISocketEventListener void OnSocketConnected(Osp::Net::Sockets::Socket& socket); void OnSocketClosed(Osp::Net::Sockets::Socket& socket, Osp::Net::Sockets::NetSocketClosedReason reason); void OnSocketReadyToReceive(Osp::Net::Sockets::Socket& socket); void OnSocketReadyToSend(Osp::Net::Sockets::Socket& socket); void OnSocketAccept(Osp::Net::Sockets::Socket& socket); }

2. Create a server socket. The server binds to a network endpoint – an IP address and port number. When a client connects to the server, the

17_974018-gr05.indd 39617_974018-gr05.indd 396

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

397

response is received by the OnSocketAccept()event handler. The code for creating a server socket consists of the following steps: a. Create a socket instance. b. In the construct method for the TCP socket provide NET_SOCKET_ TYPE_STREAM as the net socket type and NET_SOCKET_PROTOCOL_TCP as the net socket protocol. c. If you wish to use a UDP socket then in the construct method provide NET_SOCKET_TYPE_DATAGRAM as the net socket type and NET_SOCKET_PROTOCOL_UDP as the net socket protocol. d. To create a non-blocking socket, register with ISocketEventListener by calling AddSocketListener. e. Set the socket in async mode by calling AsyncSelectByListener. The events the listener receives are: Write, Read, Close, Accept, Connect, and Certificate failed for SecureSocket. f. Bind this socket to a net end point, specifying the port where the server is going to listen. g. Call the Listen() function, in order to listen for a connection. void MyClass::CreateServerSocket(void) { result r = E_SUCCESS; //Create socket instance pServerSocket = new Socket(); r = pServerSocket->Construct ( NET_SOCKET_AF_IPV4, NET_SOCKET_TYPE_STREAM, NET_SOCKET_PROTOCOL_TCP); if (E_SUCCESS!= r) { AppLog(”Construct Failed %d ”, r); } //Register with ISocketListener pServerSocket->AddSocketListener(*this); //Sets the socket in asynchronous mode, also listener will listen //to the specified events as passed in the argument r = pServerSocket->AsyncSelectByListener (NET_SOCKET_EVENT_ACCEPT|NET_SOCKET_EVENT_CLOSE ); if (E_SUCCESS!= r)

17_974018-gr05.indd 39717_974018-gr05.indd 397

8/31/10 12:41 AM8/31/10 12:41 AM

398

Part II



Recipes

{ AppLog(”AsyncSelectByListener Failed %d ”,r); } //NetEndPoint holds the IP address and Port number Ip4Address peerAddr(NET_SOCKET_INADDR_ANY); unsigned short peerPort = 9000; NetEndPoint peerEndPoint(peerAddr, peerPort); //The socket will bind to a port, on which it will listen for //connection r = pServerSocket->Bind(peerEndPoint); if (E_SUCCESS!= r) { AppLog(”CreateServerSocket Bind Failed %d ”,r); } //The socket will listen to the incoming connections, the maximum //number of incoming connections that can be queued for acceptance //can be specified as argument to this function r = pServerSocket->Listen(1); if (E_SUCCESS!= r) { AppLog(”CreateServerSocket Listen Failed %d ”,r); } }

3. Create a client socket as follows: a. Create a socket instance. b. As with a client socket, in the construct method for the TCP socket provide NET_SOCKET_TYPE_STREAM as the net socket type and NET_SOCKET_PROTOCOL_TCP as the net socket protocol. c. To create a non-blocking socket, register with ISocketEventListener by calling AddSocketListener. d. Set the socket in async mode by calling AsyncSelectByListener. e. Call the Connect function and specify the NetEndPoint of the server to which this client is going to connect. void MyClass::CreateClientSocket(String serverIP) { result r = E_SUCCESS; //Create socket instance

17_974018-gr05.indd 39817_974018-gr05.indd 398

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

399

pClientSocket = new Socket; pClientSocket->Construct(NET_SOCKET_AF_IPV4, NET_SOCKET_TYPE_STREAM, NET_SOCKET_PROTOCOL_TCP); //Register with ISocketListener pClientSocket->AddSocketListener(*this); //Sets the socket in asynchronous mode, also listener will listen //to the specified events as passed in the argument pClientSocket->AsyncSelectByListener( NET_SOCKET_EVENT_CONNECT |NET_SOCKET_EVENT_WRITE | NET_SOCKET_EVENT_READ | NET_SOCKET_EVENT_CLOSE); //NetEndPoint holds the IP address and Port number, here IP Address //and port is that of server to which the client wishes to connect Ip4Address peerAddr(serverIP); // For Testing unsigned short peerPort = 9000; // port NetEndPoint peerEndPoint(peerAddr, peerPort); //Establishes a connection to a remote host for a connection-oriented //socket r = pClientSocket->Connect(peerEndPoint); }

4. A socket receives notification of receiving a new connection from a peer in OnSocketAccept(). Call the AcceptN function, which will return an instance of a socket that can be used for sending and receiving data. You need to register this socket with the listener and set it to async mode as shown above. void MyClass::OnSocketAccept(Osp::Net::Sockets::Socket& socket) { AppLog(“OnSocketAccept”); Socket* pSocket = const_cast(&socket); if (null != pCommunicatorSocket) { delete pCommunicatorSocket; pCommunicatorSocket = null; } pCommunicatorSocket = pSocket->AcceptN(); pCommunicatorSocket->AddSocketListener(*this); pCommunicatorSocket->AsyncSelectByListener( NET_SOCKET_EVENT_CONNECT |NET_SOCKET_EVENT_WRITE |NET_SOCKET_EVENT_READ |NET_SOCKET_EVENT_CLOSE); }

17_974018-gr05.indd 39917_974018-gr05.indd 399

8/31/10 12:41 AM8/31/10 12:41 AM

400

Part II



Recipes

5. Now you can send and receive data via sockets. Call the Send() method to send the data in pByteBuffer to the remote host. void MyClass::SendData() { r = pCommunicatorSocket->Send(this->pByteBuffer); // pByteBuffer contains the data to be sent }

6. To receive data we first call the Ioctl() method to check how many bytes are available to be read and then use this information to construct a buffer to read the data into using the Receive() method. void MyClass::ReceiveData() { ByteBuffer rxBuffer; unsigned long arg =0; if (null != pCommunicatorSocket) { pCommunicatorSocket->Ioctl(NET_SOCKET_FIONREAD, arg); rxBuffer.Construct(arg); r = pCommunicatorSocket->Receive(rxBuffer); } }

7. ISocketEventListener is where you handle socket related events: //Notifies a connecting socket that the connection attempt has been completed //successfully void MyClass::OnSocketConnected(Osp::Net::Sockets::Socket& socket) { AppLog(“OnSocketConnected”); } //Notifies the registered socket that the peer socket has been closed //or if the connection attempt has not been completed successfully void MyClass::OnSocketClosed(Osp::Net::Sockets::Socket& socket, Osp::Net::Sockets::NetSocketClosedReason reason) { // Do necessary cleanup if required } //Notifies a socket that data is ready to be retrieved void

17_974018-gr05.indd 40017_974018-gr05.indd 400

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

401

MyClass::OnSocketReadyToReceive(Osp::Net::Sockets::Socket& socket) { ReceiveData(); } //Notifies a socket that it can send data void MyClass::OnSocketReadyToSend(Osp::Net::Sockets::Socket& socket) { SendData(); }

Hints, Pitfalls, and Related Topics bada also supports blocking mode. To use a blocking socket, do not implement ISocketEventListener, and do not set the socket to async mode. Call the Ioctl function with NET_SOCKET_FIONBIO and ‘0’ as arguments. void MyClass::CreateBlockingSocket() { pClientSocket = new Socket(); pClientSocket ->Construct(NET_SOCKET_AF_IPV4, NET_SOCKET_TYPE_DATAGRAM, NET_SOCKET_PROTOCOL_UDP); // Enable synchronous(blocking) mode unsigned long arg = 0; pClientSocket->Ioctl(NET_SOCKET_FIONBIO, arg); }

Applications that use blocking mode can freeze or become non-responsive during the time the transaction is in process, so it’s preferable to use nonblocking mode.

Recipe 5.6: Set Up an Ad Hoc Wi-Fi Network Problem Description You need to establish an ad hoc Wi-Fi network, to use for a multiplayer game, for example.

The Recipe The following configuration is required for this recipe:

17_974018-gr05.indd 40117_974018-gr05.indd 401

8/31/10 12:41 AM8/31/10 12:41 AM

402

Part II



Recipes

Namespaces used:

Osp::Base, Osp::Net, Osp::Net::Wifi, Osp::Base::Collection

Header files to #include: FBase.h, FUi.h, FNet.h

Required libraries: FBase, FNet

Required privilege level: Normal

Required privilege groups: NET,

WIFI

Independent mode or ad hoc mode allows a Wi-Fi network to function without a central wireless router or access point. All wireless peers on the ad hoc network must use the same SSID (Service Set Identifier) and channel number. Currently, the channel is not configurable by an application developer; the Wi-Fi device scans and selects a proper channel by itself. This recipe shows you how to use the classes and methods in the Net::WiFi namespace to do the following: 1. Establish an ad hoc Wi-Fi network. 2. Get peer information when an ad hoc network is established. 3. Exchange messages with peers. In Figure R5.5, the user of device 1 sets its name as Jerry and the user of device 2 sets its name to Tom. Then when they press Search, aWi-Fi network is established and they can see each other as peers.

Figure R5.5 Establishing an ad hoc Wi-Fi network.

17_974018-gr05.indd 40217_974018-gr05.indd 402

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

403

In Figure R5.6 the ad hoc connection is established between Tom and Jerry.

Figure R5.6 An ad hoc Wi-Fi connection is established.

Below are the steps you need to follow to establish an ad hoc Wi-Fi network from within your application. 1. Derive your class from IAdhocServiceEventListener. #include class MyWiFiClass : public Osp::Net::Wifi::IAdhocServiceEventListener { Osp::Net::Wifi::AdhocService* pAdhocService; void void void void

Initialize(); StopService(); SendBroadcastMessage(Osp::Base::String msg); SendMessageToPeer(Osp::Base::String peerName, Osp::Base::String message);

void OnAdhocServiceStarted(const Osp::Net::NetConnection* pNetConnection, result r); void OnAdhocServiceStopped(result r); void OnMessageReceived(const Osp::Base::String& peerName, const Osp::Base::String& message); };

2. Create an instance of AdhocService.

17_974018-gr05.indd 40317_974018-gr05.indd 403

8/31/10 12:41 AM8/31/10 12:41 AM

404

Part II



Recipes

3. Set your name by calling SetPeerName so that your peers will recognise you. 4. Now, call StartAdhocService. This function requires company name and application name; both these arguments form an SSID for the Wi-Fi network. The last parameter of StartAdhocService specifies whether you will give your information to peers. If this is true, you will notify your information to neighbours automatically and permit the collection of neighbour peer information. void MyWiFiClass::Initialize() { pAdhocService = new AdhocService(*this); String companyName = String(“SAMSUNG”); String appName; appName = Application::GetInstance()->GetAppName(); pAdhocService->SetPeerName(“ABC”); pAdhocService->StartAdhocService(companyName, appName, WIFI_RADIO_CHANNEL_6, true); }

Those who have established Wi-Fi connectivity with this SSID are part of your ad hoc Wi-Fi network. The SSID is a token that identifies an 802.11 (Wi-Fi) network.  5. As a result of step 4, you will get a response in OnAdhocService Started when the device starts its Wi-Fi service. 6. Once, the Wi-Fi service is started you can call GetNeighborsN(). This will provide list of Wi-Fi neighbours who are in the same network. void MyWiFiClass::OnAdhocServiceStarted(NetConnection* pNetConnection, result r) { IList* pNeighborPeerInfo; const IpAddress *pAddr; String name; AdhocPeerInfo *pAdhocPeerInfo; pNeighborPeerInfo = pAdhocService->GetNeighborsN(); if (pNeighborPeerInfo)

17_974018-gr05.indd 40417_974018-gr05.indd 404

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

405

{ IEnumerator *pEnum; pEnum = pNeighborPeerInfo->GetEnumeratorN(); while (pEnum->MoveNext() == E_SUCCESS) { pAdhocPeerInfo = (AdhocPeerInfo*) pEnum->GetCurrent(); name = pAdhocPeerInfo->GetName(); pAddr = pAdhocPeerInfo->GetAddress(); String ip = pAddr->ToString(); } pAdhocService->SendBroadcastMessage(”Hello All”); delete pNeighborPeerInfo; delete pEnum; } }

7. Once your ad hoc service is started you can broadcast a message to all the peers by calling SendBroadcastMessage(). void MyWiFiClass::SendBroadcastMessage(String msg) { pAdhocService->SendBroadcastMessage(msg); }

8. You can also send a dedicated message to any of your peers by calling SendUnicastMessage(). void MyWiFiClass::SendMessageToPeer(String peerName, String message) { pAdhocService-> SendUnicastMessage(peerName, message); }

9. Once you are done with the ad hoc service call StopService(). void MyWiFiClass:: void StopService() { if (pAdhocService) { pAdhocService->StopAdhocService(); delete pAdhocService; } }

17_974018-gr05.indd 40517_974018-gr05.indd 405

8/31/10 12:41 AM8/31/10 12:41 AM

406

Part II



Recipes

Hints, Pitfalls, and Related Topics You can see up to eight peers at a time. You cannot test the functionality of Net::WiFi in the Simulator; you will need to test it on device hardware.

Recipe 5.7: Query a DNS Server Problem Description You want to query a Domain Name System (DNS) server.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Ui, Osp::Ui::Controls, Osp::Net, Osp::Base::Collection

Header files to #include: FUi.h, FNet.h

Required libraries:

FUi, FUiControls, FNet

Required privilege level: Normal

Required privilege groups: NET

Dns is a class provided by the Osp::Net namespace. This class provides simple domain name resolution functionality that translates host names into IP addresses and vice versa. To get an answer to a query using Dns you must use an IDnsEvent Listener. The Dns class encapsulates a request for information from a DNS server. A DNS request can be one of two types: ■■

DNS lookup of IP addresses from user-friendly host names;

■■

DNS lookup of host names from IP addresses.

17_974018-gr05.indd 40617_974018-gr05.indd 406

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

407

This recipe explains how to create a Dns instance, how to send a query for name resolution, and how to get a response. The UI for sending DNS queries is supplied by a form with Host by Name and Host by IP buttons, as shown in Figure R5.7. This recipe will concentrate on the details of sending DNS queries. Our code includes the following steps: 1. Derive a class from the interface IDnsEventListener to get the result of the DNS query. 2. Override the function OnDnsResolutionCompletedN. This function is called in response to the query. 3. Query the DNS server using either of the Dns class methods GetHostByName() or GetHostByAddress().

Figure R5.7 Our UI allows us to query the DNS server by name or IP address.

17_974018-gr05.indd 40717_974018-gr05.indd 407

8/31/10 12:41 AM8/31/10 12:41 AM

408

Part II



Recipes

Let’s have a look at the code. First we derive a class from the interface IDnsEventListener. #include #include #include class FormDns : public Osp::Ui::Controls::Form, public Osp::Ui::IActionEventListener, public Osp::Net::IDnsEventListener { public: FormDns(void); virtual ~FormDns(void); bool Initialize(void); protected: static const int ID_BUTTON_BY_NAME = 101; static const int ID_BUTTON_BY_IP = 102; Osp::Ui::Controls::Button* pButtonHostByName; Osp::Ui::Controls::Button* pButtonHostByIP; Osp::Ui::Controls::Label* pLabelHostDetails; private: Osp::Net::Dns* pDns; public: result OnInitializing(void); result OnTerminating(void); void OnActionPerformed(const Osp::Ui::Control& source, int actionId); void OnDnsResolutionCompletedN(Osp::Net::IpHostEntry* ipHostEntry, result r); private: void DnsRequestIP(Osp::Base::String hostName); void DnsRequestHostName(Osp::Net::Ip4Address& ipAddress); };

OnDnsResolutionCompletedN is the callback function that is called in response to the asynchronous DNS query, either GetHostByName() or GetHostByAddress(). void FormDns::OnDnsResolutionCompletedN(IpHostEntry* ipHostEntry, result r) { if (r == E_SUCCESS && ipHostEntry != null) { // Get IP Addresses // Gets the IP address list of a domain name. IList* addressList = ipHostEntry->GetAddressList(); pLabelHostDetails->SetText(L””); String strTemp = L””; if (addressList != null) { // Get the count of IpAddress object in address list int count = addressList->GetCount(); strTemp += L”IP:\n”; for (int index = 0; index < count; index++) {

17_974018-gr05.indd 40817_974018-gr05.indd 408

8/31/10 12:41 AM8/31/10 12:41 AM

Group 5



Networking

409

// Get the IpAddress one by one IpAddress* pIpAddress = static_cast (addressList->GetAt(index)); strTemp += pIpAddress->ToString() + L”\n”; } } // Gets the alias list of a domain name. IList* aliasList = ipHostEntry->GetAliasList(); if (aliasList != null) { // Get the count of IpAddress object in alias list int count = aliasList->GetCount(); strTemp += L”ALIAS:\n”; for (int index = 0; index < count; index++) { // Get the aliases one by one String* alias = static_cast (aliasList->GetAt(index)); strTemp += (*alias) + L”\n”; } } if (pLabelHostDetails) { pLabelHostDetails->SetText(strTemp); pLabelHostDetails->Draw(); pLabelHostDetails->Show(); } delete ipHostEntry; } else { AppLog(GetErrorMessage(r)); } }

The first parameter of this callback function is IpHostEntry. This parameter associates a DNS host name with a list of aliases and a list of matching IP addresses. To get the list of IP addresses you need to call the GetAddressList() function; to get the alias list call the GetAliasList() function. We create the Dns object in our Form’s OnInitializing method, adding the form as the listener. // Create Dns Object pDns = new Dns(); // Register Dns event listener pDns->Construct(*this);

To get the host by name call the GetHostByName() function of the Dns class. This function takes String as a parameter. To get the host by IP call the GetHostByAddress() function of the Dns class. This function takes an IpAddress as a parameter.

17_974018-gr05.indd 40917_974018-gr05.indd 409

8/31/10 12:41 AM8/31/10 12:41 AM

410

Part II



Recipes

The code below shows how to call these functions to get the host information. void FormDns::DnsRequestIP(String hostName) { result r = pDns->GetHostByName(hostName); if (IsFailed(r)) { AppLog(“GetHostByName Failed.”); } } void FormDns::DnsRequestHostName(Ip4Address& ipAddress) { result r = pDns->GetHostByAddress(ipAddress); if (IsFailed(r)) { AppLog(“GetHostByAddress Failed.”); } }

Finally, to clean up, delete the Dns instance in the OnTerminating() function. delete pDns; pDns = null;

17_974018-gr05.indd 41017_974018-gr05.indd 410

8/31/10 12:41 AM8/31/10 12:41 AM

GROUP

6 Maps and Location

6.1 Get Geographic Data from a Provider and Show a Map Problem Description You want to obtain geographic information and display it in form of a map on your bada device.

The Recipe The following configuration is required.

411

18_974018-gr06.indd 41118_974018-gr06.indd 411

8/31/10 12:42 AM8/31/10 12:42 AM

412

Part II



Recipes

Namespaces used:

Osp::Locations::Services, Osp::Locations::Controls, Osp::Graphics

Header files to #include: FLocations.h

Required libraries:

FLocations, FLocationControls

Required privilege level: Normal

Required privilege groups:

LOCATION, LOCATION_SERVICE

The namespace Osp::Locations::Services provides a number of useful services that can be exploited by the developer. An essential service that we will also introduce is what is encapsulated in the IMapServiceProvider interface. A further namespace used in this recipe is Osp::Locations::Controls, which allows users to pan, zoom and interact with maps as is generally expected. We simply show how a map can be displayed on screen. Our sample code presents snippets from a C++ source file and its corresponding header file, which we called MapVisualisation.cpp (covers code for presenting geographic data as a map). In order to be able to display maps we need access to a geographic data provider. For this example we use deCarta as our map provider. You can sign up at the deCarta website (developer.decarta.com) and request a key for free. Once you have your key, you can link your deCarta account in the application by creating a map provider object. We do this in our MapVisualisation class. // Define a name for the provider String providerName = L”deCarta”; // Set a map key for deCarta (insert your username/pwd instead of XXX/ // YYY) static const String extraInfo = L”ClientName=XXX;ClientPassword=YYY;” “HostUrl=http://developer.kr.dz.decarta.com:80/openls/openls”; // Create a map provider IMapServiceProvider* pProvider = static_cast( ProviderManager::ConnectToServiceProviderN(L”deCarta”, LOC_SVC_PROVIDER_TYPE_MAP, extraInfo));

18_974018-gr06.indd 41218_974018-gr06.indd 412

8/31/10 12:42 AM8/31/10 12:42 AM

Group 6



Maps and Location

413

After that, construct a Map control and configure it according to your display requirements. // Create Map control Map* pMap = new Map(); // Construct the map pMap->Construct(Osp::Graphics::Rectangle(0, 0, GetCanvasN()->GetBounds().width, GetCanvasN()->GetBounds().height), *pProvider); // Configuration: allow panning pMap->SetPanEnabled(true); // Configuration: define the center of the map // These are the coordinates of Staines, UK, around which we center the // map double lat = 51.433315; double lon = -0.497382; pMap->SetCenter(lat, lon, false); // Configuration: Show my location pMap->SetMyLocationEnabled(true);

It is important to set the configuration value for the selected map area. The default value is ‘global-mobile’. Other area codes can be found on the deCarta website. For demonstration purposes we will use this string to access global map data. This is done by invoking the SetPreferencePropertyValue() method, which is a member of the Map class. Further map configuration settings can be obtained from the deCarta developer site. // Set configuration values static const String CONFIGURATION_VALUE(L”global-mobile”); // Configuration: Set the maps to this area pMap->SetPreferencePropertyValue(String(L”configuration”), &CONFIGURATION_VALUE);

Hints, Pitfalls, and Related Topics If no map is shown on the Simulator screen, you might first check whether you have any spelling errors in username and password that you got from your geographic data provider. Another reason might be that you are in a proxy environment. Then you have to set the proxy information in the Simulator. Go to menu | settings | connectivity | network | bada.

18_974018-gr06.indd 41318_974018-gr06.indd 413

8/31/10 12:42 AM8/31/10 12:42 AM

414

Part II



Recipes

6.2 React to Location Changes Problem Description You want to react to location changes and show the current position of a user on that map. This recipe is related to the recipe ‘Get Geographic Data from a Provider and Show a Map’.

The Recipe The following configuration is required. Namespaces used:

Osp::Locations, Osp::Graphics, Osp::Locations::Services

Header files to #include: FLocations.h

Required libraries: FLocations

Required privilege level: Normal

Required privilege groups:

LOCATION, LOCATION_SERVICE

The namespace Osp::Locations contains among others the classes LocationProvider and Location, which we will use in our recipe. With the LocationProvider class you can define where you want to get a position from (e.g. from the GPS sensor). This class also implements the interface ILocationListener, which gives you information about location updates. The class Location representing the location information is a part of LocationProvider. We show how a map can be displayed on screen that has an overlay additionally showing the user’s current position. In addition to the MapVisualisation.cpp from the recipe ‘Get Geographic Data from a Provider and Show a Map’, our sample code presents snippets from another C++ source file that we called MapInteraction.cpp Once we have established access to a geographic information provider such as deCarta and initialised our map, we can start to obtain location information from our device. For this, we switch to the MapInteraction class. We create

18_974018-gr06.indd 41418_974018-gr06.indd 414

8/31/10 12:42 AM8/31/10 12:42 AM

Group 6



Maps and Location

415

and construct a LocationProvider by adding in the location source. We’re using the GPS receiver. Here you can also configure the update rate, which we set to 5 seconds in the RequestLocationUpdate() method. // Create a LocationProvider LocationProvider *locProvider = new LocationProvider(); // Construct the LocationProvider by using GPS and WPS (Wi-Fi Positioning // System) // as its locating mechanism locProvider->Construct(LOC_METHOD_HYBRID); // Configure the time interval for updates locProvider->RequestLocationUpdates(*this, 5, false);

To receive location updates you need to override the OnLocationUpdated() method, which is declared in the ILocationListener interface. // Called when a location event is received void MapInteraction::OnLocationUpdated(Location& location) { if(location.GetQualifiedCoordinates() != null) { const QualifiedCoordinates *q = location.GetQualifiedCoordinates(); // The lat and lon values double longitude = q->GetLongitude(); double latitude = q->GetLatitude(); // Center the map around these new values pFormMap->SetCenter(latitude, longitude, true); // Redraw and show the map pFormMap->Draw(); pFormMap->Show(); } }

Hints, Pitfalls, and Related Topics Once your code compiles without errors you can run it in the Simulator. A very convenient feature of the bada Simulator is the Event Injector tool. To get this, right-click on the Simulator screen, select the Event Injector, and there choose the Location tab. You can drag and drop the pointer on the map, or directly enter latitude and longitude values, as shown in Figure R6.1. These are then sent as events to your application running on the bada Simulator. This tool is very useful for testing.

18_974018-gr06.indd 41518_974018-gr06.indd 415

8/31/10 12:42 AM8/31/10 12:42 AM

416

Part II



Recipes

Figure R6.1 The Event Injector in action in the IDE.

18_974018-gr06.indd 41618_974018-gr06.indd 416

8/31/10 12:42 AM8/31/10 12:42 AM

GROUP

7 Services and Social Networking

7.1 Create Content on the bada Server Problem Description You want to create content for the bada Server and transfer it to an Amazon S3 workspace.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Content

Header files to #include: FContent.h

Required libraries: FContent.lib

Required privilege level: System

Required privilege groups:

REMOTE_CONTENT, CONTENT_TRANSFER

417

19_974018-gr07.indd 41719_974018-gr07.indd 417

8/31/10 12:42 AM8/31/10 12:42 AM

418

Part II



Recipes

This recipe is similar to the content service presented in Chapter 5 but more detailed. Content on the bada platform refers to images, music, videos, or any other type of data that is specified by the developer. There are two steps necessary for creating content. The first step is to transfer the physical content files to the workspace, and the second is to create the content meta-information on the bada Server. This meta-information is essential for the bada platform to be able to search and manipulate physical contents on the workspace. Before using an Amazon S3 workspace, the application has to authenticate itself at the Amazon server. We explained this process in Chapter 5 earlier. Hence, in this recipe we will not cover this part again but focus on the content transfer itself. In all the example code in this recipe we assume that you have already authenticated your application with the Amazon server. The code snippet below illustrates the declaration of our class that holds the necessary methods and members. We call our class YourClassName and it derives from the interfaces Osp:: App::IAppControlEventListener,Osp::Content::IContentTransferListener, and Osp::Content::IRemoteContentManagerListener. class YourClassName : public Osp::App::IAppControlEventListener, public Osp::Content::IContentTransferListener, public Osp::Content::IRemoteContentManagerListener { private: Osp::Content::ContentTransfer* pContentTransfer; Osp::Content::RemoteContentInfo* pRemoteContentInfo; Osp::Content::RemoteContentManager* pRemoteContentManager; Osp::Base::Utility::Uri uri;

public: // We just mention the relevant methods here // Callback function for sign-in AppControl void OnAppControlCompleted(const Osp::Base::String& appControlId, const Osp::Base::String& operationId, const Osp::Base::Collection::IList* pResultList); // Callback functions for content transfer to the workspace void OnContentUploadCompleted(RequestId reqId, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMessage); void OnContentTransferCanceled(RequestId reqId, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMessage); void OnContentCreated(RequestId reqId, const Osp::Base::String& contentId, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMessage); };

19_974018-gr07.indd 41819_974018-gr07.indd 418

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

419

In this header file, there are other pure virtual functions defined within the IContentTransferListener and IRemoteContentManagerListener interface classes. For brevity, we do not list them here. In your code project, however, you will have to implement them, otherwise you will not be able to build your project. In this recipe, we only focus on the content creation part, so we just implement the related call-back function defined in the header as mentioned above. void YourClassName::OnAppControlCompleted( const Osp::Base::String& appControlId, const Osp::Base::String& operationId, const Osp::Base::Collection::IList* pResultList) { if (appControlId.Equals(APPCONTROL_SIGNIN) && operationId.Equals( OPERATION_SIGNIN)) { AppLog(“SignIn AppControl Completed”); } }

The above code is a sample implementation for checking the sign-in step. It is invoked when the user finished the sign-in processes after they have launched the application the first time. It is also possible to check the result of the sign-in process in order to verify whether it was successful or not. After a successful sign-in, we can now start to transfer the physical content information to the Amazon server. To do so you only need to create an instance of the ContentTransfer class: pContentTransfer = new ContentTranfer(); result r = E_SUCCESS; // Pass YourClassName as a pointer to IContentTransferListener r = pContentTransfer->Construct(*this); if(IsFailed(r)) { AppLog(“Failed to construct ContentTransfer :%s”, GetErrorMessage(r)); // Process the error condition } RequestId reqId; pContentTransfer->Upload(L”/Media/Images/sample.jpg”, L”/Image/sample.jpg”,true, uri, reqId);

The Upload() method takes five parameters: ■■

the source path to the content file on the device;

■■

the destination path of the content file on the Amazon workspace;

■■

a bool primitive to indicate whether an existing file should be replaced;

19_974018-gr07.indd 41919_974018-gr07.indd 419

8/31/10 12:42 AM8/31/10 12:42 AM

420

Part II



Recipes

■■

the content URI as output parameter;

■■

the request ID as output parameter.

Once the physical content file is transferred completely, the OnContentUploadCompleted() method will be invoked. void YourClassName::OnContentUploadCompleted(RequestId reqId, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMessage) { String contentId; result r = E_SUCCESS; pRemoteContentManager = new RemoteContentManager(); r = pRemoteContentManager->Construct(*this); if (IsFailed(r) { AppLog(“Construct failed.”); // Handle error condition } AppLog(“pRemoteContentManager->Construct successful”); // for reasons of brevity, we’re hard coding the contentsize // normally we’d get the file size from ContentInfo int contentSize = 82; // For brevity reasons we omit exception checking below // Make sure that you do the exception handling in your project ! pRemoteContentInfo = new RemoteContentInfo(); r = pRemoteContentInfo->Construct(L”Image”, uri, contentSize); // Exception handling … String contentName (L”NewContentName”); r = pRemoteContentInfo->SetContentName(contentName); // Exception handling … r = pRemoteContentInfo->SetKeyword(L”Evangelist”); // Exception handling … r = pRemoteContentManager->CreateContent(*pRemoteContentInfo, reqId); // Exception handling … }

The call-back function works asynchronously. You only know that the content is successfully uploaded when this call-back is executed. In the illustrated code snippet above, we implemented the second step where we created the content information inside the OnContentUploadCompleted() method. This is because it only makes sense to create the content information when the physical content is already there.

19_974018-gr07.indd 42019_974018-gr07.indd 420

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

421

After you created the content information on the bada Server, you can check the results by implementing the OnContentCreated() method as shown below. void YourClassName::OnContentCreated(RequestId reqId, const Osp::Base::String& contentId, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMessage) { if (IsFailed(r)) { AppLog(“OnContentCreated[%s]”, GetErrorMessage(r)); AppLog(“Error code: %S”, errorCode.GetPointer()); AppLog(“Error message %S”, errorMessage.GetPointer()); } else { // Continue normally and implement your “checking” here... } }

Hints, Pitfalls, and Related Topics Earlier we introduced the Osp::Content::IContentTransferListener Interface. Another helpful method is OnContentTransferInProgress(), which is defined as follows: virtual void Osp::Content::IContentTransferListener::OnContentTransferInProgress (RequestId reqId, int totalTransferedSize);

This method is declared as pure virtual, which means that it has to be implemented. It is a very helpful method to query progress information when data is uploaded or downloaded. Content creation on the bada platform is quite straightforward. The advantage is that your content is virtually managed by the bada Server, and the physical content is stored on the workspace provider such as Amazon. It guarantees the maximum security for your content because it is hosted by an independent third party. Currently Amazon is the only storage provider that allows making use of the bada content service (i.e. search, and sharing). As a result, Amazon will make a charge, albeit a small one, for this service. It is envisaged, however, that a portfolio of similar service providers will soon be established. The bada SDK provides some code samples that give even more details about how to interact with remote content and exploit this feature of the bada platform. Check, for instance, the RemoteContent sample which provides more details about functions for (remote) content management.

19_974018-gr07.indd 42119_974018-gr07.indd 421

8/31/10 12:42 AM8/31/10 12:42 AM

422

Part II



Recipes

7.2 Use the bada SNS Gateway to Access a Social Network Service such as Facebook Problem Description You need an easy way to use a social networking service like Facebook from your bada app. You can use the bada SNS Gateway.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Social::Services, Osp::Base::Collection

Header files to #include: FSocial.h, FBase.h

Required libraries:

FSocial, FSocialServices, FSocialServicesSnsAuth

Required privilege level: System

Required privilege groups: SNS_SERVICE

The bada SNS Gateway provides a unified API that enables easy access to social networking services (SNS), such as Facebook, Twitter, and MySpace. The Gateway supports many basic use-cases, and also provides simple authentication that can be used for subsequent interaction with the services’ own RESTful APIs if you need more complex interactions. The API is asynchronous, and uses listener methods of interface classes to enable call-backs to be received from the framework when events of interest occur. To use a listener, an app derives a suitable object, for example a Form, from the appropriate interface class, and implements a listener method to handle events of interest. The SNS Gateway provides listeners for four different kinds of event: ■■

nsActivityListener: receives responses to activity requests made to the Gateway.

■■

nsGatewayListener: receives events related to the login status of the client app.

19_974018-gr07.indd 42219_974018-gr07.indd 422

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

■■

ContentListener: receives responses to content requests made to the Gateway.

■■

SnsPeopleListener: receives responses to other requests to the Gateway.

423

A critical step in any interaction with SNS is authentication. There are two aspects to authentication: ■■

All social networks (and in fact most web services) require client apps to register for keys before allowing API access to their services.

■■

All social networks require user authentication before allowing user access to individual accounts.

The first step, therefore,1 when you develop a bada SNS client app is to register the app with the service provider (Facebook, Twitter, or MySpace). The documentation at developer.bada.com provides step-by-step details showing you how to register your application (i.e. your SNS client) with these service providers. When the service provider registers your application, you will be provided with your own application and secret keys.2 After you have registered your application with the relevant service provider, interaction with the bada SNS Gateway consists of the following initial steps: 1. Implement ISnsAuthenticatorListener and ISnsGatewayListener. 2. Implement any other SNS listeners your application requires. 3. Create an instance of the SnsAuthenticator and SnsGateway objects. 4. Call SnsAuthenticator::Authenticate(). 5. On successful authentication, add this result to the SnsGateway by calling SnsGateway::AddAuthResult. When these steps are complete, you can call the SnsGateway methods that provide the specific interactions your app requires, such as uploading an image or sending a tweet. Figure R7.1 shows an app authenticating with the bada SNS Gateway. First, the app itself provides a login page for the relevant service. Pressing Sign in will call SnsAuthenticator::Authenticate(). In turn, this will launch the user login page of the SNS, in this example Facebook. Finally, after the user logs in successfully, the bada Server displays a notification to the user. On pressing Exit, the user is returned to the application, which now runs. 1 Of course, you will also need to have appropriate developer privileges before you can use bada services. For more about how to become a bada partner, which is the required membership level for developers using bada services, please see the information at developer.bada.com. 2 The terminology varies between different service providers, for example for both Twitter and MySpace these are known as the Consumer Key and Secret key, whereas for Facebook they are known as the Application Key and Application Secret.

19_974018-gr07.indd 42319_974018-gr07.indd 423

8/31/10 12:42 AM8/31/10 12:42 AM

424

Part II



Recipes

Figure R7.1 Signing in to Facebook.

19_974018-gr07.indd 42419_974018-gr07.indd 424

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

425

Let’s see how this looks in code. In the example below we show how to get photo albums from Facebook. To do this, we implement the ISnsAuthenticatorListener, ISnsGatewayListener, and ISnsContentListener interfaces. 1. Implement the ISnsAuthenticatorListener interface. This is required to authenticate your application, and is the first step to using bada SNS features. If authentication is not successful, you cannot proceed further. 2. Implement the ISnsGatewayListener interface for the SnsGateway. 3. Now you can implement any other SnsGateway listeners required by your app, depending on what functionality you want to offer. For example, if your application only needs the friend list or friend circle, you only need to implement the ISnsPeopleListener interface. #include class MySNSClass : public Osp::Social::Services::ISnsAuthenticatorListener, public Osp::Social::Services::ISnsGatewayListener, public Osp::Social::Services::ISnsContentListener, { Osp::Social::Services::SnsGateway* pSnsGateway; Osp::Social::Services::SnsAuthenticator* pSNSAuthenticator; Osp::Social::Services::SnsAuthResult* pSNSAuthResult; result Initialize(void); result Authenticate(void); // ISnsAuthenticatorListener function void OnSnsAuthenticated(Osp::Social::Services::SnsAuthResult& snsAuthResult, result r, const String& errorCode, const String& errorMsg); // ISnsGatewayListener Listener void OnSnsLoggedInStatusReceived(RequestId reqId, Osp::Base ::String& serviceProvider, bool isLoggedIn, result r, const Osp::Base ::String& errorCode, const Osp::Base::String& errorMsg); result GetAlbums(void); // ISnsContentListener functions

19_974018-gr07.indd 42519_974018-gr07.indd 425

8/31/10 12:42 AM8/31/10 12:42 AM

426

Part II



Recipes

void OnSnsPhotoAlbumsReceivedN(RequestId reqId, Osp::Base::Collection::IList *pAlbumList, bool hasNext, Osp::Social::Services::SnsPagingParam& pagingParam, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg); void OnSnsPhotoReceived(RequestId reqId, Osp::Social::Services::SnsPhotoInfo*pPhoto, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg){} void OnSnsPhotosByUserReceivedN(RequestId reqId, Osp::Base::Collection::IList*pPhotoList, bool hasNext, Osp::Social::Services::SnsPagingParam& pagingParam, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg); void OnSnsPhotosInAlbumReceivedN(RequestId reqId, Osp::Base::Collection::IList*pPhotoList, bool hasNext, Osp::Social::Services::SnsPagingParam& pagingParam, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg); void OnSnsPhotoUploaded(RequestId reqId, Osp::Base::String &serviceProvider, Osp::Base::String *pPhotoId, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg);

4. In the initialisation code for this class, we create the SnsAuthenticator and SnsGateway instances and register with the event handler. 5. In the construct method of SnsGateway, we register with the relevant event handlers. result MySNSClass::Initialize() { result r = E_SUCCESS; pSNSAuthenticator = new SnsAuthenticator; r = pSNSAuthenticator->Construct(*this); if(IsFailed(r)) { AppLog(“Cannot initialize SnsAuthenticator ::: %s”, GetErrorMessage(r)); return r; }

19_974018-gr07.indd 42619_974018-gr07.indd 426

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

427

pSnsGateway = new SnsGateway(); // Be cautious in registering with listeners, if you miss this step // you will not be able to get any event. // here second argument is for ISnsContentListener r = pSnsGateway->Construct(*this, this, null, null); AppLog(“ SnsGateway ::: %s”, GetErrorMessage(r)); if(IsFailed(r)) { AppLog(“Cannot initialize SnsGateway ::: %s”, GetErrorMessage(r)); return r; } return r; }

6. Now, we are done with the instance creation process and can proceed to authentication. In this example, Facebook appId and appSecret keys are required. Substitute the real keys for the dummy values shown here. result MySNSClass::Authenticate(void) { result r = E_SUCCESS; String serviceProvider = “facebook”; //can be twitter for twitter String appID = “xyz”; //provided by facebook/twitter etc String appSecret = “abc”; // provided by facebook/twitter etc r = pSNSAuthenticator->Authenticate(serviceProvider, appID, appSecret); if (IsFailed(r)) AppLog(“Fail to Authenticate. [%s]”, GetErrorMessage(r)); return r; }

7. The result of step 6 will be returned in OnSnsAuthenticated, which is an ISnsAuthenticatorListener event handler. Do remember to add the authentication result with SNSGateway, as shown below. void MySNSClass::OnSnsAuthenticated(SnsAuthResult& snsAuthResult, result r, const String& errorCode, const Osp::Base ::String& errorMsg) {

19_974018-gr07.indd 42719_974018-gr07.indd 427

8/31/10 12:42 AM8/31/10 12:42 AM

428

Part II



Recipes

if (snsAuthResult.GetTokenKey().IsEmpty()) { AppLog(“Fail : OnSnsAuthenticated[%s][%S][%S]”, GetErrorMessage(r), errorCode.GetPointer(), errorMsg.GetPointer()); } else { pSnsGateway->AddAuthResult(snsAuthResult); } }

8. If authentication is successful, you can now use the features provided by SnsGateway. 9. Here, in this application scenario let’s suppose you want to get the list of photo albums for the logged in user who is using this application. To do, so, call the GetPhotoAlbums method of SnsGateway. result MySNSClass::GetAlbums(void) { result r = E_SUCCESS; RequestId reqId = INVALID_REQUEST_ID; SnsPagingParam pagingParam(5); String serviceProvider = pSNSAuthResult->GetServiceProvider(); r = pSnsGateway->GetPhotoAlbums(serviceProvider, null, pagingParam, reqId); if (IsFailed(r)) AppLog(“Fail to . [%s]”, GetErrorMessage(r)); return r; }

10. You get the response in call-back function OnSnsPhotoAlbums ReceivedN. Note the trailing ‘N’, which means that we are required to destroy any objects returned by the method. result MySNSClass:: OnSnsPhotoAlbumsReceivedN(RequestId reqId, IList *pAlbumList, bool hasNext, SnsPagingParam& pagingParam, result r, const String &error-Code, const String &errorMsg) {

19_974018-gr07.indd 42819_974018-gr07.indd 428

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

429

if (IsFailed(r)) { Util::ShowMessage(L”Error!”, L”Sorry, can’t get the Albums.”); AppLog(“OnSnsPhotoAlbumsReceivedN() is failed.); return; } IEnumerator* SnsAlbumInfo* String String

pEnum = null; pAlbum = null; albumId; albumTitle;

//make item to add following list Util::DeleteList(pAlbumList); pAlbumList = pAlbumList; pEnum = pAlbumList->GetEnumeratorN(); while (pEnum->MoveNext() != E_OUT_OF_RANGE) { pAlbum = static_cast(pEnum->GetCurrent()); albumId = pAlbum->GetAlbumId(); pAlbum->GetValue(SNS_ALBUM_PID_TITLE, albumTitle); //You can use this value as per the requirement } delete pEnum; }

Hints, Pitfalls, and Related Topics Be sure to register the appropriate event handlers during construction of the SnsGateway instance, in step 4 above. Each type of listener has a different position in the argument list to the Constructor. Remember, also, to add SnsAuthResult to the SnsGateway instance. This authentication result is crucial, especially if you want to incorporate other features that are not supported out of the box by the bada SNS Gateway; in this case, you can interact with the RESTful API’s provided by the service provider using the token key and token secret, which are generated as part of the application authentication process.

19_974018-gr07.indd 42919_974018-gr07.indd 429

8/31/10 12:42 AM8/31/10 12:42 AM

430

Part II



Recipes

Related Recipes ■■

Add a Form to a Frame-based App

■■

Create an AppControl to Interact with a Base App

7.3 Send a Tweet from Twitter Problem Description You need to post a tweet to Twitter.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Social::Services, Osp::Base::Collection

Header files to #include: FSocial.h

FBase.h

Required libraries:

FSocial, FSocialServices, FSocialServicesSnsAuth

Required privilege level: System

Required privilege groups: SNS_SERVICE

The bada SNS Gateway makes it easy to submit a tweet to Twitter from within an app. The basic steps for interacting with the Gateway are described in the recipe ‘Use the bada SNS Gateway to Access a Social Network Service such as Facebook’. When authenticating with the Gateway to use Facebook you should specify facebook as the service provider: String serviceProvider = “facebook”; r = pSNSAuthenticator->Authenticate(serviceProvider, appID, appSecret);

The same comments apply in this recipe as in related recipes about the keys needed to authenticate with SNS, and about required bada Privileges. For more about both topics, and for Facebook-specific guidance, see the documentation at developer.bada.com.

19_974018-gr07.indd 43019_974018-gr07.indd 430

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

431

Follow the steps 1–7 in the recipe ‘Use the bada SNS Gateway to Access a Social Network Service such as Facebook’ to set up and authenticate with the SNS Gateway. To do so your requesting class should inherit from ISnsAuthenticatorListener and ISnsGatewayListener. After your app has successfully authenticated with the bada Server, you can go on to post tweets. To do so, you use the ISnsPeopleListener interface. Figure R7.2 shows an app that provides users with a simple editable control to write text in, and an update button that sends the text as a tweet from the user’s Twitter account.

Figure R7.2 Writing and posting a tweet to a Twitter account. The Update button posts the tweet, which you can see displayed in the Twitter stream below.

Let’s see how this looks in code. 1. Derive your class from ISnsAuthenticatorListener for authentication via SnsAuthenticator, from ISnsGatewayListener for SnsGateway functions, and from ISnsPeopleListener for the interaction with Twitter. Note that your implementations of unused interface methods can be empty.

19_974018-gr07.indd 43119_974018-gr07.indd 431

8/31/10 12:42 AM8/31/10 12:42 AM

432

Part II



Recipes

#include class MyTwitterClass : public Osp::Social::Services::ISnsAuthenticatorListener, public Osp::Social::Services::ISnsGatewayListener, public Osp::Social::Services::ISnsPeopleListener { Osp::Social::Services::SnsGateway* pSnsGateway; Osp::Social::Services::SnsAuthenticator* pSNSAuthenticator; Osp::Social::Services::SnsAuthResult* pSNSAuthResult; result Initialize(void); result SubmitTweet(const Osp::Base::String tweet); // ISnsAuthenticatorListener function void OnSnsAuthenticated(Osp::Social::Services::SnsAuthResult &snsAuthResult, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMsg); // ISnsGatewayListener void OnSnsLoggedInStatusReceived(RequestId reqId, Osp::Base::String& serviceProvider, bool isLoggedIn, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMsg);

// ISnsPeopleListener void OnMySnsBuddiesReceivedN(RequestId reqId, Osp::Base::Collection::IList *pBuddyProfileList, bool hasNext, Osp::Social::Services::SnsPagingParam &pagingParam, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg); void OnSnsStatusTextReceived(RequestId reqId, Osp::Social::Services::SnsStatusText *pStatusText, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg); void OnSnsProfileReceived(RequestId reqId, Osp::Social::Services::SnsProfile *pProfile, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg);

19_974018-gr07.indd 43219_974018-gr07.indd 432

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

433

void OnMySnsStatusTextUpdated(RequestId reqId, Osp::Base::String &serviceProvider, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg);

2. Authentication follows the steps shown in the recipe ‘Use the bada SNS Gateway to Access a Social Network Service such as Facebook’, except for the position of the intended listener method supplied as an argument when you construct the SnsGateway instance. To use Twitter the listener is ISnsPeopleListener, which is supplied as the third argument in the function call (as this, because we make the call from an ISnsContentListener -derived class): pSnsGateway->Construct(*this, null, this, null);

3. After successful authentication, post the tweet with: pSnsGateway->UpdateMyStatusText(L”twitter”, tweet, reqId);

where L”twitter” is the requested service (note use of the L macro to construct the string), tweet is the message text, and reqId is a RequestId that will be filled by the server when the request completes (you might use it to track which call completed if you are making multiple requests to the server). result MyTwitterClass:: SubmitTweet(const String tweet) { result r = E_SUCCESS; RequestId reqId = INVALID_REQUEST_ID; r =pSnsGateway->UpdateMyStatusText(L”twitter”, tweet, reqId); if (IsFailed(r)) AppLog(“Fail to . [%s]”, GetErrorMessage(r)); return r; }

4. On completion, SnsGateway::OnMySnsStatusTextUpdated() is the call-back method that contains the results of the update request. Implement this method to handle any errors. The value in result r contains the result of the update request, and the errorCode and errorMsg strings give further information about any error. void MyTwitterClass::OnMySnsStatusTextUpdated (RequestId reqId, String &serviceProvider, result r, const String &errorCode, const String &errorMsg)

19_974018-gr07.indd 43319_974018-gr07.indd 433

8/31/10 12:42 AM8/31/10 12:42 AM

434

Part II



Recipes

if (IsFailed(r)) { AppLog(“Sorry, can’t update status text.”); } }

Hints, Pitfalls, and Related Topics Make sure that the correct event handler is registered when constructing the SnsGateway instance (see step 2). Otherwise, your app will not receive the expected call-back. An alternative approach to using Twitter from your applications is to use Twitter’s own RESTful APIs directly. You can use bada’s HTTP API to achieve this. Using Twitter APIs directly gives you greater flexibility, but is of course more complex.

Related Recipe ■■

Use the bada SNS Gateway to Access a Social Network Service such as Facebook

7.4 Upload a Photo to Facebook Problem Description You want to upload a photo to Facebook from your app.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Social::Services

Header files to #include: FSocial.h

Required libraries:

FSocial, FSocialServices, FSocialServicesSnsAuth

Required privilege level: System

Required privilege groups: SNS_SERVICE

19_974018-gr07.indd 43419_974018-gr07.indd 434

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

435

You can easily upload a photo to Facebook from your app by using the bada SNS Gateway. The basic steps for interacting with the Gateway are described in the recipe ‘Use the bada SNS Gateway to Access a Social Network Service such as Facebook’. The steps required to use Facebook via the Gateway are similar to those for Twitter, described in the recipe ‘Send a Tweet from Twitter’. When authenticating with the Gateway to use Facebook you should specify facebook as the service provider: String serviceProvider = “facebook”; r = pSNSAuthenticator->Authenticate(serviceProvider, appID, appSecret);

The same comments apply in this recipe as in related recipes about the keys needed to authenticate with social network services, and about required bada privileges. For more about both topics, and for Facebook-specific guidance, see the documentation at developer.bada.com. Follow the steps 1–7 in the recipe ‘Use the bada SNS Gateway to Access a Social Network Service such as Facebook’ to set up and authenticate with the SNS Gateway. To do so your requesting class should inherit from ISns AuthenticatorListener and ISnsGatewayListener. In addition, to upload a photo to Facebook, inherit the ISnsContent Listener interface and implement the ISnsContentListener::OnSns PhotoUploaded() method, which will receive the response from the framework when your upload request completes. To upload the photo, call the SnsGateway::UploadPhoto() method. Let’s see how this looks in code. 1. Inherit the required interface classes and provide implementations of the interface methods. Note that many of these can be empty implementations. For example, the only ISnsContentListener method we require is OnSnsPhotoUploaded(). #include class MyFacebookClass : public Osp::Social::Services::ISnsAuthenticatorListener, public Osp::Social::Services::ISnsGatewayListener, public Osp::Social::Services::ISnsContentListener { Osp::Social::Services::SnsGateway* pSnsGateway; Osp::Social::Services::SnsAuthenticator* pSNSAuthenticator; Osp::Social::Services::SnsAuthResult* pSNSAuthResult; result Construct(void); result Authenticate(void);

19_974018-gr07.indd 43519_974018-gr07.indd 435

8/31/10 12:42 AM8/31/10 12:42 AM

436

Part II



Recipes

// ISnsAuthenticatorListener function void OnSnsAuthenticated(Osp::Social::Services::SnsAuthResult& snsAuthResult, result r, const String& errorCode, const String& errorMsg); // ISnsGatewayListener Listener void OnSnsLoggedInStatusReceived(RequestId reqId, Osp::Base::String& serviceProvider, bool isLoggedIn, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMsg); result UploadPhoto(void); // ISnsContentListener functions void OnSnsPhotoReceived(RequestId reqId, Osp::Social::Services::SnsPhotoInfo *pPhoto, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg); void OnSnsPhotosByUserReceivedN(RequestId reqId, Osp::Base::Collection::IList *pPhotoList, bool hasNext, Osp::Social::Services::SnsPagingParam& pagingParam, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg); void OnSnsPhotosInAlbumReceivedN(RequestId reqId, Osp::Base::Collection::IList *pPhotoList, bool hasNext, Osp::Social::Services::SnsPagingParam& pagingParam, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg); void OnSnsPhotoUploaded(RequestId reqId, Osp::Base::String &serviceProvider, Osp::Base::String *pPhotoId, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg); };

19_974018-gr07.indd 43619_974018-gr07.indd 436

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

437

2. Authentication follows the steps shown in the recipe ‘Use the bada SNS Gateway to Access a Social Network Service such as Facebook’, except for the position of the intended listener method supplied as an argument when you construct the SnsGateway instance. To upload images the listener is ISnsContentListener, which is supplied as the second argument in the function call (as this, because we make the call from an ISnsContentListener -derived class): pSnsGateway->Construct(*this, this, null, null);

3. After successful authentication, upload the photo with: r = pSnsGateway->UploadPhoto(serviceProvider, null, *pContentInfo, reqId);

where serviceProvider is a String specifying Facebook and pContent Info is an instance of SnsUploadContentInfo*, which encapsulates the content to be uploaded – in this case the photo, specified by a file path. void MyFacebookClass::UploadPhotos(void) { RequestId reqId = INVALID_REQUEST_ID; result r = E_SUCCESS; String filepath = “/Home/upload/1.jpg”; String serviceProvider = pSNSAuthResult->GetServiceProvider(); SnsUploadContentInfo* pContentInfo = new SnsUploadContentInfo(SNS_UPLOAD_CONTENT_PHOTO, filepath); r = pSnsGateway->UploadPhoto(serviceProvider, null, *pContentInfo, reqId); delete pContentInfo; pContentInfo = null; }

Note: The SnsUploadContentInfo class provides methods to set the title, tag, and other content details, but not all of these are currently supported for Facebook. For more details about which features are supported for which services, see the documentation at developer.bada.com. 4. On completion, SnsGateway::OnSnsPhotoUploaded() is the call-back method that contains the results of your upload request.

19_974018-gr07.indd 43719_974018-gr07.indd 437

8/31/10 12:42 AM8/31/10 12:42 AM

438

Part II



Recipes

Implement this method to handle any errors. The value in result r contains the result of the update request, and the errorCode and errorMsg strings give further information about any error: void MyFacebookClass::OnSnsPhotoUploaded(RequestId reqId, Osp::Base::String &serviceProvider, Osp::Base::String *pPhotoId, result r, const Osp::Base::String &errorCode, const Osp::Base::String &errorMsg) { If (!isFailed(r)) { AppLog(“Successfully uploaded the photo with photoId as %ls”,pPhotoId->GetPointer()); } }

Hints, Pitfalls, and Related Topics Be aware of the argument position when you pass the listener instance ISnsContentListener to the SnsGateway constructor in step 2; ISnsContentListener is expected as the second argument, and arguments three and four should be null. As an alternative to using the SNS Gateway, you can use Facebook’s RESTful APIs directly from your applications using bada’s HTTP API. Using the SNS Gateway is much less complex, but using the Facebook APIs directly gives you greater flexibility. See the recipe ‘Get Notes from Facebook using RESTful APIs’ for more information. Note that if you do not set the destination album in UploadPhoto(), the uploaded photo will go to the default album; this is created with the app name, that is, the name for which Facebook has provided the API key and API secret. At the time of writing, you cannot set the title and other properties of a photo you upload through the SNS Gateway, although you can set the caption.

Related Recipes ■■

Use the bada SNS Gateway to Access a Social Network Service such as Facebook

■■

Send a Tweet from Twitter

■■

Get Notes from Facebook using RESTful APIs

19_974018-gr07.indd 43819_974018-gr07.indd 438

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

439

7.5 Get Notes from Facebook using RESTful APIs Problem Description You want to get notes from a Facebook account and use them in your app.

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Social::Services, Osp::Base, Osp::Base::Collection, Osp::System, Osp::Security, Osp::Security::Crypto, Osp::Base::Utility, Osp::Net::Http

Header files to #include:

FUi.h, FSocial.h, FSecurity.h , FNet.h

Required libraries:

FSocial, FSocialServices FSocialServicesSnsAuth, FSecurity, FNet FSystem

Required privilege level: System

Required privilege groups: SNS_SERVICE, HTTP

There will be times when you need to use a service feature that is not supported by the SNS Gateway. Getting notes from Facebook is one example. In such cases you must use Facebook’s RESTful APIs directly. The steps for doing this are described in this recipe. In summary, they are: 1. Follow the recipe ‘Use the bada SNS Gateway to Access a Social Network Service such as Facebook’ to get the token key and secret. 2. Use bada HTTP services to request the Facebook ‘Notes’ URL. 3. You’ll need to use bada Crypto services, because Facebook requires the URL request parameters to be MD5Hash signed. 4. The HTTP response returns XML data. 5. Follow the recipe ‘Parse XML Content’ to parse the XML and extract the content you want. The same comments apply here as in related recipes about the keys needed to authenticate with SNS, and about required bada privileges. For more about both topics, and for Facebook-specific guidance, see the documentation at developer.bada.com.

19_974018-gr07.indd 43919_974018-gr07.indd 439

8/31/10 12:42 AM8/31/10 12:42 AM

440

Part II



Recipes

Figure R7.3 shows the Facebook notes displayed after download.

Figure R7.3 The Notes retrieved from Facebook.

Let’s see how it looks in code. 1. For initial authentication, you can use the SNS Gateway SnsAuthenticator. Follow steps 1–7 in the recipe ‘Use the bada SNS Gateway to Access a Social Network Service such as Facebook’ to set up and authenticate with the SNS Gateway. To do so your requesting class should inherit from ISnsAuthenticatorListener and ISnsGatewayListener. 2. On successful authentication, the OnSnsAuthenticated() call-back returns a SnsAuthResult object that contains a key token and secret token. You can use these tokens to further communicate directly with the RESTful APIs of the SNS site, in this case Facebook. 3. Inherit from the Osp::Net::Http::IHttpTransactionEventListener interface to receive HTTP transaction events. Note that you will need to check the Facebook API documentation to see how to use the Notes interface; it provides details of the method to be called and the required parameters.

19_974018-gr07.indd 44019_974018-gr07.indd 440

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

441

#include #include class MyClass : public Osp::Net::Http::IHttpTransactionEventListener { Public: MyClass(); ~ MyClass(); Private: Osp::Net::Http::HttpSession* pSession; Osp::Base::String authToken; Osp::Base::String authTokenSecret; void GetNotes(void); void SendRequest(Osp::Base::String reqString); Osp::Base::String MakeRequestUrl(const Osp::Base::String& method); Osp::Base::String GenerateSignature(const Osp::Base::String& requestStr); //Generates the MD5Hash signature //HTTP functions void OnTransactionReadyToRead (Osp::Net::Http ::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction, int availableBodyLen); void OnTransactionAborted(Osp::Net::Http::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction, result r); void OnTransactionReadyToWrite (Osp::Net::Http::HttpSession &httpSession, Osp::Net::Http::HttpTransaction& httpTransaction, int recommendedChunkSize); void OnTransactionHeaderCompleted (Osp::Net::Http::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction, int headerLen, bool rs);

19_974018-gr07.indd 44119_974018-gr07.indd 441

8/31/10 12:42 AM8/31/10 12:42 AM

442

Part II



Recipes

void OnTransactionCompleted (Osp::Net::Http::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction); void OnTransactionCertVerificationRequiredN (Osp::Net::Http::HttpSession& httpSession, Osp::Net::Http::HttpTransaction& httpTransaction, Osp::Base::String* pCert); };

4. The GetNotes() method encapsulates the steps required to construct the URL request string and send the HTTP request. The Facebook API method called is facebook.notes.get. void MyClass:: GetNotes(void) { String url = L”http://api.facebook.com/restserver.php?”; String method = L”facebook.notes.get”; String requestString = MakeRequestString(method); String requestUrl = url + requestString; SendRequest(requestUrl); }

5. The MakeRequestString() method encapsulates the steps required to create the parameter string we will send to the facebook.notes. get API. We must provide an API key, specify the Open API (must be version 1.0), the session key, the method name, and so on. 6. The session key is the key generated by the Gateway authentication process (see step 2). 7. We construct the string, and then sort the parameter list alphabetically, and finally generate an MD5Hash signature by using the secret token generated in the Gateway authentication process. 8. Finally we append this signature to the request string. String MyClass:: MakeRequestString() { String apiKey = L”api_key=”; String callId = L”call_id=”; String version = L”v=”; String signature = L”sig=”; String sessionKey = L”session_key=”; String methodParam = L”method=”; String paramString; String requestString; String signatureStr; long long secTimeStamp = 0;

19_974018-gr07.indd 44219_974018-gr07.indd 442

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

443

String appID; SetAuthData(); apiKey.Append(“xyz”);

//api Id of the registered application

// callId // 1. Get current system time via SystemTime::GetTicks(). // 2. Make time in seconds. SystemTime::GetTicks(secTimeStamp); callId.Append(secTimeStamp); // version : 1.0 version.Append(L”1.0”); // sessionKey sessionKey.Append(authToken); // method methodParam.Append(method); ArrayList* pParamList = new ArrayList; StringComparer* pStringComp = new StringComparer(); pParamList->Construct(); pParamList->Add(*(new String(apiKey))); pParamList->Add(*(new String(callId))); pParamList->Add(*(new String(version))); pParamList->Add(*(new String(sessionKey))); pParamList->Add(*(new String(methodParam))); StringTokenizer strTok(additionalParams, L”&”); String param; while (strTok.HasMoreTokens()) { strTok.GetNextToken(param); pParamList->Add(*(new String(param))); } pParamList->Sort(*pStringComp); for (int count = 0; count < pParamList->GetCount(); count++) { String* pStr = static_cast(pParamList->GetAt(count)); paramString.Append(*pStr); }

19_974018-gr07.indd 44319_974018-gr07.indd 443

8/31/10 12:42 AM8/31/10 12:42 AM

444

Part II



Recipes

paramString.Append(authTokenSecret); signatureStr = GenerateSignature(paramString); signature.Append(signatureStr); pParamList->Add(*(new String(signature))); for (int count = 0; count < pParamList->GetCount(); count++) { String* pStr = static_cast(pParamList->GetAt(count)); requestString.Append(*pStr); if (count < pParamList->GetCount()-1) { requestString.Append(L”&”); } } pParamList->RemoveAll(true); delete pParamList; pParamList = null; delete pStringComp; pStringComp = null; return requestString; }

9. Now we can use the HTTP SendRequest method to send the request string. void MyClass::SendRequest(String requestUrl) { result r = E_SUCCESS; HttpTransaction* pTransaction = null; HttpRequest* pRequest = null; String hostAddr(L”api.facebook.com”); if (pSession == null) { pSession = new HttpSession(); r = pSession->Construct(NET_HTTP_SESSION_MODE_NORMAL, null, hostAddr, null); if (IsFailed(r)) { AppLog(“Fail to HttpSession::Construct. [%s]”, GetErrorMessage(r)); return; }

19_974018-gr07.indd 44419_974018-gr07.indd 444

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

445

} pTransaction = pSession->OpenTransactionN(); if (pTransaction) { pTransaction->AddHttpTransactionListener(*this); pRequest = pTransaction->GetRequest(); if (pRequest) { pRequest->SetUri(requestUrl); pRequest->SetMethod(NET_HTTP_METHOD_GET); r = pTransaction->Submit(); if (IsFailed(r)) { AppLog(“Fail to HttpRequest::Submit. [%s]”, GetErrorMessage(r)); } } else { delete pTransaction; pTransaction = null; } } }

10. The HTTP request is made asynchronously, and results in a call-back when it completes. The call-back method is the OnTransactionReadyToRead method of the IHttpTransactionEventListenerderived requesting class. Implement this method to receive the data you requested from Facebook. void MyClass::OnTransactionReadyToRead (HttpSession& httpSession, HttpTransaction& httpTransaction, int availableBodyLen) { // Get the response from the HTTP HttpResponse* pHttpResponse = httpTransaction.GetResponse(); // Get buffer received ByteBuffer* pBuffer = pHttpResponse->ReadBodyN(); //Now you can utilize this pBuffer data, these contain Notes in XML

19_974018-gr07.indd 44519_974018-gr07.indd 445

8/31/10 12:42 AM8/31/10 12:42 AM

446

Part II



Recipes

//format delete pBuffer; pBuffer = null; }

The Facebook API we called returns data in XML format. To parse XML, use the APIs in the bada Osp::XML namespace, which includes an implementation of the libXml2 XML library. For an example of XML parsing, see the recipe ‘Parse XML Content’ (which uses the returned Facebook XML data as its example). 11. Finally, you should delete the HttpTransaction pointer. void MyClass::OnTransactionAborted (HttpSession& httpSession, HttpTransaction& httpTransaction, result r) { delete &httpTransaction; } void MyClass::OnTransactionCompleted (HttpSession& httpSession, HttpTransaction& httpTransaction) { delete &httpTransaction; }

Hints, Pitfalls, and Related Topics The secret token (generated by the SNS Gateway authentication process) is used as the session key, and for generating the MD5 signature.

Related Recipes ■■

Use the bada SNS Gateway to Access a Social Network Service such as Facebook

■■

Parse XML Content

7.6 Use the BuddyService to Add a Buddy Problem Description You want to search for someone on the bada Server, and add them as your buddy.

19_974018-gr07.indd 44619_974018-gr07.indd 446

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

447

The Recipe The following configuration is required for this recipe: Namespaces used:

Osp::Social, Osp::Social::Services

Header files to #include: FSocial.h

Required libraries:

FSocial, FSocialServices

Required privilege level: System

Required privilege groups: BUDDY_SERVICE

This recipe uses the Osp::Social and Osp::Social::Services namespaces to provide access to the social features of bada. It is a more detailed implementation of the request for a buddy presented in Chapter 5. There are some prerequisites to using this feature in your application. First, your application profile has to be registered with System-level privilege on the bada developer web site. Second, you have to have a valid Samsung account, which you get for free, and sign in. There are two steps to adding a buddy: 1. Search the profile by passing a name, email address or login ID using the ProfileService class. 2. Send the buddy request to that particular user using the BuddyService class. To use these two classes, you have to implement the listener interface class to handle the results received from the bada Server. Let’s first implement our own listener class called MyListener. In a concrete project, you would probably use one of your UI classes, in which you want to display the results from the server, as your listener. This would mean that your UI class would inherit from the IProfileServiceListener and IBuddyServiceListener interfaces. But you can also have your own class to handle the results, as we show below. //MyListener class implementation class MyListener : public Osp::Social::Services::IProfileServiceListener, public Osp::Social::Services::IBuddyServiceListener { public: MyListener(){};

19_974018-gr07.indd 44719_974018-gr07.indd 447

8/31/10 12:42 AM8/31/10 12:42 AM

448

Part II



Recipes

~MyListener(){}; //Declare the virtual methods from interfaces void OnProfileSearchResultsReceivedN( RequestId reqId, Osp::Base::Collection::IList* pBasicProfileList, int pageNo, int countPerPage, int totalPageCount, int totalCount, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMsg); void OnBuddyRequestSent( RequestId reqId, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMsg); };

Below is the implementation of the IProfileServiceListener method: void MyListener::OnProfileSearchResultsReceivedN( RequestId reqId, IList* pBasicProfileList, int pageNo, int countPerPage, int totalPageCount, int totalCount, result r, const String& errorCode, const& errorMsg) { //UI list for displaying received profiles List* pProfileListControl; pProfileListControl = new List(); pProfileListControl->Construct(Rectangle(0, 0, 450, 600), LIST_STYLE_RADIO, LIST_ITEM_SINGLE_TEXT, 100, 0, 450, 0 ); if(pBasicProfileList->GetCount() == 0) { AppLog(“No matched profiles found!”); pProfileListResult = null; // pProfileListResult is defined // outside of this function } else { String itemString; BasicProfile* pProfile = null; IEnumerator* pEnum = pBasicProfileList->GetEnumeratorN(); while (E_SUCCESS == pEnum->MoveNext()) { pProfile = (BasicProfile* )pEnum->GetCurrent(); if (null != pProfile) { itemString = pProfile->GetValue(BP_PID_USER_NAME) + L” (“ + pProfile->GetValue(BP_PID_GENDER) + L”)”; pProfileListControl->AddItem(&itemString, null , null, null); } } delete pEnum; pProfileListResult = pBasicProfileList; } // Now you can use the pProfileListControl to display the results, and // pProfileListResult to retrieve the userID of the buddy you want // to add } //Below is the implementation of the IBuddyServiceListener method

19_974018-gr07.indd 44819_974018-gr07.indd 448

8/31/10 12:42 AM8/31/10 12:42 AM

Group 7



Services and Social Networking

449

void MyListener::OnBuddyRequestSent( RequestId reqId, result r, const Osp::Base::String& errorCode, const Osp::Base::String& errorMsg) { //You can check the results when buddy request is sent if (IsFailed(r)) { AppLog(“Fail to request buddy. (%s, %S)”, GetErrorMessage(r), errorMsg.GetPointer()); if(E_CONNECTION_FAILED == r) AppLog(“Network connection is failed.”); } else { AppLog(“Successfully sent a buddy request.”); } }

The following code snippet demonstrates how you could use the ProfileService class to search for the person you want to add as a buddy on the server side. MyListener* pMyListener; pMyListener = new MyListener(); int pageNo = 1; //Number of pages used to display the results int countPerPage = 20; //Number of profiles per page RequestId reqId; ProfileService* pProfileService; pProfileService = new ProfileService(); pProfileService->Construct(*pMyListener); List* pProfileListResult; // keep track of memory allocated by // OnProfileSearchResultsReceivedN() pProfileService->SearchProfilesByName(L”firstName”, L”lastName”, null, null, reqId, pageNo, countPerPage);

When you send the SearchProfileByName() request to the server, the listener object will catch the results from the server asynchronously. The pProfileListResult object holds the userID for the person that you want to add as a buddy. To send a buddy request to this person you have to use the BuddyService class. Below is the code snippet for sending the buddy request: BuddyService* pBuddyService; pBuddyService = new BuddyService(); pBuddyService->Construct(*pMyListener); //The same MyListener object //from before BasicProfile* pProfile = null; pProfile = (BasicProfile*) pProfileListResult->GetAt(0); //Assuming that //the first entry in the list is the person you want to add as buddy pBuddyService->RequestBuddy(pProfile->GetUserId(), reqId);

19_974018-gr07.indd 44919_974018-gr07.indd 449

8/31/10 12:42 AM8/31/10 12:42 AM

450

Part II



Recipes

Finally, assuming your buddy request has been successfully sent to the server, the person you sent the request to needs to check the received request and respond to it. This process is described in detail in Chapter 5.

Hints, Pitfalls, and Related Topics The buddy service is a powerful and convenient feature in bada. But be aware of how the request and response between the device and the bada Server work. The call-back function is invoked asynchronously, and there may be network errors and delays. So it is always recommended to track all error messages. Sometime if you don’t find the person you want to add as buddy, it might be because their profile is not set as PROFILE_SEARCHABLE. The BuddyManager sample from the SDK provides a more detailed implementation and functions for handling buddies. Please feel free to use this in your own implementations.

19_974018-gr07.indd 45019_974018-gr07.indd 450

8/31/10 12:42 AM8/31/10 12:42 AM

PART

III Appendices

20_974018-pp03.indd 45120_974018-pp03.indd 451

8/31/10 12:43 AM8/31/10 12:43 AM

20_974018-pp03.indd 45220_974018-pp03.indd 452

8/31/10 12:43 AM8/31/10 12:43 AM

APPENDIX

A Downloading and Installing the bada SDK

To get the latest version of the bada SDK, visit the developer site at developer.bada.com. Before you download, you first need to be a registered bada developer. Don’t worry, it’s free and once you’re signed up, you also have access to all the support resources on the site, including developer forums, blog postings, and other useful information. The details in this appendix apply to version 1.0.0b3 of the SDK, so you may notice some differences in later versions of the SDK you may use. Note: At the time of writing, the system requirements to install the bada SDK are: Microsoft Windows, XP, Vista, or Windows 7 and 1.8 GB of free hard disk space. To download the SDK, go to the Development Tools section of the site and choose SDK/IDE, as shown in Figure A.1. You’ll notice that there are two versions of the SDK available for download: ■■

Full package: IDE and Simulator/Target SDK (Language Pack 1, 2, 3 and 4)

■■

SDK Installer: IDE and Simulator/Target SDK

You can choose a full version that contains all the language packs, or a smaller download that allows you to choose a subset. Both downloads include the IDE and all the files you need to develop for the Simulator and a target device. 453

21_974018-bapp01.indd 45321_974018-bapp01.indd 453

8/31/10 12:43 AM8/31/10 12:43 AM

454

Part III



Appendices

Figure A.1 Downloading the bada SDK from developer.bada.com.

If you download the smaller version and start the install process, you’ll see a screen allowing you to choose language packs, as shown in Figure A.2. The installer will guide you through the rest of the installation process.

Figure A.2 Choosing which language packs to install during the SDK download.

21_974018-bapp01.indd 45421_974018-bapp01.indd 454

8/31/10 12:43 AM8/31/10 12:43 AM

Appendix A



Downloading and Installing the bada SDK

455

When the installation is finished, you’ll see the bada SDK welcome screen as shown in Figure A.3. We’ll talk about accessing help information a bit later, but for now you probably can’t wait to get started with the development environment, so choose the workbench icon (or just close the welcome screen to take you to the workbench). The workbench will be displayed together with the bada SDK examples, as shown in the window to the right of Figure A.4. Note: You can show the SDK examples view at any time by choosing Window | Show View | Other | bada | bada SDK Samples. Right click on one of the samples and choose Copy into my workspace. The selected project will then be copied to your workspace for building and running. Build the project by clicking the hammer icon or choosing Project | Build Project. To run the project, select the Run button or choose Run| Run As | bada simulator application. Figure A.4 shows the AnimationApp sample in the SDK about to be run, while Figure A.5 shows the application running in the Simulator.

Figure A.3 The bada SDK welcome screen.

21_974018-bapp01.indd 45521_974018-bapp01.indd 455

8/31/10 12:43 AM8/31/10 12:43 AM

456

Part III



Appendices

Figure A.4 Preparing to run one of the SDK examples in the Simulator.

Figure A.5 Running the AnimationApp sample in the Simulator.

21_974018-bapp01.indd 45621_974018-bapp01.indd 456

8/31/10 12:43 AM8/31/10 12:43 AM

Appendix A



Downloading and Installing the bada SDK

457

With the SDK all set up, you’re ready to develop your own applications. We guide you through the bada development process in detail starting in Chapter 2. Apart from the samples included with the SDK, another useful development resource is the extensive help system. To open the help choose Help | Help Contents in the IDE. Figure A.6 shows the help system. From here you can get more information about all of the bada namespaces and classes, the bada developer guide, and a guide to UI development.

Figure A.6 the help system in the bada SDK.

21_974018-bapp01.indd 45721_974018-bapp01.indd 457

8/31/10 12:43 AM8/31/10 12:43 AM

21_974018-bapp01.indd 45821_974018-bapp01.indd 458

8/31/10 12:43 AM8/31/10 12:43 AM

APPENDIX

B A UML Primer

This appendix gives an explanation of the subset of UML notation that we’ve used in the book.

B.1 Class Diagrams Interface inheritance Queue derives from and implements the interface defined by ICollection. See Chapter 4, ‘bada Fundamentals’, for more information about interfaces. Inheritance Both AudioContentInfo and VideoContentInfo derive from ContentInfo.

(continued)

459

22_974018-bapp02.indd 45922_974018-bapp02.indd 459

8/31/10 12:44 AM8/31/10 12:44 AM

460

Part III



Appendices

(continued) Dependencies LocationProvider uses IAreaListener and ILocationListener to provide location updates.

Simple association CurrentWeather and WeatherForecast are connected to IWeatherEventListener in some way; the classes work together. The application requests a list of WeatherForecast or the CurrentWeather and this will be returned using the IWeatherEventListener. Composition Route contains one or more RouteSegment. If the diamond is not filled in, this represents aggregation, a ‘has a’ relationship.

Note: The UML class diagrams in Chapter 6 were created using the excellent free online tool yUML, available at: yuml.me.

B.2 Sequence Diagrams Sequence diagrams show how objects and processes interact with each other over a timeline – the vertical line shown on the diagrams in Chapter 5, representing the lifetime of an object. In Chapter 5, we use sequence diagrams to show how the application interacts with the bada Server in response to user requests, such as to make their profile searchable, and how messages are sent between the objects involved in handling the request.

22_974018-bapp02.indd 46022_974018-bapp02.indd 460

8/31/10 12:44 AM8/31/10 12:44 AM

Appendix B



A UML Primer

461

An entity. In this case the object MyBuddyService of class BuddyService.

A message sent between objects.

A response to a request.

A process performed in response to a message.

Note: The sequence diagrams used in Chapter 5 were created using the free online web tool at www.websequencediagrams.com.

22_974018-bapp02.indd 46122_974018-bapp02.indd 461

8/31/10 12:44 AM8/31/10 12:44 AM

22_974018-bapp02.indd 46222_974018-bapp02.indd 462

8/31/10 12:44 AM8/31/10 12:44 AM

APPENDIX

C A Software Engineering Model for Mobile App Development

As we mentioned early in the book (see Chapter 1), to successfully develop a mobile software solution you should follow an engineering process that helps you address the specific characteristics of mobile software. We refer to this as mobile software engineering. Such a process is ideally highly agile, incorporating several macro and micro-iterations. Of course, you can follow any process you prefer, or develop your software without following any process at all. There is a range, from a strict waterfall model to cowboy coding. As a rule of thumb the more complex a project is and the more coordination it requires the more formalisation in terms of processes is advisable. Experience has shown that so called agile processes are very appropriate with software for fast-paced markets, which is definitely the case in mobile app development. From a high-level point of view, there is no difference between developing software for desktops, servers, the Web or for mobile devices. It is all software engineering and the basic steps are always the same: requirements, design, programming, testing, and deployment. However, it is the detail that makes the difference. From experience we can say that it is not possible to simply transfer the techniques of traditional software engineering one-toone to mobile software engineering without significant modifications. As we are talking about the bada platform for mobile applications in this book, our prime interest in this appendix, naturally, is the mobile software engineering process. In the following pages we will introduce one such agile mobile software engineering process that subsumes several recommended best-practices. Of course, you are free to choose whichever engineering process you want to follow 463

23_974018-bapp03.indd 46323_974018-bapp03.indd 463

8/31/10 12:44 AM8/31/10 12:44 AM

464

Part III



Appendices

and whether to comply with all the phases we introduce, pick out the most relevant for your needs, or not to use it at all. We will also show where and how the bada platform and its tools support the described phases and best-practices.

Some Mobile Software Engineering Best-practices For developing mobile software, we recommend deploying ideas from agile development initiatives (stated in the agile manifesto1) such as adaptability, iterations, and making heavy use of prototyping and diversified testing as early as possible in the process. Prototypes can be exploited in nearly any phase of the engineering of a mobile software solution. They are primarily helpful in eliciting requirements or to get a common understanding with various stakeholders early in the project. Testing surely is not unique to mobile software engineering but must be treated and executed differently, as we will argue throughout this appendix. The mobile software engineering process that we introduce here is subdivided into three major phases: 1. Feasibility and economic efficiency analysis phase 2. Software product realisation phase 3. Distribution phase The following sections discuss each of these phases in detail and Figure C.1 gives an illustration of the whole process. SOFTWARE PRODUCT REALIZATION

Pro Ear tot ly ypi ng

User A T es ccepta ting nc

ign g Desaftin r D

MS 3

MS 4

Design Detailing

T esting

ements Requirineering Eng

User A T escceptanc ting e

e

keting Mar

MS 2

s ent rem ing qui eer Re ngin E

MS 1

DISTRIBUTION

MaPinroduc tain t ing

FEASIBILITY & ECONOMIC EFFICIENCY ANALYSIS

Preparing for Deployment

Pro

gra

mm

ing

g inin es Defst Cas e T

Figure C.1 A software engineering process model. 1

See http://www.agilemanifesto.org/.

23_974018-bapp03.indd 46423_974018-bapp03.indd 464

8/31/10 12:44 AM8/31/10 12:44 AM

Appendix C



A Software Engineering Model

465

Phase 1: Feasibility and Economic Efficiency Analysis This first phase should help all the stakeholders to get a better picture about the feasibility, the acceptance, and the potential economic success of a mobile software solution. By economic efficiency analysis we mean that very early in the project lifetime it can be determined whether it is worth pursuing a mobile software development project. This first phase is composed of four stages: requirements engineering, design drafting, early prototyping, user acceptance testing, and a milestone at the end of the phase.

Stage 1.1: Requirements Engineering The first step in this analysis phase is the elicitation and understanding of the requirements. The business requirements cover considerations about the business model and distribution policy. This is input that usually originates from the product management process in which our mobile software engineering process is embedded. User requirements are the starting point and represent what users need and what they expect from mobile software. These requirements must be collected and can be maintained in the form of use-cases or user stories. Early prototypes can be used for this, because users can get a more tangible impression of the future system. Early prototypes can be low-fidelity ones, such as drawings on paper. More advanced ones can be created by using electronic images that can actually allow a sequence and simple interactions to be shown. Even more advanced is the use of simple user interfaces (UIs) that can be created fairly easily and quickly by using the UI Builder provided by the bada IDE. The application envisaged can be sketched and simple user interaction (clicking on buttons or exploiting multi-touch) can be modelled and even deployed and demonstrated on a real hardware device. This helps the user even more to think of the future use of an application, which is directly reflected by the quality of user feedback. For mobile applications we recommend focusing on addressing a clearly defined problem or need with as little functionality as required. Many applications seem overloaded and, as a result, are difficult to use. Focus on the core and address rather fewer requirements. We are not talking about desktop applications. We have already outlined the differences between mobile and desktop apps. The cognitive resources and the attention timespan is substantially more limited. Traditional software engineers tend to underestimate the impact that a mobile setting will have on application usage patterns.

23_974018-bapp03.indd 46523_974018-bapp03.indd 465

8/31/10 12:44 AM8/31/10 12:44 AM

466

Part III



Appendices

Stage 1.2: Design Drafting The drafting of the design deals with two aspects. The first aspect is the draft of the dialog flow logic and the UI design. This is the only part of the software that is exposed to users and, hence, the only part they can experience. Experience has shown that it is essential to provide a simple yet attractive UI. If an application is too complex to understand within the first minute, or it is ugly looking, the user will most probably not launch it a second time. The second aspect deals primarily with software component architecture considerations. The UI design activities are conducted in various microiterations with feedback from stakeholders.

Stage 1.3: Early Prototyping Early prototypes embody the requirements gathered and the design developed so far. They are a good means to get a common understanding. Some rudimentary functionality should be in place such that minimal interaction is possible. That can be achieved by paper prototypes, an interactive slideshow or a clickable UI mock-up. The goal is to find a good balance between a fast and cost-effective prototype and providing a user experience that comes close to the final product. As mentioned above, the bada tools give ideal support for building good prototypes quickly. A further advantage is that these prototypes can be reused for the later programming as they are, without the need of redoing all the work for the UI. This is a result of the clear separation between UI design and programming brought to you by bada.

Stage 1.4: User Acceptance Testing This is an optional stage. However, we recommend planning and executing tests with users that are not involved in the project. These tests can be short in length but should be as close to the real-world context as possible. This way, many problems that would go unnoticed in a lab environment will become apparent, such as bad readability under sunlight or overly complex and confusing user interfaces. These kinds of trials will almost always yield highly valuable feedback about the future acceptance by users and thus potential success in the market. After a test session there may be one or more iterations back to the requirements engineering stage depending on available time, and quality and cost targets. The first phase ends with the milestone Decision for Continuation, which entails the decision to pursue or abandon the software project. With the knowledge gained in this phase – particularly arising from the early acceptance tests – the potential success of a mobile solution can be estimated much more clearly, which helps to assess the economic efficiency.

23_974018-bapp03.indd 46623_974018-bapp03.indd 466

8/31/10 12:44 AM8/31/10 12:44 AM

Appendix C



A Software Engineering Model

467

Phase 2: Software Product Realisation The second main phase deals with realising the software solution. It builds on the work in the first phase, and as many of the results as possible should be reused. In following the agile engineering process, this phase is also characterised by many iterations, incremental development (‘first things first’), and a high degree of internal and external communication. The phase is composed of six stages: requirements reviewing, design detailing, defining test cases, programming, testing, user acceptance testing, and a milestone at the end of the phase. Again, we would like to emphasise that we present here a complete mobile software engineering process. With reference to our advice about working in an agile way, which implies adaptability, you are free to choose whichever stages you want to deploy in your software project.

Stage 2.1: Requirements Reviewing Prior to starting with the detailed software design, programming, and testing, the requirements should be reviewed and revised – ideally together with all stakeholders.

Stage 2.2: Design Detailing In this step, the available UI and architecture designs of the first phase are detailed into much more fine-grained levels – down to element and component level. Although, mobile software engineering is a comparatively young discipline, some (mostly vendor-driven) initiatives have emerged that provide guidelines for UI design. Although you are not bound to use these, we strongly recommend complying with these guidelines because it simply increases the usability of your product and its acceptance. Also the bada platform has introduced such guidelines. These are implicitly used when you use the open application programming interfaces (APIs) for the UI and extended UI controls. Apart from that, the IDE ships with a help document that gives further information about best-practices for ideal UI design.

Stage 2.3: Defining Test Cases Testing is absolutely necessary in any software engineering endeavour. In mobile software engineering it is more multifaceted and more variables need to be taken into consideration. The definition of test cases is the first activity related to testing. The cases can be derived from the requirements.

23_974018-bapp03.indd 46723_974018-bapp03.indd 467

8/31/10 12:44 AM8/31/10 12:44 AM

468

Part III



Appendices

Stage 2.4: Programming During this stage the designs should be transformed into program code that can finally successfully pass all test cases. Although mobile devices are becoming more and more powerful, it is nevertheless highly recommended to write efficient code with an eye on conservative computation to conserve as much battery capacity as possible. Stretching availability of battery power is crucial, as we argued in Chapter 1. The bada IDE ideally supports you with all you need for writing your program code, such as syntax highlighting, code completion, comprehensive documentation, and example material, and all the necessary compiling, linking, deploying, and running functionalities. It is also important to understand that every mobile application is subject to a ‘technical’ application lifecycle, which subsumes initialising, running, terminating, and terminated. The bada platform and the IDE that you use to access it provide support for dealing with this app lifecycle and doing the right things in the appropriate stages (through well-defined methods).

Stage 2.5: Testing In the mobile software engineering process, much emphasis must be placed on the testing stage. It is important to differentiate between the testing platform and the real platform. The testing platform is usually a desktop computer that runs an emulation of the mobile device. Unfortunately, emulators exhibit great discrepancies with real mobile devices. Emulator tests are in ideal lab environments where context factors such as position or light conditions are either not considered or simulated. Hence, it is necessary to test software on the real target mobile device and in the real-world environment where the software is intended to be used. All the ‘controllable’ variables must be caught by the software, such as behaviour according to device capabilities, adapting to screen size, masking network disconnections, or loss of GPS signal. These last three stages (defining test cases, programming, and testing) are characterised by many micro-iterations and in reality are partly also executed in parallel. In particular, testing naturally iterates with the test case definition and programming stages. It usually also iterates with the design detailing and the requirements reviewing stages.

Stage 2.6: User Acceptance Testing User acceptance tests at the end of the second phase are again optional but recommended. This way, engineers can make sure to really meet users’

23_974018-bapp03.indd 46823_974018-bapp03.indd 468

8/31/10 12:44 AM8/31/10 12:44 AM

Appendix C



A Software Engineering Model

469

requirements with a software version that increasingly resembles the final state. This type of testing can be repeated and the outcomes can be fed back into earlier steps of this phase. Human–computer interaction techniques such as audio/video recordings, questionnaires, cooperative evaluations, focus groups, or controlled experiments can be deployed and are beneficial. After stakeholders accept the existing version of the mobile software, it can be denoted as a release. This means that the milestone Version Released is fulfilled, and the next iteration of the same phase (to realise a further increment) or the successive phase can start.

Phase 3: Distribution This phase mainly deals with bringing the mobile software product into the market to the users. This phase is less iterative than the other two. It is composed of the three stages: marketing, preparing for deployment, product maintenance, and a milestone at the end of the phase.

Stage 3.1: Marketing The marketing stage exemplifies where and how the processes of mobile software engineering and product management overlap and complement one another. This stage serves for the finalisation of the business model and distribution policy, and for preparation of the actual market entry of the software product. Marketing is partly in parallel with other stages, and starts during earlier phases.

Stage 3.2: Preparing for Deployment In this step, the software must be prepared (i.e. certified) such that the required functionality of a mobile device can be accessed appropriately. It must be decided which components and content are packaged together and which parts may be downloaded or installed on-demand. Also the distribution channel must be prepared, which usually involves requesting app store accounts and becoming familiar with the relevant policies. Finally, the mobile software is physically distributed and installed on the end-users’ devices.

Stage 3.3: Product Maintainance Maintenance covers support, bug fixing, and feedback integration. This step – depending on the significance of the reported issue and the policy of the

23_974018-bapp03.indd 46923_974018-bapp03.indd 469

8/31/10 12:44 AM8/31/10 12:44 AM

470

Part III



Appendices

application provider – can lead to an additional iteration with the preparing for deployment stage. Also, the level of maintenance and the commitment to it depends on the provider and can range from 24/7 service to no support at all. The mobile software engineering process ends with the end event (milestone: Project End) that was defined by the stakeholders and the project manager.

23_974018-bapp03.indd 47023_974018-bapp03.indd 470

8/31/10 12:44 AM8/31/10 12:44 AM

Index Index A abstract methods, 69 ad hoc Wi-Fi network, 401–406 AddControl() method, container, 76 AddItem() method, List control, 94 Addressbook class, 195–196, 235–236 AdhocService class, 191–192, 404–405 AesSecureRandom class, 193 agile software development, 15–17 Alarm class, 201–202 Amazon S3 (Simple Storage Service), 131, 153–155, 417–421 AMOLED display (Samsung), 11, 30, 89 Animation control, 75 App namespace, 160–162 app store, 13, 14 AppAssert() macro, 29 AppAssertf() macro, 29 AppControl class (Application Control), 161, 162, 228–236 Append() method, strings, 119 Application class, 64, 161–162 Application Control (AppControl class), 161, 162, 228–236 Application Manager (AppManager class), 161, 229 application registry, 213–216 applications. See also mobile software base applications. See base application building, 25–26, 46 certifying, 61

creating, 21–22 described, 20–21 development of. See mobile software development folder structure of, 23–25 GUI for. See GUI (Graphical User Interface) icon for, 46–47 ID for, 51, 52 lifecycle of, 65–69 localisation for. See localisation logging, 28–29 package for, creating, 60 privileges for, 53, 125–127, 160 profile for, 51–53 publishing, 61–62 running in Simulator, 26–27, 46 secret key for, 52 splash screen for, 27 testing. See testing application.xml file, 25–26, 51–53 AppLog() macro, 28 AppLogDebug() macro, 28 AppLogException() macro, 28 AppManager class (Application Manager), 161, 229 AppRegistry class, 214–216 architecture of bada, 98, 101–103 ARGB colour model, 89 ArrayList class, 122, 164–165 arrays, 106, 121. See also Buffer class

471

24_974018-bindex.indd 47124_974018-bindex.indd 471

8/31/10 12:45 AM8/31/10 12:45 AM

472

Index ASCII encoding, 120 audio playing, 369–374 recording, 366–369 AudioRecorder class, 183–184, 367–369 azimuth measurement, 332

B bada. See also specific topics architecture of, 98, 101–103 features of, 2–5, 98–99 history of, 99–100 bada developer programme, 51 bada SDK downloading and installing, 453–455 help system for, 457 running sample projects, 455–456 system requirements for, 453 bada Server. See also mobile services creating content for, 417–421 described, 102 privileges for, 160, 161 Ballard, Barbara (author) Designing the Mobile User Experience, 29 base application Browser base application, 229–231 Contact base application, 231–235 described, 229 launching from bada application, 228–236 Player base application, 373 Base namespace, 117–118, 162–168 Base::Collection namespace, 118, 164–166 Base::Runtime namespace, 166–167 Base::Utility namespace, 118, 167 battery capacity, of mobile hardware, 12 Battery class, 201–202 Binaries folder, 26 Bitmap class, 84–88, 171–172, 350–351, 354–355 bitmaps. See also graphics creating from a file, 86–87 described, 83–85 displaying an image as, 350–351 drawing onto Canvas, 87–88, 354–355 transparency colour of, 366 blocking sockets, 401

24_974018-bindex.indd 47224_974018-bindex.indd 472

Bluetooth namespace, 187–188 Bluetooth profiles, 388–395 BluetoothDevice class, 187–188, 389 BluetoothManager class, 187–188, 389 BluetoothOppClient class, 389 books about user interface design, 29 Boolean class, 118 browser downloading files in, 315–319 launching using Application Control, 229–231 launching using Web control, 314–315 Browser base application, 229–231 buddy lists. See also Social service adding buddy to, 446–450 described, 131 requests of, 142–146 BuddyFix application example app icon for, 46–47 building, 25–26 creating, 21–22 folder structure for, 23–24 Form for, 35–38 GUI for, 33–41 list for, creating, 38–41 list for, populating, 94–96 metadata for, 24–25 Option menu for, 77–78, 90–93 running in Simulator, 26–27 soft key for, 93–94 BuddyService class, 197–199 Buffer class, 121 BufferBase class, 118 BufferType class, 121 building applications, 25–26, 46 built-in memory, 229 Button control adding to Form, 263–269 containing an image, 267–268 containing text, 265–267 described, 72 ByteBuffer class, 121, 163

C C++ alternatives to, 104 described, 103 exception handling, 111–114

8/31/10 12:45 AM8/31/10 12:45 AM

Index inheritance, 69, 114–116 as native system for bada, 104 object construction, 106–110 object ownership, 110–111 restrictions on, for mobile apps, 104–106 Calendar class, 174–175 Calendarbook class, 195–196 CallManager class, 202–203 camera detecting a face in a video, 337–342 displaying image overlaid on preview screen, 360–366 displaying live frames from, 356–360 recognizing a face in a video, 337–342 Camera class, 183–184, 357–360 Canvas class described, 78–80, 171–172 drawing primitives to, 81–83, 87–88, 352–356 showing to display, 81 Cert namespace, 194 certifying applications, 61 Character class, 118, 119 characters, 118–121 CheckButton control, 72 class diagrams, 459–460 Clear() method, Canvas class, 81 collection classes, 121–123 Collection namespace, 164–166 Color class, 88–89 ColorPicker control, 73 colours of canvas foreground and background, 80 of shapes, 81 of text, 82, 83 specifying in code, 88–89 transparency colour of bitmap, 366 user specifying, 73 Commerce service, 131–132, 150–153, 167–168 Commerce::Store namespace, 167–168 Comparer classes, 118 compass (magnetometer), 327–331 component setup for services, 153–155 Construct() method Canvas class, 81 Font class, 81 objects, 225–227

24_974018-bindex.indd 47324_974018-bindex.indd 473

473

construction of objects, 106–110, 224–228 Contact base application, 231–235 Container class, 204 content, forms containing, 71 Content namespace, 168–170 Content service Amazon S3 required for, 131 creating content for server, 417–421 creating content on remote server, 150 described, 131 listening to remote server, 149 signing in required for, 147 transferring content to server, 147–148 ContentInfo class, 169–170 ContentManager class, 169–170 ContentSearch class, 169–170 ContentTransfer class, 419 Control class, 70, 204 controls. See also specific controls described, 30–31, 71 displaying, 71–72 focus on, 32 hierarchy of, 70 listeners for, 32–33 Controls namespace in Locations namespace, 178–180 in UI namespace, 204–205 in Web namespace, 208–209 CreateInstance() function, 64 Crypto namespace, 194–195 CustomList control, 74, 291–298

D Database class, 173, 216 DatePicker control, 73 dates and times described, 124 formatting, 244–246, 250 formatting for different locales, 48 time differences, calculating, 247–249 DateTime class, 118, 124, 163, 244–246 DateTimeFormatter class, 174–175 deCarta map provider, 135, 182, 412 Decoder class, 203 derivation, 69 DesEdeSecureRandom class, 193 Designing Interactions (Moggridge), 29

8/31/10 12:45 AM8/31/10 12:45 AM

474

Index Designing the Mobile User Experience (Ballard), 29 desktop software, differences from mobile, 11–14 DesSecureRandom class, 193 destruction of objects, 224–228 development. See mobile software development device. See mobile hardware Dimension class, 80 Directory class, 173 Directory service, 181–184 display, of mobile hardware, 11, 30, 89 DNS (Domain Name System) server, querying, 406–410 Dns class, 406–410 double-tap motion event, 322 downloading files in browser, 315–319 Draw() method, control, 71–72 DrawRectangle() method, Canvas class, 81 DrawText() method, Canvas class, 82–83 dynamic binding, 69

E Eclipse IDE, 19, 21 editable controls, 74–75 EditArea control, 75 EditDate control, 74 EditField control, 74, 275–279 EditTime control, 75 EmailManager class, 185 Encoder class, 203 Encoding class, 203 energy consumption, of mobile hardware, 12 EnrichedText class, 82–83, 171–172 Equals() method, Object class, 118 error (exception) handling, 111–114, 217–224 error codes, 219–224 event driven applications, 65 Event Injector, 15, 331, 336, 415–416 events. See also listeners described, 32–33 gesture events, retrieving, 321–327

24_974018-bindex.indd 47424_974018-bindex.indd 474

key pressed events, retrieving, 309–313 motion events, retrieving, 321–327 multi-touch events, retrieving, 286–291 touch events, retrieving, 280–286 exceptions in C++, not supported, 106 handling, 111–114, 217–224 ExpandableList control, 74

F face detection, 337–342 face recognition, 342–346 Facebook accessing with SNS Gateway, 422–430 getting Notes from, 439–446 uploading a photo to, 434–438 FaceDetector class, 206–207, 337 FaceRecognizer class, 206–207, 343–344 File class, 173, 216 file system, 116–117 files, downloading in browser, 315–319 FillRectangle() method, Canvas class, 81 Flash, 104 focus on a Control, 32 folder structure of application, 23–25 of bada phones, 116–117 Font class, 81 Form class adding Button control to, 263–269 adding Option menu to, 77–78, 90–93, 258–263 adding soft keys to, 93–94, 255–258 adding to Frame, 76, 251–255 in control hierarchy, 70, 205 creating, 35–38, 42 described, 30–31, 77–78 getting Frame within, 76 initialising, 43, 45 listeners for, setting, 42–44 manipulating within Frame, 76–77 properties of, 35–38 standard elements in, 31–32 tabbed, 76–77 Form Manager, 298–309

8/31/10 12:45 AM8/31/10 12:45 AM

Index Form-based apps, 77 Frame class adding Form to, 76, 251–255 in control hierarchy, 70, 205 described, 30–31, 75–77 getting from within Form methods, 76 Frame-based apps, 77 frameworks, 69 full screen apps, 77 functions. See methods

G GAP (General Access Profile), Bluetooth, 388–389 geographic data, obtaining, 411–413. See also Location service gesture events, retrieving, 321–327 GetCurrentForm() method, Frame class, 76 GetHashCode() method, Object class, 118 GPS (Global Positioning System), 11 Graphical User Interface. See GUI graphics. See also bitmaps; images Canvas for, 78–80 colours, 88–89, 366 primitives for, 80–83, 87–88, 352–356 Graphics namespace, 171–172 Graphics::Opengl namespace, 172 GroupedList control, 74 GSM encoding, 120 GUI (Graphical User Interface) basic UI recipes, 251–319 building, 33–41 connecting to code, 41–45 Controls in, 30–31 described, 20, 29–33 design guidelines for, 29–30 extended UI recipes, 321–346 Forms in, 30–32, 77–78 Frame in, 30–31, 75–77 namespaces applicable to, 159

475

HashMap class, 122 headers for namespaces, 160 help system for bada SDK, 457 history of bada, 99–100 HistoryItem class, 208 /Home folder, 23–24 Http namespace, 188–190 HTTP sessions, establishing, 383–388 HttpHeader class, 189 HttpRequest class, 189 HttpResponse class, 189 HttpSession class, 189, 385–388 HttpTransaction class, 189, 190

I IActionEventListener interface, 42, 264–265

IAdhocServiceEventListener interface, 403

IAppControlEventListener interface, 231–235

IAreaListener interface, 176–177 IAudioRecorderEventListener interface, 367

IBidirectionalEnumerator interface, 123

IBluetoothManagerEventListener interface, 389

IBluetoothOppClientEventListener interface, 389, 394 IBluetoothOppServerEventListener interface, 389, 395 ICameraEventListener class, 343, 359–360

ICollection interface, 123, 164–165 IComparer interface, 123, 164–166 icon for application, 46–47 IconList control, 74, 303–304, 309 /Icons folder, 23–24, 47

IContentTransferListener interface, 418–419, 421 ID for application, 51, 52 Id property, Forms, 38

IDirectoryServiceListener

H

interface, 181–182

Haptic class, 206–207

IDirectoryServiceProvider

hard keys, 309–313 hardware. See mobile hardware

IDnsEventListener interface, 406–408

24_974018-bindex.indd 47524_974018-bindex.indd 475

interface, 181–182

8/31/10 12:45 AM8/31/10 12:45 AM

476

Index IEnumerator interface, 123, 164–165 IHash interface, 194–195 IHashCodeProvider interface, 123 IHmac interface, 194–195 IHttpTransactionEventListener interface, 190, 384–385

Io namespace, 173–174 IOrientationEventListener interface, 322–326

IPlayerEventListener interface, 371–372

IRemoteContentManagerListener interface, 418–419

IImageDecodeUrlEventListener interface, 348–349

IItemEventListener interface, 43 IKeyEventListener interface, 310–312 IList interface, 123 ILoadingListener interface, 315 ILocationListener interface,

IRouteServiceListener interface, 181–182

IRouteServiceProvider interface, 181–182

IScreenEventListener interface, 43, 64 ISecureSocketEventListener

176–177, 414–415

Image class, 84–85, 86, 348–351 images. See also graphics on Button control, 267–268 creating bitmaps from files, 86–87 described, 83–85 displaying as a bitmap, 350–351 displaying overlaid on camera preview screen, 360–366 downloading and saving as a file, 348–350 drawing bitmaps to Canvas, 87–88 file types supported, 84–85 uploading to Facebook, 434–438 IMapEnumerator interface, 123 IMapEventListener interface, 178–181 IMapOverlay interface, 178–181 IMapServiceProvider interface, 181, 412 IMotionEventListener interface, 322–326 /inc folder, 23–24 #include directive, 45 /Includes folder, 24 IndexOf() method, strings, 119 Indicator bar, 31, 37

INetConnectionEventListener interface, 377 Info Window layer, 179 inheritance, 69, 114–116 Initialising state, 66–67 Initialize() macro, 45 Insert() method, string, 119 interfaces, 114–116. See also specific interfaces

24_974018-bindex.indd 47624_974018-bindex.indd 476

interface, 379–380

ISensorEventListener interface, 329, 333–335

ISnsAuthenticatorListener interface, 425

ISnsContentListener interface, 425, 435, 438

ISnsGatewayListener interface, 425 ISnsPeopleListener interface, 431–433

ISocketEventListener interface, 396, 401

ItemInfo class, 168 ItemService class, 168 ITextEventListener interface, 273–275

ITimerEventListener interface, 237–238

ITouchEventListener interface, 280–282

ITraceServiceListener interface, 176–177

IWebDownloadListener interface, 315

J Jensen, Scott (author) The Simplicity Shift, 29

K KeyPad class, 272–279 KeyPair class, 194 KeyPairGenerator class, 194 keys. See hard keys; soft keys

8/31/10 12:45 AM8/31/10 12:45 AM

Index

L L macro, 119 Label control, 72 Landmark class, 176–178 LandmarkStore class, 176–177, 178 languages, human. See localisation languages, programming. See C++; Flash; WebKit Latin1 encoding, 120 Layout|Mode property, Forms, 38 LBS (location-based services), 10, 11. See also Location service libraries for namespaces, 160 lifecycle methods, 64, 65 lifecycle of application, 65–69 Lifelog class, 195–197 Lindholm, Christian (author) Mobile Usability, 29 LinkedList class, 122, 164–165 List control, 38–41. See also ArrayList class; CustomList control; ExpandableList control; GroupedList control; IconList control; LinkedList class listeners, 32–33, 42–44. See also specific listener interfaces Locale class, 174–175 LocaleManager class, 174–175 Locales namespace, 174–175 localisation date and time formats, 48 languages, adding, 48–49 languages supported, 47 number formats, 48 strings, reading from resources, 49–50 Location service with buddy lists, 145–146 described, 130, 180–182 geographic data, obtaining, 411–413 location changes, reacting to, 414–416 map, displaying, 412–413 using, 134–140 location-based services (LBS), 10, 11 LocationProvider class, 176–177, 414–415 Locations namespace, 176–181 Locations::Controls namespace, 178–180

24_974018-bindex.indd 47724_974018-bindex.indd 477

477

Locations::Services namespace, 180–182

.log suffix, 28 logging applications, 28–29

M magnetometer, 327–331 manifest.xml file, 25–26, 51–53 Map control, 178–181, 412–413 Map layer, 180 map services. See Location service MapEntry class, 122 MapInteraction class, 414–415 Math class, 167 mchar class, 121 media content service. See Content service media formats supported, 184 Media namespace, 182–184 memory allocation of, responsibility for, 110–111 built-in, base applications in, 229 leaks, causes of, 106 of mobile hardware, 11 object construction affecting, 106–110, 224–228 restrictions on C++ for, 105–106 types of, 106 MessageBox class, 269–272 Messaging namespace, 184–186 MessagingService class, 197–199 metadata files, 25–26 methods. See also specific methods abstract methods, 69 lifecycle methods, 64, 65 ‘N’ postfix for method name, 110–111 overloading, 69 overriding, 69 virtual methods, 69 microphone, recording audio from, 366–369 MmsManager class, 185 mobile hardware battery capacity of, 12 device orientation, determining, 327–331 display of, 11, 30, 89 energy consumption of, 12 memory of. See memory

8/31/10 12:45 AM8/31/10 12:45 AM

478

Index mobile hardware (continued) processor speeds of, 11 sensors in, 12 technological advances in, 11–12 testing applications on, 57–60 user experience with, 9–10, 12–13 mobile services. See also specific services APIs for, 132–134 component setup for, 153–155 described, 3, 10 namespaces applicable to, 159 mobile software, 9–14 mobile software development best practices for, 14–17 process for, 50–62, 463–470 prototyping, 15 technical support resources for, 14 testing, 15 Mobile Usability (Lindholm), 29 Moggridge, Bill (author) Designing Interactions, 29 Monitor class, 166 Motion class, 206–207 motion events, retrieving, 321–327 MultiHashMap class, 122 multimedia content recipes, 347–374 multiple inheritance, 114–116 multiple screen apps, 76–77 multi-touch events, retrieving, 286–291 MyLocation layer, 179

N ‘N’ postfix for method name, 110–111 namespaces, 158–160. See also specific namespaces Net namespace, 186–192 NetAccountInfo class, 186–187, 377 NetAccountManager class, 186–187, 377 Net::Bluetooth namespace, 187–188 NetConnection class, 186–187 Net::Http namespace, 188–190 Net::Sockets namespace, 190, 396 Net::Wifi namespace, 190–192 network connection ad hoc Wi-Fi, 401–406 Bluetooth, 388–395

24_974018-bindex.indd 47824_974018-bindex.indd 478

creating, 375–379 DNS server, querying, 406–410 HTTP sessions, 383–388 secure sockets, 379–383 TCP and UDP sockets, 395–401 NetworkManager class, 202–203 normal mode, HTTP session, 383–388 Notes from Facebook, 439–446 NotificationManager class, 161, 162 Number class, 163, 164 number formats, localisation for, 48, 174–175 NumberFormatter class, 174–175 numbers, 118, 124–125

O Object class, 118, 163 object construction, 106–110, 224–228 object deletion, 110–111, 224–228 Object Push Profile (OPP), Bluetooth, 388–389 OnActionPerformed() method, IActionEventListener interface, 68

OnAppInitializing() method, Application class, 65, 66–67 OnAppTerminating() method, Application class, 65, 68 OnBackground() method, Application class, 65, 68 OnBatteryLevelChanged() method, Application class, 65 OnDraw() method, container, 71–72, 77, 80

OnForeground() method, Application class, 65, 68 OnLowMemory() method, Application class, 65 OnScreenOff() method, 65 OnScreenOn() method, 65 OpenGL ES, 31 Opengl namespace, 172 OPP (Object Push Profile), Bluetooth, 388–389 Option menu, 32, 77–78, 90–93, 258–263 OptionMenu class, 90–93, 258–263

8/31/10 12:45 AM8/31/10 12:45 AM

Index orientation of device, determining, 327–331 Orientation property, Forms, 38 Osp namespace, 160 Osp::Base classes, 121 Output pane, 28–29 Overlay layer, 179–180 OverlayPanel control, 356–366 overloading methods, 69 overriding methods, 69

P package for application, 60 panels, 75, 76–77 paths, virtual, 117 picker controls, 73 pipeline mode, HTTP session, 383–388 pitch measurement, 332 Player base application, 373 Player class, 183–184, 370–374 Point class, 80 Popup class, 271, 272. See also KeyPad class; MessageBox class positioning technologies, 11. See also location-based services (LBS) PowerManager class, 201–202 primitives, drawing, 81–83, 87–88, 352–356 PrivacyManager class, 197–199 PrivateKey class, 193 privileges, 53, 125–127, 160 processor speeds, of mobile hardware, 11 profile, application, 51–53 Profile class, 197–199 profiles, in Social service, 131, 140–142 ProfileService class, 197–199 programming languages. See C++; Flash; WebKit Progress control, 75 projects. See applications properties of Forms, 35–38 of lists, 38–40 XML layout file for, 41 prototyping, 15 ProviderManager class, 181 PublicKey class, 193 publishing applications, 61–62

24_974018-bindex.indd 47924_974018-bindex.indd 479

479

PurchaseService class, 168 pure virtual methods, 69

Q Queue class, 122, 164–165

R RadioGroup control, 73 recipes basic UI, 251–319 extended UI and sensors, 321–346 fundamentals, 213–250 maps and location, 411–416 multimedia content, 347–374 networking, 375–410 services and social networking, 417–450 Rectangle class, 81 registry, application, 213–216 Registry class, 173–174 RemoteLandmarkStore class, 178 RemoteLocationProvider class, 176–177 Remove() method, 119 RemoveControl() method, container, 76

RequestLastKnownLocationList() method, RemoteLocationProvider class, 177 RequestLastKnownLocationListInCircle() method, RemoteLocationProvider class, 177 RequestLastKnownLocationListInRectangle() method, RemoteLocationProvider class, 177

RequestRedraw() method, control, 71–72

/Res folder, 23–24 RESTful APIs, 134, 439–446

result type, 217–219 roll measurement, 332 Route service, 181–184 RsaCipher class, 194–195 RsaSignature class, 194–195 running applications, 26–27 Running state, 67–68

8/31/10 12:45 AM8/31/10 12:45 AM

480

Index Runtime namespace, 166–167 RuntimeInfo class, 201–202

S Samsung Kies software, 61 SamsungApps store, 13, 14 ScrollPanel control, 75 SDK. See bada SDK secret key for application, 52 SecretKey class, 193 SecretKeyGenerator class, 193 secure sockets, 379–383 SecureSocket class, 190, 379–383 security, 125–127 Security namespace, 192–195 Security::Cert namespace, 194 Security::Crypto namespace, 194–195 SensorManager class, 206–207, 329, 333–335 sensors, in mobile hardware, 12 sequence diagrams, 460–461 Serial Port Profile (SPP), Bluetooth, 388–389 server. See bada Server services. See mobile services Services namespace in Locations namespace, 180–181 in Social namespace, 197–199 SetCurrentForm() method, Frame class, 76 SetFont() method Canvas class, 81 TextElement class, 83 SetForegroundColor() method, Canvas class, 81 SetTextColor() method, TextElement class, 83 SetTextWrapStyle() method, EnrichedText class, 83 SettingInfo class, 201–202 shake motion event, 322 shapes, drawing, 353–354 shopping and commerce services. See Commerce service Show() method Canvas class, 81 control, 71–72

24_974018-bindex.indd 48024_974018-bindex.indd 480

SimInfo class, 202–203 The Simplicity Shift (Jensen), 29 Simulator Event Injector, 15, 331, 336 launching, 19 running applications in, 26–27 .Simulator-Debug directory, 26 single sign on (SSO) service, 132 Slider control, 73 SmsManager class, 185 snap motion event, 322 SNS (social network services), 10. See also Social service SNS Gateway, 422–438 SnsAuthenticator class, 426 SnsGateway class, 197–200 Social namespace, 195–199 social network services (SNS), 10 social networking recipes, 417–450 Social service. See also buddy lists; profiles described, 130 RESTful APIs for, 439–446 SNS Gateway for, 422–438 Social::Services namespace, 197–199 Socket class, 190, 396 sockets, 395–401 Sockets namespace, 190, 396 soft keys adding to Form, 93–94, 255–258 described, 32 enabling and disabling, 258 key pressed events for, retrieving, 309–313 software. See mobile software software development. See mobile software development sound. See audio splash screen, 27 splash.png file, 27 SPP (Serial Port Profile), Bluetooth, 388–389 /src folder, 23–24 SSO (single sign on) service, 132 Stack class, 122, 164–165 Standard Template Library (STL), 122 StartLocationReport() method, RemoteLocationProvider class, 177 states in lifecycle, 65–69

8/31/10 12:45 AM8/31/10 12:45 AM

Index STL (Standard Template Library), 122 Store namespace, 167–168 String class, 118, 163 strings native, discouraged, 106 ordinary construction for, 228 reading from resources, 49–50 using, 118–121 StringTokenizer class, 119 StringUtil class, 167

SubscribeToTraceService() method, RemoteLocationProvider class, 177 Super AMOLED display (Samsung), 11, 30, 89 System namespace, 200–202 SystemInfo class, 201–202 SystemTime class, 201–202

T TCP sockets, 395–401 Telephony namespace, 202–203 Terminated state, 69 Terminating state, 68 testing Event Injector in Simulator for, 15, 331, 336 recommendations for, 15 on Simulator, 54–56 on target device, 57–60 text, drawing, 354 Text namespace, 121, 203 TextElement class, 82–83 Thread class, 166 TimePicker control, 73 Timer class, 166, 236–239 times. See dates and times TimeSpan class, 118, 124, 244, 247–249 TimeZone class, 174–175 Title bar, 31, 37 Title property, Forms, 38 touch events, retrieving, 280–286 TouchInfo class, 288–290 Twitter, posting a tweet to, 430–434 two-phase construction, 109–110, 224–228 Type property, Forms, 38 types, 117–125

24_974018-bindex.indd 48124_974018-bindex.indd 481

481

U UCS2 encoding, 120 UDP sockets, 395–401 UI (User Interface). See also GUI (Graphical User Interface); specific topics basic recipes, 251–319 extended recipes, 321–346 UI Builder Controls, adding, 38–41 described, 15, 33 Forms, creating, 35–38 saving resources, 41 Ui namespace, 203–205 Ui::Controls namespace, 204–205 Uix namespace, 206–207, 328–329 UML notation, 459–461 Unicode, 118–121 Universal Unique Identifier. See UuId class URI (Uniform Resource Identifier), 118, 119 Uri class, 167 user interface (UI). See UI (User Interface) users distribution of apps affecting, 13–14 interaction with mobile hardware, 9–10, 12–13 using directive, 158–159 UTF-8 encoding, 120 Utility namespace, 167 UuId class, 118

V Vibrator class, 201–202 video detecting a face in, 337–342 recognizing a face in, 337–342 VideoRecorder class, 183–184 virtual methods, 69 virtual path prefixes, 117

W WeatherSensor class, 206–207 web browser. See browser

Web control, 208–209, 314–319 Web namespace, 207–209

8/31/10 12:45 AM8/31/10 12:45 AM

482

Index web-based software, differences from mobile, 11–14 Web::Controls namespace, 208–209 WebHistory class, 208 WebKit, 104 Wifi namespace, 190–192 Wi-Fi network, ad hoc, 401–406 WifiManager class, 191–192 WifiNetAccountInfo class, 191–192 Window class, 204 wish and use notion, 13 workspace, choosing, 23

24_974018-bindex.indd 48224_974018-bindex.indd 482

X X509Certificate class, 194 XML content, parsing, 239–243 XML layout file, 41 Xml namespace, 209

Z Zoom layer, 179

8/31/10 12:45 AM8/31/10 12:45 AM