Sie sind auf Seite 1von 262

The Busy Coder's Guide to Advanced Android Development

by Mark L. Murphy

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

The Busy Coder's Guide to Advanced Android Development by Mark L. Murphy Copyright 2009 CommonsWare, LLC. All Rights Reserve . !rinte in the "nite #tates o$ Ameri%a. CommonsWare books may be pur%hase in printe &bulk' or igital $orm $or e u%ational or business use. (or more in$ormation, %onta%t direct@commonsware.com. !rinting )istory* +ul 2009* ,ersion -.0 .#/0* 91230392-41203-34 relate tra e ress are

5he CommonsWare name an logo, 6/usy Co er7s 8ui e9, an tra emarks o$ CommonsWare, LLC.

All other tra emarks re$eren%e in this book are tra emarks o$ their respe%tive $irms. 5he publisher an author&s' assume no responsibility $or errors or omissions or $or amages resulting $rom the use o$ the in$ormation %ontaine herein.

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

Table of Contents

Welcome to the Warescription!............................................................ix Preface....................................................................................................xi Wel%ome to the /ook:.................................................................................;i !rere<uisites.................................................................................................;i Wares%ription.............................................................................................;ii /ook /ug /ounty.......................................................................................;iii #our%e Co e Li%ense..................................................................................;iv Creative Commons an the (our3to3(ree &=2(' 8uarantee...................;iv Li$e%y%le o$ a CommonsWare /ook..........................................................;v We !ie"# $nside and %ut........................................................................& (rien s >ith /ene$its....................................................................................5urnabout is (air !lay..................................................................................4 8earing "p....................................................................................................9 /a%k 5o 5he (uture......................................................................................-Craftin' (our %"n !ie"s.......................................................................&) 8etting Meta................................................................................................-? 5he Wi get Layout...............................................................................-= 5he Attribute @e%larations..................................................................-= 5he Wi get .mplementation...............................................................-A
iii
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

"sing the Wi get..................................................................................-9 Change o$ #tate............................................................................................2Changing /utton /a%kgroun s............................................................2Changing Che%k/o; #tates..................................................................2A *ore +un With ,ist!ie"s......................................................................-. 8iant B%onomy3#iCe @ivi ers....................................................................29 Choosing What .s #ele%table...............................................................?0 Composition $or #e%tions.....................................................................?(rom )ea 5o 5oe......................................................................................?2 Control Dour #ele%tion...............................................................................=2 Create a "ni$ie Ro> ,ie>..................................................................=2 Con$igure the List, 8et Control on #ele%tion.....................................=? Change the Ro>...................................................................................=4 /ho" 0p At 1ome.................................................................................2. Bast is Bast, an West is West...................................................................=9 5he /ig !i%ture $or a #mall App Wi get...................................................A0 Cra$ting App Wi gets.................................................................................A5he Mani$est.........................................................................................A2 5he Meta ata........................................................................................A? 5he Layout............................................................................................A= 5he /roa %astRe%eiver.........................................................................AA 5he #ervi%e............................................................................................A4 5he Con$iguration A%tivity..................................................................A2 5he Result..............................................................................................4Another an Another.................................................................................4= App Wi gets* 5heir Li$e an 5imes..........................................................4A Controlling Dour &App Wi get7s' @estiny................................................44
iv
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

/eing a 8oo )ost.....................................................................................44 Creatin' Dra"a les................................................................................3& 5raversing Along a 8ra ient......................................................................1A #tit%h .n 5ime #aves 0ine......................................................................1A 5he 0ame an the /or er...................................................................14 !a ing an the /o;............................................................................14 #tret%h Eones........................................................................................11 5ooling..................................................................................................12 "sing 0ine3!at%h .mages....................................................................20 Animatin' Wid'ets................................................................................43 .t7s 0ot +ust (or 5oons Anymore...............................................................21 A Fuirky 5ranslation.................................................................................22 Me%hani%s o$ 5ranslation....................................................................22 .magining a #li ing !anel...................................................................29 5he A$termath......................................................................................29 .ntro u%ing #li ing!anel....................................................................90 "sing the Animation............................................................................92 (a ing 5o /la%k. Gr #ome Gther Color....................................................92 Alpha 0umbers....................................................................................9? Animations in HML..............................................................................9? "sing HML Animations.......................................................................9= When .t7s All #ai An @one....................................................................9= )it 5he A%%elerator....................................................................................9A Animate. #et. Mat%h...................................................................................94 Playin' *edia.......................................................................................... 8et Dour Me ia Gn....................................................................................99 Making 0oise.............................................................................................-00
v
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Moving !i%tures.........................................................................................-0A 0sin' the Camera..................................................................................&&& #neaking a !eek..........................................................................................--5he !ermission....................................................................................--2 5he #ur$a%e,ie>..................................................................................--? 5he Camera..........................................................................................--? .mage .s Bverything...................................................................................--4 Asking $or a (ormat.............................................................................--1 Conne%ting the Camera /utton..........................................................--1 5aking a !i%ture...................................................................................--2 "sing Asyn%5ask..................................................................................--9 /ensors..................................................................................................&-) 5he #i;th #ense. Gr !ossibly the #eventh...............................................-2? Grienting Doursel$.....................................................................................-2= #teering Dour !hone..................................................................................-21 @o I5he #hakeI..........................................................................................-29 Data ases and Content Providers.......................................................&)5 @istribute @ata........................................................................................-?4 #FLite* Gn3@evi%e, Gn3@esktop.......................................................-?1 B;porting a @atabase..........................................................................-?1 Loa ing the B;porte @atabase.........................................................-?9 B;amining Dour Relationships.................................................................-=2 Conta%t !ermissions...........................................................................-=2 !re3+oine @ata...................................................................................-=? 5he #ample A%tivity............................................................................-=? A%%essing !eople.................................................................................-=4 A%%essing !hone 0umbers.................................................................-=1
vi
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

A%%essing Bmail A

resses................................................................-=2

Rummaging 5hrough Dour !hone Re%or s............................................-A0 Come 5ogether, Right 0o>.......................................................................-ACursorWrapper....................................................................................-A2 .mplementing a +oinCursor................................................................-A2 "sing a +oinCursor..............................................................................-A1 1andlin' /ystem 6vents......................................................................&73 8et Moving, (irst 5hing............................................................................-41 5he !ermission...................................................................................-42 5he Re%eiver Blement.........................................................................-42 5he Re%eiver .mplementation...........................................................-49 . #ense a Conne%tion /et>een "s............................................................-10 (eeling @raine ..........................................................................................-1? 0sin' /ystem /ervices..........................................................................&3. 8et Alarme ...............................................................................................-19 Con%ept o$ WakeLo%ks.......................................................................-20 #%he uling Alarms...............................................................................-2Arranging $or Work (rom Alarms.....................................................-22 #taying A>ake At Work.....................................................................-2= #etting B;pe%tations.................................................................................-22 /asi% #ettings......................................................................................-22 #e%ure #ettings.....................................................................................-9Can Dou )ear Me 0o>J GK, )o> About 0o>J....................................-92 Reusing Meter.....................................................................................-9? Atta%hing Meters to ,olume #treams...............................................-9? (our %"n 8Advanced9 /ervices...........................................................&.3 When .!C Atta%ks:....................................................................................-91
vii
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Write the A.@L...................................................................................-92 .mplement the .nter$a%e....................................................................-99 A Consumer B%onomy.............................................................................200 /oun $or #u%%ess..............................................................................200 Re<uest $or #ervi%e.............................................................................20!rometheus "nboun ........................................................................20#ervi%e (rom A$ar.....................................................................................202 #ervi%e 0ames.....................................................................................202 5he #ervi%e..........................................................................................20? 5he Client...........................................................................................20A #ervi%ing the #ervi%e.................................................................................201 Callba%ks via A.@L.............................................................................202 Revising the Client.............................................................................209 Revising the #ervi%e.............................................................................2-+indin' Availa le Actions via $ntrospection......................................-&5 !i%k 7Bm......................................................................................................2-4 Woul Dou Like to #ee the MenuJ..........................................................220 Asking Aroun ..........................................................................................222 Testin' (our Patience..........................................................................--5 Dou 8et What 5hey 8ive Dou..................................................................22A Bre%ting More #%a$$ol ing.......................................................................224 5esting Real #tu$$......................................................................................229 A%tivity.nstrumentation5estCase.....................................................229 An roi 5estCase.................................................................................2?Gther Alternatives..............................................................................2?? Monkeying Aroun ...................................................................................2??

viii
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Welcome to the Warescription!

We hope you enLoy this igital book an its up ates M keep tabs on the Wares%ription $ee o$$ the CommonsWare site to learn >hen ne> e itions o$ this book, or other books in your Wares%ription, are available. Ba%h Wares%ription igital book is li%ense $or the e;%lusive use o$ its subs%riber an is tagge >ith the subs%ribers name. We ask that you not istribute these books. .$ you >ork $or a $irm an >ish to have several employees have a%%ess, enterprise Wares%riptions are available. +ust %onta%t us at enterpriseN%ommons>are.%om. Also, bear in min that eventually this e ition o$ this title >ill be release un er a Creative Commons li%ense M more on this in the pre$a%e. Remember that the CommonsWare Web site has errata an resour%es &e.g., sour%e %o e' $or ea%h o$ our titles. +ust visit the Web page $or the book you are intereste in an $ollo> the links. #ome notes $or $irst3generation Kin le users*

Dou may >ish to rop your $ont siCe to level 2 $or easier rea ing #our%e %o e listings are in%orporate as graphi%s so as to retain the monospa%e $ont, though this means the sour%e %o e listings o not honor %hanges in Kin le $ont siCe

ix
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

Preface

Welcome to the Book!


.$ you %ome to this book a$ter having rea its %ompanion volume, 5he /usy Co er7s 8ui e to An roi @evelopment, thanks $or sti%king >ith the series: CommonsWare aims to have the most %omprehensive set o$ An roi evelopment resour%es &outsi e o$ the Gpen )an set Allian%e itsel$', an >e appre%iate your interest. .$ you %ome to this book having learne about An roi $rom other sour%es, thanks $or Loining the CommonsWare %ommunity: An roi , >hile aime at small evi%es, is a surprisingly vast plat$orm, making it i$$i%ult $or any given book, training, >iki, or other sour%e to %ompletely %over everything one nee s to kno>. 5his book >ill hope$ully augment your kno>le ge o$ the ins an outs o$ An roi 3 om an make it easier $or you to %reate Ikiller appsI that use the An roi plat$orm. An , most o$ all, thanks $or your interest in this book: . sin%erely hope you $in it use$ul an at least o%%asionally entertaining.

Prerequisites
5his book assumes you have e;perien%e in An roi evelopment, >hether $rom a CommonsWare resour%e or somepla%e else. .n other >or s, you shoul have*

xi
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

A >orking An roi evelopment environment, >hether it is base on B%lipse, another .@B, or Lust the %omman 3line tools that a%%ompany the An roi #@K A strong un erstan ing o$ ho> to %reate a%tivities an the various sto%k >i gets available in An roi A >orking kno>le ge o$ the Intent system, ho> it serves as a message bus, an ho> to use it to laun%h other a%tivities B;perien%e in %reating, or at least using, %ontent provi ers an servi%es

.$ you pi%ke this book up e;pe%ting to learn those topi%s, you really nee another sour%e $irst, sin%e this book $o%uses on other topi%s. While >e are $ans o$ 5he /usy Co er7s 8ui e to An roi @evelopment, there are plenty o$ other books available %overing the An roi basi%s, blog posts, >ikis, an , o$ %ourse, the main An roi site itsel$. A list o$ %urrently3available An roi books %an be $oun on the An roi !rogramming knol. #ome %hapters may re$eren%e material in previous %hapters, though usually >ith a link ba%k to the pre%e ing se%tion o$ relevan%e. Many %hapters >ill re$eren%e material in 5he /usy Co er7s 8ui e to An roi @evelopment, sometimes via the shorthan BCG to Android moniker. .n or er to make e$$e%tive use o$ this book, you >ill >ant to o>nloa the sour%e %o e $or it o$$ o$ the book7s page on the CommonsWare site.

Warescription
5his book >ill be publishe both in print an in igital $orm. 5he igital versions o$ all CommonsWare titles are available via an annual subs%ription M the Wares%ription. 5he Wares%ription entitles you, $or the uration o$ your subs%ription, to igital $orms o$ all CommonsWare titles, not Lust the one you are rea ing. !resently, CommonsWare o$$ers !@( an Kin leO other igital $ormats >ill be a e base on interest an the openness o$ the $ormat.

xii
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Ba%h subs%riber gets personaliCe e itions o$ all e itions o$ ea%h title* both those mirroring printe e itions an in3bet>een up ates that are only available in igital $orm. 5hat >ay, your igital books are never out o$ ate $or long, an you %an take a vantage o$ ne> material as it is ma e available instea o$ having to >ait $or a >hole ne> print e ition. (or e;ample, >hen ne> releases o$ the An roi #@K are ma e available, this book >ill be <ui%kly up ate to be a%%urate >ith %hanges in the A!.s. (rom time to time, subs%ribers >ill also re%eive a%%ess to subs%riber3only online material, in%lu ing not3yet3publishe ne> titles. Also, i$ you o>n a print %opy o$ a CommonsWare book, an it is in goo %lean %on ition >ith no marks or sti%kers, you %an e;%hange that %opy $or a $ree $our3month Wares%ription. .$ you are intereste in a Wares%ription, visit the Wares%ription se%tion o$ the CommonsWare Web site.

Book Bug Bounty


(in a problem in one o$ our booksJ Let us kno>: /e the $irst to report a uni<ue %on%rete problem in the %urrent igital e ition, an >e7ll give you a %oupon $or a si;3month Wares%ription as a bounty $or helping us eliver a better pro u%t. Dou %an use that %oupon to get a ne> Wares%ription, rene> an e;isting Wares%ription, or give the %oupon to a $rien , %olleague, or some ran om person you meet on the sub>ay. /y I%on%reteI problem, >e mean things like*

5ypographi%al errors #ample appli%ations that o not >ork as a vertise , in the environment es%ribe in the book (a%tual errors that %annot be open to interpretation

xiii
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

/y Iuni<ueI, >e mean ones not yet reporte . Ba%h book has an errata page on the CommonsWare Web siteO most kno>n problems >ill be liste there. Gne %oupon is given per email %ontaining vali bug reports. :%T6* /ooks >ith version numbers lo>er than 0.9 are ineligible $or the bounty program, as they are in various stages o$ %ompletion. We appre%iate bug reports, though, i$ you %hoose to share them >ith us. We appre%iate hearing about Iso$terI issues as >ell, su%h as*

!la%es >here you think >e are in error, but >here >e $eel our interpretation is reasonable !la%es >here you think >e %oul e;pan upon the e;isting material a sample appli%ations, or

#amples that o not >ork ue to Ishi$ting san sI o$ the un erlying environment &e.g., %hange A!.s >ith ne> releases o$ an #@K' o not <uali$y $or the $ormal bounty

)o>ever, those Iso$terI issues program.

Fuestions about the bug bounty, or problems you >ish to report $or bounty %onsi eration, shoul be sent to bountyN%ommons>are.%om.

Source Code icense


5he sour%e %o e samples sho>n in this book are available $or o>nloa $rom the CommonsWare Web site. All o$ the An roi proLe%ts are li%ense un er the Apa%he 2.0 Li%ense, in %ase you have the esire to reuse any o$ it.

Creative Commons and the !our"to"!ree #$%!& 'uarantee


Ba%h CommonsWare book e ition >ill be available $or use un er the Creative Commons Attribution30on%ommer%ial3#hare Alike ?.0 li%ense as o$ the $ourth anniversary o$ its publi%ation ate, or >hen =,000 %opies o$ the e ition have been sol , >hi%hever %omes $irst. 5hat means that, on%e $our years have elapse &perhaps sooner:', you %an use this prose $or non3
xiv
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

%ommer%ial purposes. 5hat is our (our3to3(ree 8uarantee to our rea ers an the broa er %ommunity. (or the purposes o$ this guarantee, ne> Wares%riptions an rene>als >ill be %ounte as sales o$ this e ition, starting $rom the time the e ition is publishe . 5his e ition o$ this book >ill be available un er the a$orementione Creative Commons li%ense on +une -# -;&). G$ %ourse, >at%h the CommonsWare Web site, as this e ition might be reli%ense sooner base on sales. (or more etails on the Creative Commons Attribution30on%ommer%ial3 #hare Alike ?.0 li%ense, visit the Creative Commons Web site. 0ote that $uture e itions o$ this book >ill be%ome $ree on later ates, ea%h $our years $rom the publi%ation o$ that e ition or base on sales o$ that spe%i$i% e ition. Releasing one e ition un er the Creative Commons li%ense oes not automati%ally release all e itions un er that li%ense.

ifecycle of a CommonsWare Book


CommonsWare books generally go through a series o$ stages. (irst are the pre3release e itions. 5hese >ill have version numbers belo> 0.9 &e.g., 0.2'. 5hese e itions are in%omplete, o$ten times having but a $e> %hapters to go along >ith outlines an notes. )o>ever, >e make them available to those on the Wares%ription so they %an get early a%%ess to the material. Release %an i ates are e itions >ith version numbers en ing in I.9I &0.9, -.9, et%.'. 5hese e itions shoul be %omplete. Gn%e again, they are ma e available to those on the Wares%ription so they get early a%%ess to the material an %an $ile bug reports &an re%eive bounties in return:'. MaLor e itions are those >ith version numbers en ing in I.0I &-.0, 2.0, et%.'. 5hese >ill be $irst publishe igitally $or the Wares%ription members, but >ill shortly therea$ter be available in print $rom booksellers >orl >i e.

xv
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

,ersions bet>een a maLor e ition an the ne;t release %an i ate &e.g., -.-, -.2' >ill %ontain bug $i;es plus ne> material. Ba%h o$ these e itions shoul also be %omplete, in that you >ill not see any I5/@I &to be one' markers or the like. )o>ever, these e itions may have bugs, an so bug reports are eligible $or the bounty program, as >ith release %an i ates an maLor releases. A book usually >ill progress $airly rapi ly through the pre3release e itions to the $irst release %an i ate an ,ersion -.0 M o$ten times, only a $e> months. @epen ing on the book7s s%ope, it may go through another %y%le o$ signi$i%ant improvement &versions -.- through 2.0', though this may take several months to a year or more. Bventually, though, the book >ill go into more o$ a Imaintenan%e mo eI, only getting up ates to $i; bugs an eal >ith maLor e%osystem events M $or e;ample, a ne> release o$ the An roi #@K >ill ne%essitate an up ate to all An roi books.

xvi
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

PART I Advanced Widgets

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 1

Web(ie)* +nside and ,ut

An roi uses the WebKit bro>ser engine as the $oun ation $or both its /ro>ser appli%ation an the WebView embe able bro>sing >i get. 5he /ro>ser appli%ation, o$ %ourse, is something An roi users %an intera%t >ith ire%tlyO the WebView >i get is something you %an integrate into your o>n appli%ations $or pla%es >here an )5ML inter$a%e might be use$ul. .n BCG to Android, >e sa> a simple integration o$ a WebView into an An roi a%tivity, >ith the a%tivity i%tating >hat the bro>sing >i get isplaye an ho> it respon e to links. )ere, >e >ill e;pan on this theme, an sho> ho> to more tightly integrate the +ava environment o$ an An roi appli%ation >ith the +avas%ript environment o$ WebKit.

!riends )ith Benefits


When you integrate a WebView into your a%tivity, you %an %ontrol >hat Web pages are isplaye , >hether they are $rom a lo%al provi er or %ome $rom over the .nternet, >hat shoul happen >hen a link is %li%ke , an so $orth. An bet>een WebView, WebViewClient, an WebSettings, you %an %ontrol a $air bit about ho> the embe e bro>ser behaves. Det, by e$ault, the bro>ser itsel$ is Lust a bro>ser, %apable o$ sho>ing Web pages an intera%ting >ith Web sites, but other>ise gaining nothing $rom being hoste by an An roi appli%ation.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Web(ie)* +nside and ,ut

B;%ept $or one thing* addJavascriptInterface(). 5he addJavascriptInterface() metho on WebView allo>s you to inLe%t a +ava obLe%t into the WebView, e;posing its metho s, so they %an be %alle by +avas%ript loa e by the Web %ontent in the WebView itsel$. 0o> you have the po>er to provi e a%%ess to a >i e range o$ An roi $eatures an %apabilities to your WebView3hoste %ontent. .$ you %an a%%ess it $rom your a%tivity, an i$ you %an >rap it in something %onvenient $or use by +avas%ript, your Web pages %an a%%ess it as >ell. (or e;ample, 8oogle7s 8ears proLe%t o$$ers a 8eolo%ation A!., so Web pages loa e in a 8ears3enable bro>ser %an $in out >here the bro>ser is lo%ate . 5his in$ormation %oul be use $or everything $rom $ine3tuning a sear%h to emphasiCe lo%al %ontent to serving up lo%ale3tailore a vertising. We %an o mu%h o$ the same thing >ith An roi an

addJavascriptInterface().

.n the WebView/GeoWeb1 proLe%t, you >ill $in &main.xml'*

a $airly simple layout

!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,orientation#$vertical$ ""android,la+o&t/widt-#$fill/parent$ ""android,la+o&t/-eig-t#$fill/parent$ "") "" WebView"android,id#$01id/web.it$ """"android,la+o&t/widt-#$fill/parent$" """"android,la+o&t/-eig-t#$fill/parent$" ""/) /*inear*a+o&t)

All this oes is host a $ull3s%reen WebView >i get. 0e;t, take a look at the GeoWeb2ne a%tivity %lass*
p&blic"class"GeoWeb2ne"extends"3ctivit+"4 ""private"static"String"562VI786#*ocation9anager.G5S/562VI786:

%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Web(ie)* +nside and ,ut

""private"WebView"browser: ""private"*ocation9anager"m+*ocation9anager#n&ll: "" ""02verride ""p&blic"void"onCreate(;&ndle"icicle)"4 """"s&per.onCreate(icicle): """" """"setContentView(6.la+o&t.main): """"browser#(WebView)findViewById(6.id.web.it): """" """"m+*ocation9anager#(*ocation9anager)getSystemService(Context.*2C3<I2=/S86VIC8 ): """" """"browser.getSettings().setJavaScriptEnabled(tr&e): """"browser.addJavascriptInterface(new"Locater()>"$locater$): """"browser.loadUrl($file,///android/asset/geoweb1.-tml$): ""? "" ""02verride ""p&blic"void"onResume()"4 """"s&per.onResume(): """"m+*ocation9anager.requestLocationUpdates(562VI786>"1%%%%> """"""""""""""""""""""""""""""""""""""""""""1%%.%f> """"""""""""""""""""""""""""""""""""""""""""on*ocationC-ange): ""? "" ""02verride ""p&blic"void"on ause()"4 """"s&per.on ause(): """"m+*ocation9anager.removeUpdates(on*ocationC-ange): ""? "" ""*ocation*istener"on*ocationC-ange#new"LocationListener()"4 """"p&blic"void"onLocationC!anged(*ocation"location)"4 """"""//"ignore...for"now """"? """" """"p&blic"void"on rovider"isabled(String"provider)"4 """"""//"re@&ired"for"interface>"not"&sed """"? """" """"p&blic"void"on roviderEnabled(String"provider)"4 """"""//"re@&ired"for"interface>"not"&sed """"? """" """"p&blic"void"onStatusC!anged(String"provider>"int"stat&s> """"""""""""""""""""""""""""""""";&ndle"extras)"4 """"""//"re@&ired"for"interface>"not"&sed """"? ""?: "" ""p&blic"class"*ocater"4 """"p&blic"do&ble"getLatitude()"4 """"""*ocation"loc#m+*ocation9anager.getLast#nownLocation(562VI786):

.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Web(ie)* +nside and ,ut

"""""" """"""if"(loc##n&ll)"4 """"""""ret&rn(%): """"""? """""" """"""ret&rn(loc.getLatitude()): """"? """" """"p&blic"do&ble"getLongitude()"4 """"""*ocation"loc#m+*ocation9anager.getLast#nownLocation(562VI786): """""" """"""if"(loc##n&ll)"4 """"""""ret&rn(%): """"""? """""" """"""ret&rn(loc.getLongitude()): """"? ""? ?

5his looks a bit like some o$ the WebView e;amples in the BCG to Android7s %hapter on integrating WebKit. )o>ever, it a s three key bits o$ %o e* -. .t sets up the *ocation9anager to provi e up ates >hen the evi%e position %hanges, routing those up ates to a o3nothing *ocation*istener %allba%k obLe%t

2. .t has a *ocater inner %lass that provi es a %onvenient A!. $or a%%essing the %urrent lo%ation, in the $orm o$ latitu e an longitu e values ?. .t uses addJavascriptInterface() to e;pose a *ocater instan%e un er the name locater to the Web %ontent loa e in the WebView 5he re$eren%e in the sour%e %o e as file,///android/asset/geoweb1.-tml, so the GeoWeb1 proLe%t has a %orrespon ing assets/ ire%tory %ontaining geoweb1.-tml*
-tml) -ead) title)3ndroid"GeoWeb2ne"7emo /title) script"lang&age#$Aavascript$) ""f&nction"w-ereami()"4 """"doc&ment.get8lement;+Id($lat$).innerB<9*#locater.get*atit&de(): """"doc&ment.get8lement;+Id($lon$).innerB<9*#locater.get*ongit&de(): ""? /script) /-ead)

Web

page

itsel$

is

$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Web(ie)* +nside and ,ut

bod+) p) Co&"are"at," br/)" span"id#$lat$)(&n.nown) /span)"latit&de"and" br/) span"id#$lon$)(&n.nown) /span)"longit&de. /p) p) a"onClic.#$w-ereami()$)Dpdate"*ocation /a) /p) /bod+) /-tml)

When you %li%k the I"p ate Lo%ationI link, the page %alls a w-ereami()" +avas%ript $un%tion, >hi%h in turn uses the locater obLe%t to up ate the latitu e an longitu e, initially sho>n as I&unkno>n'I on the page. .$ you run the appli%ation, initially, the page is pretty boring*

!igure -/ The 'eoWeb,ne sample application* as initially launched

)o>ever, i$ you >ait a bit $or a 8!# $i;, an %li%k the I"p ate Lo%ationI link...the page is still pretty boring, but it at least kno>s >here you are*

0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Web(ie)* +nside and ,ut

!igure %/ The 'eoWeb,ne sample application* after clicking the 1pdate ocation link

Turnabout is !air Play


0o> that >e have seen ho> +avas%ript %an %all into +ava, it >oul be ni%e i$ +ava %oul someho> %all out to +avas%ript. .n our e;ample, it >oul be help$ul i$ >e %oul e;pose automati% lo%ation up ates to the Web page, so it %oul proa%tively up ate the position as the user moves, rather than >ait $or a %li%k on the I"p ate Lo%ationI link. Well, as lu%k >oul have it, >e %an o that too. 5his is a goo other>ise, this >oul be a really >eak se%tion o$ the book. thing,

What is unusual is ho> you %all out to +avas%ript. Gne might imagine there >oul be an exec&teJavascript() %ounterpart to addJavascriptInterface(), >here you %oul supply some +avas%ript sour%e an have it e;e%ute >ithin the %onte;t o$ the %urrently3loa e Web page. G ly enough, that is not ho> this is a%%omplishe .

2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Web(ie)* +nside and ,ut

.nstea , given your snippet o$ +avas%ript sour%e to e;e%ute, you %all loadDrl() on your WebView, as i$ you >ere going to loa a Web page, but you put Aavascript, in $ront o$ your %o e an use that as the Ia ressI to loa . .$ you have ever %reate a IbookmarkletI $or a esktop Web bro>ser, you >ill re%ogniCe this te%hni<ue as being the An roi analogue M the Aavascript, pre$i; tells the bro>ser to treat the rest o$ the a ress as +avas%ript sour%e, inLe%te into the %urrently3vie>e Web page. #o, arme >ith this %apability, let us mo i$y the previous e;ample to %ontinuously up ate our position on the Web page. 5he layout $or this ne> proLe%t &WebView/GeoWebE' is the same as be$ore. 5he +ava sour%e $or our a%tivity %hanges a bit*
p&blic"class"GeoWeb<wo"extends"3ctivit+"4 ""private"static"String"562VI786#$gps$: ""private"WebView"browser: ""private"*ocation9anager"m+*ocation9anager#n&ll: "" ""02verride ""p&blic"void"onCreate(;&ndle"icicle)"4 """"s&per.onCreate(icicle): """"setContentView(6.la+o&t.main): """"browser#(WebView)findViewById(6.id.web.it): """" """"m+*ocation9anager#(*ocation9anager)getSystemService(Context.*2C3<I2=/S86VIC8 ): """" """"browser.getSettings().setJavaScriptEnabled(tr&e): """"browser.addJavascriptInterface(new"Locater()>"$locater$): """"browser.loadUrl($file,///android/asset/geowebE.-tml$): ""? "" ""02verride ""p&blic"void"onResume()"4 """"s&per.onResume(): """"m+*ocation9anager.requestLocationUpdates(562VI786>"%> """"""""""""""""""""""""""""""""""""""""""""%> """"""""""""""""""""""""""""""""""""""""""""on*ocationC-ange): ""? "" ""02verride ""p&blic"void"on ause()"4 """"s&per.on ause(): """"m+*ocation9anager.removeUpdates(on*ocationC-ange): ""?

3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Web(ie)* +nside and ,ut

"" ""*ocation*istener"on*ocationC-ange#new"LocationListener()"4 """"p&blic"void"onLocationC!anged(*ocation"location)"4 """"""String;&ilder"b&f#new"StringBuilder($Aavascript,w-ereami($): """""" """"""b&f.append(String.value$f(location.getLatitude())): """"""b&f.append($>$): """"""b&f.append(String.value$f(location.getLongitude())): """"""b&f.append($)$): """""" """"""browser.loadUrl(b&f.toString()): """"? """" """"p&blic"void"on rovider"isabled(String"provider)"4 """"""//"re@&ired"for"interface>"not"&sed """"? """" """"p&blic"void"on roviderEnabled(String"provider)"4 """"""//"re@&ired"for"interface>"not"&sed """"? """" """"p&blic"void"onStatusC!anged(String"provider>"int"stat&s> """"""""""""""""""""""""""""""""";&ndle"extras)"4 """"""//"re@&ired"for"interface>"not"&sed """"? ""?: "" ""p&blic"class"*ocater"4 """"p&blic"do&ble"getLatitude()"4 """"""*ocation"loc#m+*ocation9anager.getLast#nownLocation(562VI786): """""" """"""if"(loc##n&ll)"4 """"""""ret&rn(%): """"""? """""" """"""ret&rn(loc.getLatitude()): """"? """" """"p&blic"do&ble"getLongitude()"4 """"""*ocation"loc#m+*ocation9anager.getLast#nownLocation(562VI786): """""" """"""if"(loc##n&ll)"4 """"""""ret&rn(%): """"""? """""" """"""ret&rn(loc.getLongitude()): """"? ""? ?

/e$ore, the on*ocationC-anged() metho o$ our *ocation*istener %allba%k i nothing. 0o>, it buil s up a %all to a w-ereami() +avas%ript $un%tion, provi ing the latitu e an longitu e as parameters to that %all. #o, $or
4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Web(ie)* +nside and ,ut

e;ample, i$ our lo%ation >ere =0 egrees latitu e an 31A egrees longitu e, the %all >oul be w-ereami(F%>'GH). 5hen, it puts Aavascript, in $ront o$ it an %alls loadDrl() on the WebView. 5he result is that a w-ereami() $un%tion in the Web page gets %alle >ith the ne> lo%ation. 5hat Web page, o$ %ourse, also nee e a slight revision, to a%%ommo ate the option o$ having the position be passe in*
-tml) -ead) title)3ndroid"GeoWeb<wo"7emo /title) script"lang&age#$Aavascript$) ""f&nction"w-ereami(lat>"lon)"4 """"doc&ment.get8lement;+Id($lat$).innerB<9*#lat: """"doc&ment.get8lement;+Id($lon$).innerB<9*#lon: ""? /script) /-ead) bod+) p) Co&"are"at," br/)" span"id#$lat$)(&n.nown) /span)"latit&de"and" br/) span"id#$lon$)(&n.nown) /span)"longit&de. /p) p) a"onClic.#$w-ereami(locater.get*atit&de()>"locater.get*ongit&de())$) Dpdate"*ocation /a) /p) /bod+) /-tml)

5he basi%s are the same, an >e %an even keep our I"p ate Lo%ationI link, albeit >ith a slightly i$$erent onClic. attribute. .$ you buil , install, an run this revise sample on a 8!#3e<uippe An roi evi%e, the page >ill initially isplay >ith I&unkno>n'I $or the %urrent position. A$ter a $i; is rea y, though, the page >ill automati%ally up ate to re$le%t your a%tual position. An , as be$ore, you %an al>ays %li%k I"p ate Lo%ationI i$ you >ish.

'earing 1p
.n these e;amples, >e emonstrate ho> Web,ie> %an intera%t >ith +ava %o e, %o e that provi es a servi%e a little like one o$ those $rom 8ears.

5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Web(ie)* +nside and ,ut

G$ %ourse, >hat >oul be really sli%k is i$ >e %oul use 8ears itsel$. 5he goo ne>s is that An roi is %lose on that $ront. 8ears is a%tually bake into An roi . )o>ever, it is only e;pose by the /ro>ser appli%ation, not via WebView. #o, an en user o$ an An roi evi%e %an leverage 8ears3enable Web pages. (or e;ample, you %oul loa the 8eolo%ation sample appli%ation in your An roi evi%e7s /ro>ser appli%ation. .nitially, you >ill get the stan ar I%an >e please use 8earsJI se%urity prompt*

!igure ./ The 'ears security prompt

5hen, 8ears >ill $ire up the 8!# inter$a%e &i$ enable ' an >ill $et%h your lo%ation*

-6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Web(ie)* +nside and ,ut

!igure $/ The 'ears 'eolocation sample application

Back To The !uture


5he %ore An roi team has in i%ate that these sorts o$ %apabilities >ill in%rease in $uture e itions o$ the An roi operating system. 5his %oul in%lu e support $or more types o$ plugins, a ri%her +ava3+avas%ript bri ge, an so on. Dou %an also e;pe%t some improvements %oming $rom the overall An roi e%osystem. (or e;ample, the !hone8ap proLe%t is attempting to buil a $rame>ork that supports %reating An roi appli%ations solely out o$ Web %ontent, using Web,ie> as the $ront3en , supporting a range o$ 8ears3like %apabilities an more, su%h as a%%elerometer a>areness.

-Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 2

Crafting 7our ,)n (ie)s

Gne o$ the %lassi% $orms o$ %o e reuse is the 8". >i get. #in%e the a vent o$ Mi%roso$t Win o>s M an , to some e;tent, even earlier M evelopers have been %reating their o>n >i gets to e;ten an e;isting >i get set. 5hese range $rom -43bit Win o>s I%ustom %ontrolsI to ?23bit Win o>s GCH %omponents to the innumerable >i gets available $or +ava #>ing an #W5, an beyon . An roi lets you %ra$t your o>n >i gets as >ell, su%h as e;ten ing an e;isting >i get >ith a ne> ". or ne> behaviors.

'etting 8eta
Gne %ommon >ay o$ %reating your o>n >i gets is to aggregate other >i gets together into a reusable ImetaI >i get. Rather than >orry about all the etails o$ measuring the >i get siCes an ra>ing its %ontents, you simply >orry about %reating the publi% inter$a%e $or ho> one intera%ts >ith the >i get. .n this se%tion, >e >ill look at the Views/9eter sample proLe%t. )ere, >e bun le a 5rogress;ar an t>o Image;&tton >i gets into a reusable 9eter" >i get, allo>ing one to %hange a value by %li%king Iin%rementI an I e%rementI buttons. .n most %ases, one >oul probably be better serve using the built3in See.;ar >i get. )o>ever, there are times >hen >e only >ant people to %hange the value a %ertain amount at a time, $or >hi%h the 9eter is i eally suite . .n $a%t, >e >ill reuse the 9eter in a later %hapter >hen >e sho> ho> to manipulate the various volume levels in An roi .
-.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

The

id!et "ayout

5he $irst step to>ar s %reating a reusable >i get is to lay it out. .n some %ases, you may pre$er to %reate your >i get %ontents purely in +ava, parti%ularly i$ many %opies o$ the >i get >ill be %reate an you o not >ant to in$late them every time. )o>ever, other>ise, layout HML is simpler in many %ases than the in3+ava alternative. )ere is one su%h 9eter layout &res/la+o&t/meter.xml in Views/9eter'*
!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,orientation#$-oriIontal$ ""android,la+o&t/widt-#$fill/parent$ ""android,la+o&t/-eig-t#$wrap/content$ ) "" Image;&tton"android,id#$01id/decr$ """"android,la+o&t/-eig-t#$J%px$ """"android,la+o&t/widt-#$J%px$ """"android,src#$0drawable/decr$ ""/) "" 5rogress;ar"android,id#$01id/bar$ """"st+le#$!android,attr/progress;arSt+leBoriIontal$ """"android,la+o&t/widt-#$%px$ """"android,la+o&t/weig-t#$1$ """"android,la+o&t/-eig-t#$wrap/content$ ""/) "" Image;&tton"android,id#$01id/incr$ """"android,la+o&t/-eig-t#$J%px$ """"android,la+o&t/widt-#$J%px$ """"android,src#$0drawable/incr$ ""/) /*inear*a+o&t)

All >e o is line them up in a ro>, giving the 5rogress;ar any e;%ess spa%e &via android,la+o&t/widt-"#"$%px$ an android,la+o&t/weig-t"#"$1$'. We are using a pair o$ -4;-4 pi;el images $rom the 0uvola i%on set $or the in%rement an e%rement button $a%es.

The Attri#ute Declarations


Wi gets usually have attributes that you %an set in the HML $ile, su%h as the android,src attribute >e spe%i$ie on the Image;&tton >i gets in the layout

-$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

above. Dou %an %reate your o>n %ustom attributes that %an be use in your %ustom >i get, by %reating a res/val&es/attrs.xml $ile to spe%i$y them. (or e;ample, here is the attributes $ile $or 9eter*
reso&rces) "" declare'st+leable"name#$9eter$) """" attr"name#$max$"format#$integer$"/) """" attr"name#$incr$"format#$integer$"/) """" attr"name#$decr$"format#$integer$"/) "" /declare'st+leable) /reso&rces)

5he declare'st+leable element es%ribes >hat attributes are available on the >i get %lass spe%i$ie in the name attribute M in our %ase, >e >ill %all the >i get 9eter. .nsi e declare'st+leable you %an have one or more attr" elements, ea%h in i%ating the name o$ an attribute &e.g., incr' an >hat ata type the attribute has &e.g., integer'. 5he ata type >ill help >ith %ompile3time vali ation an in getting any supplie values $or this attribute parse into the appropriate type at runtime. )ere, >e in i%ate there are three attributes* max &in i%ating the highest value the 9eter >ill go to', incr &in i%ating ho> mu%h the value shoul in%rease >hen the in%rement button is %li%ke ', an decr &in i%ating ho> mu%h the value shoul e%rease >hen the e%rement button is %li%ke '.

The

id!et $mplementation

5here are many >ays to go about a%tually implementing a >i get. 5his se%tion outlines one option* using a %ontainer %lass &spe%i$i%ally *inear*a+o&t' an in$lating the %ontents o$ your >i get layout into the %ontainer.

The Constructor
5o be usable insi e o$ layout HML, you nee to implement a %onstru%tor that takes t>o parameters*

-0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

-.

A Context obLe%t, typi%ally representing the 3ctivit+ that is in$lating your >i get

2. An 3ttrib&teSet, representing the bun le o$ attributes in%lu e in the element in the layout being in$late that re$eren%es your >i get .n this %onstru%tor, a$ter %haining to your super%lass, you %an o some basi% %on$iguration o$ your >i get. /ear in min , though, that you are not in position to %on$igure the >i gets that make up your aggregate >i get M you nee to >ait until onKinis-Inflate() be$ore you %an o anything >ith those. Gne thing you e$initely >ant to o in the %onstru%tor, though, is use that 3ttrib&teSet to get the values o$ >hatever attributes you e$ine in your attrs.xml $ile. (or e;ample, here is the %onstru%tor $or 9eter*
p&blic"%eter(final"Context"ctxt>"3ttrib&teSet"attrs)"4 ""s&per(ctxt>"attrs): ""t-is.set$rientation(B26IL2=<3*): ""<+ped3rra+"a#ctxt.obtainStyled&ttributes(attrs> """"""""""""""""""""""""""""""""""""""""""6.st+leable.9eter> """"""""""""""""""""""""""""""""""""""""""%>"%): ""max#a.getInt(6.st+leable.9eter/max>"1%%): ""incr3mo&nt#a.getInt(6.st+leable.9eter/incr>"1): ""decr3mo&nt#'1Ma.getInt(6.st+leable.9eter/decr>"1): ""a.recycle(): ?

5he obtainSt+led3ttrib&tes() on Context allo>s us to %onvert the 3ttrib&teSet into use$ul values*

.t resolves re$eren%es to other resour%es, su%h as strings .t han les any styles that might be e%lare via the style attribute in the layout element that re$eren%es your >i get .t $in s the resour%es you e%lare via attrs.;ml an makes them available to you the %o e sho>n above, >e get our <+ped3rra+ via then %all getInt() three times to get our values
-2

.n

obtainSt+led3ttrib&tes(),

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

out o$ the <+ped3rra+. 5he <+ped3rra+ is keye by 6.st+leable i enti$iers, so >e use the three generate $or us by the buil tools $or max, incr, an decr. 0ote that you shoul %all rec+cle() on the <+ped3rra+ >hen one M this makes this <+ped3rra+ available $or imme iate reuse, rather than $or%ing it to be garbage3%olle%te .

Finishing Inflation
Dour >i get >ill also typi%ally overri e onKinis-Inflate(). At this point, you %an turn aroun an a your o>n %ontents, via +ava %o e or, as sho>n belo>, by in$lating a layout HML resour%e into yoursel$ as a %ontainer*
02verride protected"void"on'inis!Inflate()"4 ""s&per.on'inis!Inflate(): ""((3ctivit+)getConte(t()).getLayoutInflater().inflate(6.la+o&t.meter>"t-is): ""bar#(5rogress;ar)findViewById(6.id.bar): ""bar.set%a((max): ""Image;&tton"btn#(Image;&tton)findViewById(6.id.incr): ""btn.set$nClic)Listener(new"View.$nClic)Listener()"4 """"p&blic"void"onClic)(View"v)"4 """"""bar.increment rogressBy(incr3mo&nt): """"""if"(onIncrN#n&ll)"4 """"""""onIncr.onClic)(9eter.t-is): """"""? """"? ""?): ""btn#(Image;&tton)findViewById(6.id.decr): ""btn.set$nClic)Listener(new"View.$nClic)Listener()"4 """"p&blic"void"onClic)(View"v)"4 """"""bar.increment rogressBy(decr3mo&nt): """"""if"(on7ecrN#n&ll)"4 """"""""on7ecr.onClic)(9eter.t-is): """"""? """"? ""?): ?

-3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

G$ %ourse, on%e you have %onstru%te or in$late your %ontents, you %an %on$igure them, parti%ularly using the attributes you e%lare in attrs.;ml an retrieve in your %onstru%tor.

Event Handlers and Other Methods


.$ you >ish to e;pose events to the outsi e >orl M su%h as 9eter e;posing >hen the in%rement or e%rement buttons are %li%ke M you nee to o a $e> things*

Choose or %reate an appropriate listener %lass or %lasses &e.g., View.2nClic.*istener' )ol onto instan%es o$ those %lasses as ata members o$ the >i get %lass G$$er setters &an , optionally, getters' to obLe%ts Call those listeners >hen appropriate e$ine those listener

(or e;ample, 9eter hol s onto a pair o$ View.2nClic.*istener instan%es*


private"View.2nClic.*istener"onIncr#n&ll: private"View.2nClic.*istener"on7ecr#n&ll:

.t lets users o$ 9eter e$ine those listeners via getters*


p&blic"void"set$nIncrListener(View.2nClic.*istener"onIncr)"4 ""t-is.onIncr#onIncr: ? p&blic"void"set$n"ecrListener(View.2nClic.*istener"on7ecr)"4 ""t-is.on7ecr#on7ecr: ?

An , as sho>n in the previous se%tion, it passes along the button %li%ks to the listeners*
Image;&tton"btn#(Image;&tton)findViewById(6.id.incr): btn.set$nClic)Listener(new"View.$nClic)Listener()"4

-4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

""p&blic"void"onClic)(View"v)"4 """"bar.increment rogressBy(incr3mo&nt): """"if"(onIncrN#n&ll)"4 """"""onIncr.onClic)(9eter.t-is): """"? ""? ?): btn#(Image;&tton)findViewById(6.id.decr): btn.set$nClic)Listener(new"View.$nClic)Listener()"4 ""p&blic"void"onClic)(View"v)"4 """"bar.increment rogressBy(decr3mo&nt): """"if"(on7ecrN#n&ll)"4 """"""on7ecr.onClic)(9eter.t-is): """"? ""? ?):

0ote that >e %hange the value passe in the onClic.() metho M our listener re%eives the Image;&tton, but >e pass the 9eter >i get on the outboun onClic.() %all. 5his is so >e o not leak internal implementation o$ our >i get. 5he users o$ 9eter shoul neither kno> nor %are that >e have Image;&tton >i gets as part o$ the 9eter internals. Dour >i get may >ell re<uire other metho s as >ell, $or >i get3spe%i$i% %on$iguration or $un%tionality, though 9eter oes not.

%sin! the

id!et

8iven all o$ that, using the 9eter >i get is not signi$i%antly i$$erent than using any other >i get provi e in the system...>ith a $e> minor e;%eptions. .n the layout, sin%e your %ustom >i get is not in the android.widget +ava pa%kage, you nee to $ully3<uali$y the %lass name $or the >i get, as seen in the main.xml layout $or the Views/9eter proLe%t*
!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""xmlns,app#$-ttp,//sc-emas.android.com/ap./res/com.commonsware.android.widget$

-5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

""android,orientation#$-oriIontal$ ""android,la+o&t/widt-#$fill/parent$ ""android,la+o&t/-eig-t#$wrap/content$ ""android,padding<op#$Hpx$ ) "" <extView"" """"android,la+o&t/widt-#$wrap/content$" """"android,la+o&t/-eig-t#$wrap/content$" """"android,text#$9eter,$ ""/) "" com.commonsware.android.widget.9eter """"android,id#$01id/meter$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$wrap/content$ """"app,max#$1%%$ """"app,incr#$1$ """"app,decr#$H$ ""/)""""""""""""""""""""""""""""""""""""" /*inear*a+o&t)

Dou >ill also note that >e have a ne> namespa%e &xmlns,app " #" $-ttp,//sc-emas.android.com/ap./res/com.commonsware.android.widget$', an that our %ustom attributes $rom above are in that namespa%e &e.g., app,max'. 5he %ustom namespa%e is be%ause our attributes are not o$$i%ial An roi ones an so >ill not be re%ogniCe by the buil tools in the android," namespa%e, so >e have to %reate our o>n. 5he value o$ the namespa%e nee s to be -ttp,//sc-emas.android.com/ap./res/ plus the name o$ the pa%kage %ontaining the styleable attributes &com.commonsware.android.widget'. With Lust the sto%k generate a%tivity, >e get the $ollo>ing ".*

%6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

!igure 0/ The 8eter9emo application

0ote that there is a signi$i%ant short%ut >e are taking here* our 9eter" implementation an its %onsumer &9eter7emo' are in the same +ava pa%kage. We >ill e;pose this short%ut in a later %hapter >hen >e use the 9eter" >i get in another proLe%t.

Change of State
#ometimes, >e o not nee to %hange the $un%tionality o$ an e;isting >i get, but >e simply >ant to %hange ho> it looks. Maybe you >ant an o ly3shape ;&tton, or a C-ec.;ox that is mu%h larger, or something. .n these %ases, you may be able to tailor instan%es o$ the e;isting >i get as you see $it, rather than have to roll a separate >i get yoursel$.

Chan!in! Button Bac&!rounds


#uppose you >ant a ;&tton that looks like the se%on button sho>n belo>*

%Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

!igure 2/ The !ancyButton application* sho)ing a normal oval"shaped button

Moreover, it nee s to not Lust sit there, but also be $o%usable*

!igure 3/ The !ancyButton application* sho)ing a focused oval"shaped button

%%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

...an it nee s to be %li%kable*

!igure 4/ The !ancyButton application* sho)ing a pressed oval"shaped button

.$ you i not >ant the look o$ the ;&tton to %hange, you %oul get by Lust >ith a simple android,bac.gro&nd attribute on the ;&tton, provi ing an oval !08. )o>ever, i$ you >ant the /utton to %hange looks base on state, you nee to %reate another $lavor o$ %ustom 7rawable M the sele%tor. A sele%tor 7rawable is an HML $ile, akin to shapes >ith gra ients. )o>ever, rather than spe%i$ying a shape, it spe%i$ies a set o$ other 7rawable resour%es an the %ir%umstan%es un er >hi%h they shoul be applie , as es%ribe via a series o$ states $or the >i get using the 7rawable. (or e;ample, $rom Views/Kanc+;&tton, here is res/drawable/fanc+b&tton.xml, implementing a sele%tor 7rawable*
!xml"version#$1.%$"encoding#$&tf'($!) selector"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$) "" item """"android,state/foc&sed#$tr&e$" """"android,state/pressed#$false$" """"android,drawable#$0drawable/btn/oval/selected$

%.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

""/) "" item """"android,state/foc&sed#$tr&e$" """"android,state/pressed#$tr&e$ """"android,drawable#$0drawable/btn/oval/pressed$ ""/) "" item """"android,state/foc&sed#$false$" """"android,state/pressed#$tr&e$ """"android,drawable#$0drawable/btn/oval/pressed$ ""/) "" item """"android,drawable#$0drawable/btn/oval/normal$ ""/) /selector)

5here are $our states being es%ribe in this sele%tor* -. Where the button is $o%use &android,state/foc&sed"#"$tr&e$' but not presse &android,state/pressed"#"$false$'

2. Where the button is both $o%use an presse ?. Where the button is not $o%use but is presse =. 5he e$ault, >here the button is neither $o%use nor presse .n these $our states, >e spe%i$y three 7rawable resour%es, $or normal, $o%use , an presse &the latter being use regar less o$ $o%us'. .$ >e spe%i$y this sele%tor 7rawable resour%e as the android,bac.gro&nd o$ a ;&tton, An roi >ill use the appropriate !08 base on the status o$ the ;&tton itsel$*
!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,orientation#$-oriIontal$ ""android,la+o&t/widt-#$fill/parent$ ""android,la+o&t/-eig-t#$wrap/content$ ) "" ;&tton """"android,la+o&t/widt-#$wrap/content$ """"android,la+o&t/-eig-t#$wrap/content$ """"android,text#$Clic."meN$ ""/) "" ;&tton """"android,la+o&t/widt-#$wrap/content$ """"android,la+o&t/-eig-t#$wrap/content$

%$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

""""android,text#$Clic."meN$ """"android,bac.gro&nd#$0drawable/fanc+b&tton$ ""/) /*inear*a+o&t)

Chan!in! Chec&Bo' (tates


5he same basi% %on%ept %an be use C-ec.;ox. to %hange the images use by a

.n this %ase, the $a%t that An roi is open sour%e helps, as >e %an e;tra%t $iles an resour%es $rom An roi an a Lust them to %reate our o>n e itions, >ithout >orrying about li%ense hassles. (or e;ample, here is a sele%tor 7rawable $or a $an%y C-ec.;ox, sho>ing a iCCying array o$ possible states*
!xml"version#$1.%$"encoding#$&tf'($!) selector"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$) """" N''"8nabled"states"'') """""" """" item"android,state/c-ec.ed#$tr&e$"android,state/window/foc&sed#$false$ """"""""""android,state/enabled#$tr&e$ """"""""""android,drawable#$0drawable/btn/c-ec./on$"/) """" item"android,state/c-ec.ed#$false$"android,state/window/foc&sed#$false$ """"""""""android,state/enabled#$tr&e$ """"""""""android,drawable#$0drawable/btn/c-ec./off$"/) """" item"android,state/c-ec.ed#$tr&e$"android,state/pressed#$tr&e$ """"""""""android,state/enabled#$tr&e$ """"""""""android,drawable#$0drawable/btn/c-ec./on/pressed$"/) """" item"android,state/c-ec.ed#$false$"android,state/pressed#$tr&e$ """"""""""android,state/enabled#$tr&e$ """"""""""android,drawable#$0drawable/btn/c-ec./off/pressed$"/) """" item"android,state/c-ec.ed#$tr&e$"android,state/foc&sed#$tr&e$ """"""""""android,state/enabled#$tr&e$ """"""""""android,drawable#$0drawable/btn/c-ec./on/selected$"/) """" item"android,state/c-ec.ed#$false$"android,state/foc&sed#$tr&e$ """"""""""android,state/enabled#$tr&e$ """"""""""android,drawable#$0drawable/btn/c-ec./off/selected$"/) """" item"android,state/c-ec.ed#$false$ """"""""""android,state/enabled#$tr&e$ """"""""""android,drawable#$0drawable/btn/c-ec./off$"/) """" item"android,state/c-ec.ed#$tr&e$

%0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

""""""""""android,state/enabled#$tr&e$ """"""""""android,drawable#$0drawable/btn/c-ec./on$"/) """" N''"7isabled"states"'') """" item"android,state/c-ec.ed#$tr&e$"android,state/window/foc&sed#$false$ """"""""""android,drawable#$0drawable/btn/c-ec./on/disable$"/) """" item"android,state/c-ec.ed#$false$"android,state/window/foc&sed#$false$ """"""""""android,drawable#$0drawable/btn/c-ec./off/disable$"/) """" item"android,state/c-ec.ed#$tr&e$"android,state/foc&sed#$tr&e$ """"""""""android,drawable#$0drawable/btn/c-ec./on/disable/foc&sed$"/) """" item"android,state/c-ec.ed#$false$"android,state/foc&sed#$tr&e$ """"""""""android,drawable#$0drawable/btn/c-ec./off/disable/foc&sed$"/) """" item"android,state/c-ec.ed#$false$" android,drawable#$0drawable/btn/c-ec./off/disable$"/) """" item"android,state/c-ec.ed#$tr&e$" android,drawable#$0drawable/btn/c-ec./on/disable$"/) /selector)

Ba%h o$ the re$eren%e !08 images %an be e;tra%te $rom the android.Aar" $ile in your An roi #@K, or obtaine $rom various online resour%es. .n the %ase o$ Views/Kanc+C-ec., >e Coome ea%h o$ the images to 200P o$ original siCe, to make a set o$ large &albeit $uCCy' %he%kbo; images.

!igure 5/ :n example of a ;oomed CheckBox image

.n

res/drawable/fanc+c-ec..xml sele%tor 7rawable as our

our

layout,

>e

%an

spe%i$y

that

>e

>ant to use ba%kgroun *

our

!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,orientation#$vertical$ ""android,la+o&t/widt-#$fill/parent$ ""android,la+o&t/-eig-t#$wrap/content$ ) "" C-ec.;ox %2


Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Crafting 7our ,)n (ie)s

""""android,la+o&t/widt-#$wrap/content$ """"android,la+o&t/-eig-t#$wrap/content$ """"android,text#$IOm"normalN$ ""/) "" C-ec.;ox """"android,la+o&t/widt-#$wrap/content$ """"android,la+o&t/-eig-t#$wrap/content$ """"android,text#$""""""""$ """"android,b&tton#$0drawable/fanc+c-ec.$ """"android,bac.gro&nd#$0drawable/btn/c-ec./label/bac.gro&nd$ ""/) /*inear*a+o&t)

5his gives us a look like this*

!igure -6/ The !ancyCheck application* sho)ing a focused and checked CheckBox

0ote that our C-ec.;ox te;t is blank. 5he reason is that C-ec.;ox is e;pe%ting the graphi%s to be ?2p; >i e. #in%e ours are substantially larger, the C-ec.;ox images overlap the te;t. (i;ing this >oul re<uire substantial >ork. .t is simplest to $ill the C-ec.;ox te;t >ith some >hitespa%e, then use a separate <extView $or our C-ec.;ox %aption.

%3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER )

8ore !un With ist(ie)s

Gne o$ the most important >i gets in your toolbelt is the *istView. #ome a%tivities are purely a *istView, to allo> the user to si$t through a $e> %hoi%es...or perhaps a $e> thousan . We alrea y sa> in The Busy Coder's Guide to Android De elopment ho> to %reate I$an%y *istViewsI, >here you have %omplete %ontrol over the list ro>s themselves. .n this %hapter, >e >ill %over some a itional te%hni<ues you %an use to make your *istView" >i gets be pleasant $or your users to >ork >ith.

'iant <conomy"Si;e 9ividers


Dou may have noti%e that the pre$eren%e ". has >hat behaves a lot like a *istView, but >ith a %urious %hara%teristi%* not everything is sele%table*

%5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

!igure --/ : PreferenceScreen 1+

Dou may have thought that this re<uire some %ustom >i get, or some $an%y on3the3$ly View han ling, to a%hieve this e$$e%t. .$ so, you >oul have been >rong. .t turns out that any *istView %an e;hibit this behavior. .n this se%tion, >e >ill see ho> this is a%hieve an a reusable $rame>ork $or %reating su%h a *istView.

Choosin!

hat $s (electa#le

5here are t>o metho s in the 3dapter hierar%hy that let you %ontrol >hat is an is not sele%table in a *istView*
are3llItemsSelectable() shoul >i gets an false $or *istView is8nabled(),

return tr&e $or or inary *istView" >i gets >here some items in the A apter are sele%table an others are not given a position, shoul return tr&e i$ the item at that position shoul be sele%table an false other>ise
.6

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

8iven these t>o, it is ImerelyI a matter o$ overri ing your %hosen 3dapter" %lass an implementing these t>o metho s as appropriate to get the visual e$$e%t you esire. As one might e;pe%t, this is not <uite as easy as it may soun . (or e;ample, suppose you have a atabase o$ books, an you >ant to present a list o$ book titles $or the user to %hoose $rom. (urthermore, suppose you have arrange $or the books to be in alphabeti%al or er >ithin ea%h maLor book style &(i%tion, 0on3(i%tion, et%.', %ourtesy o$ a >ell3%ra$te 26786";C %lause on your <uery. An suppose you >ant to have hea ings, like on the pre$eren%es s%reen, $or those book styles. .$ you simply take the C&rsor $rom that <uery an han it to a the t>o metho s %ite above >ill be implemente as the e$ault, saying every ro> is sele%table. An , sin%e every ro> is a book, that is >hat you >ant...$or the books.
SimpleC&rsor3dapter,

5o get the hea ings in pla%e, your 3dapter nee s to mi; the hea ings in >ith the books &so they all appear in the proper se<uen%e', return a %ustom View $or ea%h &so hea ings look i$$erent than the books', an implement the t>o metho s that %ontrol >hether the hea ings or books are sele%table. 5here is no easy >ay to o this $rom a simple <uery. .nstea , you nee
SimpleC&rsor3dapter

to be a bit more %reative, an >rap your in something that %an intelligently inLe%t the se%tion

hea ings.

Composition *or (ections


+e$$ #harkey, author o$ CompareBvery>here an all3aroun An roi guru, emonstrate a >ay o$ using %omposition to %reate a *istView >ith se%tion hea ings. 5he %o e presente here is base on his implementation, >ith a $e> alterations. As his original %o e >as release un er the 8!Lv?, bear in min that the %o e presente here is also release un er the 8!Lv?, as

.Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

oppose to the Apa%he Li%ense 2.0 that most o$ the book7s %o e uses as a li%ense. 5he pattern is $airly simple*

Create one 3dapter $or ea%h se%tion. (or e;ample, in the book s%enario es%ribe above, you might have one SimpleC&rsor3dapter" $or ea%h book style &one $or (i%tion, one $or 0on3(i%tion, et%.'. !ut ea%h o$ those 3dapter obLe%ts into a %ontainer 3dapter, asso%iating ea%h >ith a hea ing name. .mplement, on your %ontainer 3dapter sub%lass, a metho to return the View $or a hea ing, mu%h like you might implement getView() to return a View $or a ro> !ut the %ontainer 3dapter in the *istView, an everything $lo>s $rom there

Dou >ill see this implemente in the *istView/Sections sample proLe%t, >hi%h is another ri$$ on the Ilist o$ lorem ipsum >or sI sample you see s%attere throughout the Busy Coder books. 5he layout $or the s%reen is Lust a *istView, be%ause the a%tivity M Sectioned7emo M is Lust a *ist3ctivit+*
!xml"version#$1.%$"encoding#$&tf'($!) *istView ""xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,id#$0android,id/list$ ""android,la+o&t/widt-#$fill/parent$" ""android,la+o&t/-eig-t#$fill/parent$ ""android,drawSelector2n<op#$tr&e$ /)

3dapter

Most o$ the smarts %an be $oun in Sectioned3dapter. 5his %lass e;ten s an elegates all o$ the 3dapter metho s to a list o$ %hil 3dapter" obLe%ts*
pac.age"com.commonsware.android.listview: import"android.view.View:

.%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

import"android.view.ViewGro&p: import"android.widget.3dapter: import"android.widget.;ase3dapter: import"Aava.&til.3rra+*ist: import"Aava.&til.*ist: abstract"p&blic"class"Sectioned3dapter"extends";ase3dapter"4 ""abstract"protected"View"get*eaderView(String"caption> """""""""""""""""""""""""""""""""""""""int"index> """""""""""""""""""""""""""""""""""""""View"convertView> """""""""""""""""""""""""""""""""""""""ViewGro&p"parent): "" ""private"*ist Section)"sections#new"3rra+*ist Section)(): ""private"static"int"<C58/S8C<I2=/B83786#%: ""p&blic"Sectioned&dapter()"4 """"s&per(): ""? ""p&blic"void"addSection(String"caption>"3dapter"adapter)"4 """"sections.add(new"Section(caption>"adapter)): ""? ""p&blic"2bAect"getItem(int"position)"4 """"for"(Section"section","t-is.sections)"4 """"""if"(position##%)"4 """"""""ret&rn(section): """"""? """""" """"""int"siIe#section.adapter.getCount()11: """"""if"(position siIe)"4 """"""""ret&rn(section.adapter.getItem(position'1)): """"""? """"""position'#siIe: """"? """" """"ret&rn(n&ll): ""? ""p&blic"int"getCount()"4 """"int"total#%: """" """"for"(Section"section","t-is.sections)"4 """"""total1#section.adapter.getCount()11:"//"add"one"for"-eader """"? """" """"ret&rn(total): ""? ""p&blic"int"getView+ypeCount()"4 """"int"total#1:""//"one"for"t-e"-eader>"pl&s"t-ose"from"sections """"

..
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

""""for"(Section"section","t-is.sections)"4 """"""total1#section.adapter.getView+ypeCount(): """"? """" """"ret&rn(total): ""? ""p&blic"int"getItemView+ype(int"position)"4 """"int"t+pe2ffset#<C58/S8C<I2=/B8378611:""//"start"co&nting"from"-ere """" """"for"(Section"section","t-is.sections)"4 """"""if"(position##%)"4 """"""""ret&rn(<C58/S8C<I2=/B83786): """"""? """""" """"""int"siIe#section.adapter.getCount()11: """"""if"(position siIe)"4 """"""""ret&rn(t+pe2ffset1section.adapter.getItemView+ype(position'1)): """"""? """"""position'#siIe: """"""t+pe2ffset1#section.adapter.getView+ypeCount(): """"? """" """"ret&rn('1): ""? ""p&blic"boolean"are&llItemsSelectable()"4 """"ret&rn(false): ""? ""p&blic"boolean"isEnabled(int"position)"4 """"ret&rn(getItemView+ype(position)N#<C58/S8C<I2=/B83786): ""? ""02verride ""p&blic"View"getView(int"position>"View"convertView> """""""""""""""""""""ViewGro&p"parent)"4 """"int"sectionIndex#%: """" """"for"(Section"section","t-is.sections)"4 """"""if"(position##%)"4 """"""""ret&rn(get*eaderView(section.caption>"sectionIndex> """""""""""""""""""""""""""""convertView>"parent)): """"""? """"""int"siIe#section.adapter.getCount()11: """"""if"(position siIe)"4 """"""""ret&rn(section.adapter.getView(position'1> """""""""""""""""""""""""""""""""""""""convertView> """""""""""""""""""""""""""""""""""""""parent)): """"""?

.$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

""""""position'#siIe: """"""sectionIndex11: """"? """" """"ret&rn(n&ll): ""? ""02verride ""p&blic"long"getItemId(int"position)"4 """"ret&rn(position): ""? ""class"Section"4 """"String"caption: """"3dapter"adapter: """" """"Section(String"caption>"3dapter"adapter)"4 """"""t-is.caption#caption: """"""t-is.adapter#adapter: """"? ""? ?

Sectioned3dapter hol s a *ist o$ Section obLe%ts, >here a Section is simply a name an an 3dapter hol ing the %ontents o$ that se%tion o$ the list. Dou %an give Sectioned3dapter the etails o$ a Section via addSection() M the

se%tions >ill appear in the or er in >hi%h they >ere a


Sectioned3dapter

e .

synthesiCes the overall list o$ obLe%ts $rom ea%h o$ the a apters, plus the se%tion hea ings. #o, $or e;ample, the implementation o$ getView() >alks ea%h se%tion an returns either a View $or the se%tion hea er &i$ the re<ueste item is the $irst one $or that se%tion' or the View" $rom the se%tion7s a apter &i$ the re<ueste item is any other one in this se%tion'. 5he same hol s true $or getCo&nt() an getItem(). Gne thing that Sectioned3dapter nee s to o, though, is ensure that the pool o$ se%tion hea er View obLe%ts is re%y%le separately $rom ea%h se%tion7s o>n pool o$ View obLe%ts. 5o o this, Sectioned3dapter takes a vantage o$ getView<+peCo&nt(), by returning the total number o$ istin%t types o$ View obLe%ts $rom all se%tion 3dapters plus one $or its o>n hea er View pool. #imilarly, getItemView<+pe() %onsi ers the %th View type to be the hea er View pool, >ith the pools $or ea%h 3dapter in se<uen%e starting $rom -. 5his pattern re<uires that ea%h se%tion 3dapter have its View type numbers
.0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

starting $rom 0 an in%rementing by -, but most 3dapter %lasses only use one View type an o not even implement their o>n getView<+peCo&nt() or getItemView<+pe(), so this >ill >ork most o$ the time. 5o use a Sectioned3dapter, Sectioned7emo simply %reates one, a s in three se%tions &>ith three sets o$ the lorem ipsum >or s', an atta%hes the Sectioned3dapter to the *istView $or the *ist3ctivit+*
pac.age"com.commonsware.android.listview: import"android.app.*ist3ctivit+: import"android.content.Context: import"android.os.;&ndle: import"android.view.View: import"android.view.ViewGro&p: import"android.widget.3dapterView: import"android.widget.3rra+3dapter: import"android.widget.*istView: import"android.widget.<extView: import"Aava.&til.3rra+s: import"Aava.&til.Collections: import"Aava.&til.*ist: p&blic"class"Sectioned7emo"extends"*ist3ctivit+"4 ""private"static"StringPQ"items#4$lorem$>"$ips&m$>"$dolor$> """""""""""""""""""""""""""""""""$sit$>"$amet$>"$consectet&er$> """""""""""""""""""""""""""""""""$adipiscing$>"$elit$>"$morbi$> """""""""""""""""""""""""""""""""$vel$>"$lig&la$>"$vitae$> """""""""""""""""""""""""""""""""$arc&$>"$ali@&et$>"$mollis$> """""""""""""""""""""""""""""""""$etiam$>"$vel$>"$erat$> """""""""""""""""""""""""""""""""$placerat$>"$ante$> """""""""""""""""""""""""""""""""$porttitor$>"$sodales$> """""""""""""""""""""""""""""""""$pellentes@&e$>"$a&g&e$> """""""""""""""""""""""""""""""""$p&r&s$?: "" ""02verride ""p&blic"void"onCreate(;&ndle"icicle)"4 """"s&per.onCreate(icicle): """"setContentView(6.la+o&t.main): """" """"adapter.addSection($2riginal$> """""""""""""""""""""""new"3rra+3dapter String)(t-is> """""""""""""""""""""""""android.6.la+o&t.simple/list/item/1> """""""""""""""""""""""""items)): """" """"*ist String)"list#3rra+s.asList(items): """" """"Collections.s!uffle(list): """"adapter.addSection($S-&ffled$> """""""""""""""""""""""new"3rra+3dapter String)(t-is> .2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

"""""""""""""""""""""""""android.6.la+o&t.simple/list/item/1> """""""""""""""""""""""""list)): """" """"list#3rra+s.asList(items): """" """"Collections.s!uffle(list): """"adapter.addSection($6e's-&ffled$> """""""""""""""""""""""new"3rra+3dapter String)(t-is> """""""""""""""""""""""""android.6.la+o&t.simple/list/item/1> """""""""""""""""""""""""list)): """" """"setList&dapter(adapter): ""? "" ""Sectioned3dapter"adapter#new"Sectioned&dapter()"4 """"protected"View"get*eaderView(String"caption>"int"index> """""""""""""""""""""""""""""""""View"convertView> """""""""""""""""""""""""""""""""ViewGro&p"parent)"4 """"""<extView"res&lt#(<extView)convertView: """""" """"""if"(convertView##n&ll)"4 """"""""res&lt#(<extView)getLayoutInflater() """"""""""""""""""""""""""""""""".inflate(6.la+o&t.-eader> """"""""""""""""""""""""""""""""""""""""n&ll): """"""? """""" """"""res&lt.set+e(t(caption): """""" """"""ret&rn(res&lt): """"? ""?: ?

5he result is mu%h as you might e;pe%t*

.3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

!igure -%/ : ist(ie) using a Sectioned:dapter* sho)ing one header and part of a list

)ere, the hea ers are simple bits o$ te;t >ith an appropriate style applie . Dour se%tion hea ers, o$ %ourse, %an be as %omple; as you like.

!rom =ead To Toe


!erhaps you o not nee se%tion hea ers s%attere throughout your list. .$ you only nee e;tra I$ake ro>sI at the beginning or en o$ your list, you %an use hea er an $ooter vie>s. supports addBeaderView() an addKooterView() metho s that allo> you to a View obLe%ts to the beginning an en o$ the list, respe%tively. 5hese View obLe%ts other>ise behave like regular ro>s, in that they are part o$ the s%rolle area an >ill s%roll o$$ the s%reen i$ the list is long enough. .$ you >ant $i;e hea ers or $ooters, rather than put them in the *istView" itsel$, put them outsi e the *istView, perhaps using a *inear*a+o&t.
*istView

5o

hea er an $ooter vie>s, take a *istView/BeaderKooter, parti%ularly the BeaderKooter7emo %lass*


.4
Subscribe to updates at http://commonsware.com

emonstrate

peek

at

Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

pac.age"com.commonsware.android.listview: import"android.app.*ist3ctivit+: import"android.content.Context: import"android.os.;&ndle: import"android.os.Bandler: import"android.os.S+stemCloc.: import"android.view.View: import"android.view.ViewGro&p: import"android.widget.3dapterView: import"android.widget.3rra+3dapter: import"android.widget.;&tton: import"android.widget.*istView: import"android.widget.<extView: import"Aava.&til.3rra+s: import"Aava.&til.Collections: import"Aava.&til.*ist: import"Aava.&til.conc&rrent.atomic.3tomic;oolean: p&blic"class"BeaderKooter7emo"extends"*ist3ctivit+"4 ""private"static"StringPQ"items#4$lorem$>"$ips&m$>"$dolor$> """""""""""""""""""""""""""""""""$sit$>"$amet$>"$consectet&er$> """""""""""""""""""""""""""""""""$adipiscing$>"$elit$>"$morbi$> """""""""""""""""""""""""""""""""$vel$>"$lig&la$>"$vitae$> """""""""""""""""""""""""""""""""$arc&$>"$ali@&et$>"$mollis$> """""""""""""""""""""""""""""""""$etiam$>"$vel$>"$erat$> """""""""""""""""""""""""""""""""$placerat$>"$ante$> """""""""""""""""""""""""""""""""$porttitor$>"$sodales$> """""""""""""""""""""""""""""""""$pellentes@&e$>"$a&g&e$> """""""""""""""""""""""""""""""""$p&r&s$?: ""private"long"start<ime#S+stemCloc..uptime%illis(): ""private"Bandler"-andler#new"*andler(): ""private"3tomic;oolean"areWe7eadCet#new"&tomicBoolean(false): "" ""02verride ""p&blic"void"onCreate(;&ndle"icicle)"4 """"s&per.onCreate(icicle): """"setContentView(6.la+o&t.main): """"getListView().add*eaderView(build*eader()): """"getListView().add'ooterView(build'ooter()): """"setList&dapter(new"3rra+3dapter String)(t-is> """""""""""""""""""""""android.6.la+o&t.simple/list/item/1> """""""""""""""""""""""items)): ""? "" ""02verride ""p&blic"void"on"estroy()"4 """"s&per.on"estroy(): """" """"areWe7eadCet.set(tr&e): ""? "" ""private"View"build*eader()"4 """";&tton"btn#new"Button(t-is): """" .5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

""""btn.set+e(t($6andomiIeN$): """"btn.set$nClic)Listener(new"View.$nClic)Listener()"4 """"""p&blic"void"onClic)(View"v)"4 """"""""*ist String)"list#3rra+s.asList(items): """""""" """"""""Collections.s!uffle(list): """""""" """"""""setList&dapter(new"3rra+3dapter String)(BeaderKooter7emo.t-is> """""""""""""""""""""""""""android.6.la+o&t.simple/list/item/1> """""""""""""""""""""""""""list)): """"""? """"?): """" """"ret&rn(btn): ""? "" ""private"View"build'ooter()"4 """"<extView"txt#new"+e(tView(t-is): """" """"update'ooter(txt): """" """"ret&rn(txt): ""? "" ""private"void"update'ooter(final"<extView"txt)"4 """"long"r&ntime#(S+stemCloc..uptime%illis()'start<ime)/1%%%: """" """"txt.set+e(t(String.value$f(r&ntime)1$"seconds"since"activit+"la&nc-ed$): """" """"if"(NareWe7eadCet.get())"4 """"""-andler.post"elayed(new"Runnable()"4 """"""""p&blic"void"run()"4 """""""" """"""""""update'ooter(txt):"" """"""""? """"""?>"1%%%): """"? ""? ?

)ere, >e a a hea er View built via b&ildBeader(), returning a ;&tton that, >hen %li%ke , >ill shu$$le the %ontents o$ the list. We also a a $ooter View" built via b&ildKooter(), returning a <extView that sho>s ho> long the a%tivity has been running, up ate every se%on . 5he list itsel$ is the ever3 popular list o$ lorem ipsum >or s. When initially isplaye , the hea er is visible but the $ooter is not, be%ause the list is too long*

$6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

!igure -./ : ist(ie) )ith a header vie) sho)n

.$ you s%roll o>n>ar , the hea er >ill sli e o$$ the top, an eventually the $ooter >ill s%roll into vie>*

!igure -$/ : ist(ie) )ith a footer vie) sho)n

$Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

Control 7our Selection


5he sto%k An roi ". $or a sele%te *istView ro> is $airly simplisti%* it highlights the ro> in orange...an nothing more. Dou %an %ontrol the 7rawable use $or sele%tion via the android,listSelector an android,drawSelector2n<op attributes on the *istView element in your layout. )o>ever, even those simply apply some generi% look to the sele%te ro>. .t may be you >ant to o something more elaborate $or a sele%te ro>, su%h as %hanging the ro> aroun to e;pose more in$ormation. Maybe you have thumbnail photos but only isplay the photo on the sele%te ro>. Gr perhaps you >ant to sho> some sort o$ se%on ary line o$ te;t, like a person7s instant messenger status, only on the sele%te ro>. Gr, there may be times you >ant a more subtle in i%ation o$ the sele%te item than having the >hole ro> sho> up in some neon %olor. 5he sto%k An roi ". $or highlighting a sele%tion >ill not o any o$ this $or you. 5hat Lust means you have to o it yoursel$. 5he goo ne>s is, it is not very i$$i%ult.

Create a %ni*ied Ro+ ,ie+


5he simplest >ay to a%%omplish this is $or ea%h ro> View to have all o$ the >i gets you >ant $or the sele%te 3ro> perspe%tive, but >ith the Ie;tra stu$$I $lagge as invisible at the outset. 5hat >ay, ro>s initially look InormalI >hen put into the list M all you nee to o is toggle the invisible >i gets to visible >hen a ro> gets sele%te an toggle them ba%k to invisible >hen a ro> is e3sele%te . (or e;ample, in the *istView/Selector proLe%t, you >ill $in layout representing a ro> in a list*
!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t ""xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,orientation#$-oriIontal$

a ro>.;ml

$%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

""android,la+o&t/widt-#$fill/parent$" ""android,la+o&t/-eig-t#$fill/parent$") "" View """"android,id#$01id/bar$ """"android,bac.gro&nd#$RKKKK%%%%$ """"android,la+o&t/widt-#$Hpx$" """"android,la+o&t/-eig-t#$fill/parent$ """"android,visibilit+#$invisible$ ""/) "" <extView """"android,id#$01id/label$ """"android,la+o&t/widt-#$fill/parent$" """"android,la+o&t/-eig-t#$fill/parent$ """"android,textSiIe#$1%pt$ """"android,padding<op#$Epx$ """"android,padding;ottom#$Epx$ """"android,padding*eft#$Hpx$ ""/) /*inear*a+o&t)

5here is a <extView representing the bulk o$ the ro>. /e$ore it, though, on the le$t, is a plain View name bar. 5he ba%kgroun o$ the View is set to re &android,bac.gro&nd"#"$RKKKK%%%%$' an the >i th to Hpx. More importantly, it is set to be invisible &android,visibilit+"#"$invisible$'. )en%e, >hen the ro> is put into a *istView, the re bar is not seen...until >e make the bar visible.

Con*i!ure the "ist- Get Control on (election


0e;t, >e nee to set up a *istView an arrange to be noti$ie >hen ro>s are sele%te an e3sele%te . 5hat is merely a matter o$ %alling set2nItemSelected*istener() $or the *istView, provi ing a listener to be noti$ie on a sele%tion %hange. Dou %an see that in the %onte;t o$ a *ist3ctivit+ in our Selector7emo %lass*
pac.age"com.commonsware.android.listview: import"android.app.*ist3ctivit+: import"android.content.Context: import"android.os.;&ndle: import"android.content.res.ColorState*ist: import"android.view.View: import"android.view.ViewGro&p: import"android.widget.3dapterView: import"android.widget.3rra+3dapter: import"android.widget.*istView:

$.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

import"android.widget.<extView: p&blic"class"Selector7emo"extends"*ist3ctivit+"4 ""private"static"ColorState*ist"allW-ite#ColorState*ist.value$f(%xKKKKKKKK): ""private"static"StringPQ"items#4$lorem$>"$ips&m$>"$dolor$> """""""""""""""""""""""""""""""""$sit$>"$amet$>"$consectet&er$> """""""""""""""""""""""""""""""""$adipiscing$>"$elit$>"$morbi$> """""""""""""""""""""""""""""""""$vel$>"$lig&la$>"$vitae$> """""""""""""""""""""""""""""""""$arc&$>"$ali@&et$>"$mollis$> """""""""""""""""""""""""""""""""$etiam$>"$vel$>"$erat$> """""""""""""""""""""""""""""""""$placerat$>"$ante$> """""""""""""""""""""""""""""""""$porttitor$>"$sodales$> """""""""""""""""""""""""""""""""$pellentes@&e$>"$a&g&e$> """""""""""""""""""""""""""""""""$p&r&s$?: "" ""02verride ""p&blic"void"onCreate(;&ndle"icicle)"4 """"s&per.onCreate(icicle): """"setContentView(6.la+o&t.main): """"setList&dapter(new"Selector&dapter(t-is)): """"getListView().set$nItemSelectedListener(listener): ""? "" ""class"Selector3dapter"extends"3rra+3dapter"4 """"Selector&dapter(Context"ctxt)"4 """"""s&per(ctxt>"6.la+o&t.row>"items): """"? """" """"02verride """"p&blic"View"getView(int"position>"View"convertView> """""""""""""""""""""""""ViewGro&p"parent)"4 """"""SelectorWrapper"wrapper#n&ll: """""" """"""if"(convertView##n&ll)"4 """"""""convertView#getLayoutInflater().inflate(6.la+o&t.row> """"""""""""""""""""""""""""""""""""""""""""""n&ll): """"""""wrapper#new"Selector,rapper(convertView): """"""""wrapper.getLabel().set+e(tColor(allW-ite): """"""""convertView.set+ag(wrapper): """"""? """"""else"4 """"""""wrapper#(SelectorWrapper)convertView.get+ag(): """"""? """""" """"""wrapper.getLabel().set+e(t(itemsPpositionQ): """""" """"""ret&rn(convertView): """"? ""? "" ""class"SelectorWrapper"4 """"View"row#n&ll: """"<extView"label#n&ll: """"View"bar#n&ll:

$$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

"""" """"Selector,rapper(View"row)"4 """"""t-is.row#row: """"? """" """"<extView"getLabel()"4 """"""if"(label##n&ll)"4 """"""""label#(<extView)row.findViewById(6.id.label): """"""? """""" """"""ret&rn(label): """"? """" """"View"getBar()"4 """"""if"(bar##n&ll)"4 """"""""bar#row.findViewById(6.id.bar): """"""? """""" """"""ret&rn(bar): """"? ""? "" ""3dapterView.2nItemSelected*istener"listener#new" 3dapterView.$nItemSelectedListener()"4 """"View"last6ow#n&ll: """" """"p&blic"void"onItemSelected(3dapterView !)"parent> """""""""""""""""""""""""""""View"view>"int"position> """""""""""""""""""""""""""""long"id)"4 """"""if"(last6owN#n&ll)"4 """"""""SelectorWrapper"wrapper#(SelectorWrapper)last6ow.get+ag(): """"""""wrapper.getBar().setVisibility(View.I=VISI;*8): """"""? """""" """"""SelectorWrapper"wrapper#(SelectorWrapper)view.get+ag(): """""" """"""wrapper.getBar().setVisibility(View.VISI;*8): """"""last6ow#view: """"? """" """"p&blic"void"on-ot!ingSelected(3dapterView !)"parent)"4 """"""if"(last6owN#n&ll)"4 """"""""SelectorWrapper"wrapper#(SelectorWrapper)last6ow.get+ag(): """"""""wrapper.getBar().setVisibility(View.I=VISI;*8): """"""""last6ow#n&ll: """"""? """"? ""?: ?

$0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

sets up a Selector3dapter, >hi%h $ollo> the vie>3>rapper pattern establishe in The Busy Coder's Guide to Android De elopment. Ba%h ro> is %reate $rom the layout sho>n earlier, >ith a SelectorWrapper" provi ing a%%ess to both the <extView &$or setting the te;t in a ro>' an the bar View.
Selector7emo

Chan!e the Ro+


Gur 3dapterView.2nItemSelected*istener instan%e keeps tra%k o$ the last sele%te ro> &last6ow'. When the sele%tion %hanges to another ro> in onItemSelected(), >e make the bar $rom the last sele%te ro> invisible, be$ore >e make the bar visible on the ne>ly3sele%te ro>. .n on=ot-ingSelected(), >e make the bar invisible an make our last sele%te ro> be null. 5he net e$$e%t is that as the sele%tion %hanges, >e toggle the bar o$$ an on as nee e to in i%ate >hi%h is the sele%te ro>. .n the layout $or the a%tivity7s *istView, >e turn o$$ the regular highlighting*
!xml"version#$1.%$"encoding#$&tf'($!) *istView ""xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,id#$0android,id/list$ ""android,la+o&t/widt-#$fill/parent$" ""android,la+o&t/-eig-t#$fill/parent$ ""android,listSelector#$R%%%%%%%%$ /)

5he result is >e are %ontrolling the highlight, in the $orm o$ the re bar*

$2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

8ore !un With ist(ie)s

!igure -0/ : ist(ie) )ith a custom"dra)n selector icon

Gbviously, >hat >e o to highlight a ro> %oul be mu%h more elaborate than >hat is emonstrate here. At the same time, it nee s to be $airly <ui%k to e;e%ute, lest the list appear to be too sluggish.

$3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER .

Sho) 1p :t =ome

Gne o$ the o$t3re<ueste $eatures a e in An roi -.A is the ability to a live elements to the home s%reen. Calle Iapp >i getsI, these %an be a e by users via a long3tap on the home s%reen an %hoosing an appropriate >i get $rom the available roster. An roi ships >ith a $e> app >i gets, su%h as a musi% player, but evelopers %an a their o>n M in this %hapter, >e >ill see ho> this is one. (or the purposes o$ this book, Iapp >i getsI >ill re$er to these items that go on the home s%reen. Gther uses o$ the term I>i getI >ill be reserve $or the ". >i gets, sub%lasses o$ View, usually $oun in the android.widget +ava pa%kage.

<ast is <ast* and West is West///


!art o$ the reason it took as long as it available is se%urity. i $or app >i gets to be%ome

An roi 7s se%urity mo el is base heavily on Linu; user, $ile, an pro%ess se%urity. Ba%h appli%ation is &normally' asso%iate >ith a uni<ue user .@. All o$ its $iles are o>ne by that user, an its pro%ess&es' run as that user. 5his prevents one appli%ation $rom mo i$ying the $iles o$ another or other>ise inLe%ting their o>n %o e into another running pro%ess.

$5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

.n parti%ular, the %ore An roi team >ante to $in a >ay that >oul allo> app >i gets to be isplaye by the home s%reen appli%ation, yet have their %ontent %ome $rom another appli%ation. .t >oul be angerous $or the home s%reen to run arbitrary %o e itsel$ or someho> allo> its ". to be ire%tly manipulate by another pro%ess. 5he app >i get ar%hite%ture, there$ore, is set up to keep the home s%reen appli%ation in epen ent $rom any %o e that puts app >i gets on that home s%reen, so bugs in one %annot harm the other.

The Big Picture for a Small :pp Widget


5he >ay An roi 6emoteViews. pulls o$$ this bit o$ se%urity is through the use o$

5he appli%ation %omponent that supplies the ". $or an app >i get is not an 3ctivit+, but rather a ;roadcast6eceiver &o$ten in tan em >ith a Service'. 5he ;roadcast6eceiver, in turn, oes not in$late a normal View hierar%hy, like an 3ctivit+ >oul , but instea in$lates a layout into a 6emoteViews" obLe%t. en%apsulates a limite e ition o$ normal >i gets, in su%h a $ashion that the 6emoteViews %an be IeasilyI transporte a%ross pro%ess boun aries. Dou %on$igure the 6emoteViews via your ;roadcast6eceiver an make those 6emoteViews available to An roi . An roi in turn elivers the 6emoteViews to the app >i get host &usually the home s%reen', >hi%h ren ers them to the s%reen itsel$.
6emoteViews

5his ar%hite%tural %hoi%e has many impa%ts* -. Dou o not have a%%ess to the $ull range o$ >i gets an %ontainers. Dou %an use Krame*a+o&t, *inear*a+o&t, an 6elative*a+o&t $or %ontainers, an 3nalogCloc., ;&tton, C-ronometer, Image;&tton, ImageView, 5rogress;ar, an <extView $or >i gets.

06
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

2. 5he only user input you %an get is %li%ks o$ the ;&tton an Image;&tton >i gets. .n parti%ular, there is no 8dit<ext $or te;t input. ?. /e%ause the app >i gets are ren ere in another pro%ess, you %annot simply register an 2nClic.*istener to get button %li%ksO rather, you tell 6emoteViews a 5endingIntent to invoke >hen a given button is %li%ke . =. Dou o not hol onto the 6emoteViews an reuse them yoursel$. Rather, the pattern appears to be that you %reate an sen out a bran 3ne> 6emoteViews >henever you >ant to %hange the %ontents o$ the app >i get. 5his, %ouple >ith having to transport the 6emoteViews a%ross pro%ess boun aries, means that up ating the app >i get is rather e;pensive in terms o$ C!" time, memory, an battery li$e. A. /e%ause %omponent han ling the up ates is a you have to be <ui%k &lest you take too long an An roi %onsi er you to have time out', you %annot use ba%kgroun threa s, an your %omponent itsel$ is lost on%e the re<uest has been %omplete . )en%e, i$ your up ate might take a >hile, you >ill probably >ant to have the ;roadcast6eceiver start a Service an have the Service o the long3running task an eventual app >i get up ate.
;roadcast6eceiver,

the

Crafting :pp Widgets


5his >ill be%ome some>hat easier to un erstan in the %onte;t o$ some sample %o e. .n the 3ppWidget/<witterWidget proLe%t, you >ill $in an app >i get that sho>s the latest t>eet in your 5>itter timeline. .$ you have rea Android !ro"rammin" Tutorials, you >ill re%ogniCe the +5>itter +AR >e >ill use $or a%%essing the 5>itter Web servi%e.

0Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

The /ani*est
(irst, >e nee to register our ;roadcast6eceiver &an , i$ relevant, Service' implementation in our 3ndroid9anifest.xml $ile, along >ith a $e> e;tra $eatures*
!xml"version#$1.%$"encoding#$&tf'($!) manifest"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ """"""pac.age#$com.commonsware.android.appwidget$ """"""android,versionCode#$1$ """"""android,version=ame#$1.%$) "" &ses'permission"android,name#$android.permission.I=<86=8<$"/) """" application"android,label#$0string/app/name$) """""""" activit+"android,name#$.<W5refs$ """"""""""""""""""android,label#$0string/app/name$) """""""""""" intent'filter) """""""""""""""" action"android,name#$android.intent.action.93I=$"/) """""""""""""""" categor+"android,name#$android.intent.categor+.*3D=CB86$"/) """""""""""" /intent'filter) """""""""""" intent'filter) """""""""""""""" action" android,name#$android.appwidget.action.355WI7G8</C2=KIGD68$"/) """""""""""" /intent'filter) """""" /activit+) """""""" receiver"android,name#$.<witterWidget$ """"""""""""android,label#$0string/app/name$ """"""""""""android,icon#$0drawable/tw/icon$) """""""""""" intent'filter) """""""""""""""" action """"""""""""""""""""android,name#$android.appwidget.action.355WI7G8</D573<8$"/) """""""""""" /intent'filter) """""""""""" meta'data """"""""""""""""android,name#$android.appwidget.provider$ """"""""""""""""android,reso&rce#$0xml/widget/provider$"/) """""""" /receiver) """""""" service"android,name#$.<witterWidgetSDpdateService$"/) """" /application) /manifest)

)ere >e have an activit+), a receiver), an a service). G$ note*

Gur receiver) has android,label an android,icon attributes, >hi%h are not normally nee e on ;roadcast6eceiver e%larations. )o>ever, in this %ase, those are use $or the entry that goes in the menu o$ available >i gets to a to the home s%reen. )en%e, you >ill probably >ant to supply values $or both o$ those, an use appropriate resour%es in %ase you >ant translations $or other languages.
0%

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

Gur

receiver) has an intent'filter) android.appwidget.action.355WI7G8</D573<8 a%tion. 5his

$or the means >e >ill get %ontrol >henever An roi >ants us to up ate the %ontent o$ our app >i get. 5here may be other a%tions >e >ant to monitor M more on this in a later se%tion. Gur receiver) also has a meta'data) element, in i%ating that its android.appwidget.provider etails %an be $oun in the res/xml/widget/provider.xml $ile. 5his meta ata is es%ribe in the ne;t se%tion. Gur activit+) has t>o intent'filter) elements, the normal Iput me in the Laun%herI one an one looking $or an a%tion o$ android.appwidget.action.355WI7G8</C2=KIGD68.

The /etadata
0e;t, >e nee to e$ine the app >i get provi er meta ata. 5his has to resi e at the lo%ation in i%ate in the mani$est M in this %ase, in res/xml/widget/provider.xml*
appwidget'provider"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,minWidt-#$ETEdip$ ""android,minBeig-t#$GEdip$ ""android,&pdate5eriod9illis#$T%%%%%$ ""android,config&re#$com.commonsware.android.appwidget.<W5refs$ /)

)ere, >e provi e $our pie%es o$ in$ormation*

5he minimum >i th an height o$ the app >i get &android,minWidt-" an android,minBeig-t'. 5hese are appro;imate M the app >i get host &e.g., home s%reen' >ill ten to %onvert these values into I%ellsI base upon the overall layout o$ the ". >here the app >i gets >ill resi e. )o>ever, they shoul be no smaller than the minimums %ite here. 5he $re<uen%y in >hi%h An roi shoul re<uest an up ate o$ the >i get7s %ontents &android,&pdate5eriod9illis'. 5his is e;presse in terms o$ millise%on s, so a value o$ T%%%%% is a -A3minute up ate %y%le.
0.

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

An a%tivity %lass that >ill be use to %on$igure the >i get >hen it is $irst a e to the s%reen &android,config&re'. 5his >ill be es%ribe in greater etail in a later se%tion.

5he %on$iguration a%tivity is optional. )o>ever, i$ you skip the %on$iguration a%tivity, you o nee to tell An roi the initial layout to use $or the app >i get, via an android,initial*a+o&t attribute.

The "ayout
Bventually, you are going to nee a layout that es%ribes >hat the app >i get looks like. #o long as you sti%k to the >i get an %ontainer %lasses note above, this layout %an other>ise look like any other layout in your proLe%t. (or e;ample, here is the layout $or the <witterWidget*
!xml"version#$1.%$"encoding#$&tf'($!) 6elative*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ """"android,orientation#$-oriIontal$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$fill/parent$ """"android,bac.gro&nd#$RKK%%%%(($ """") "" Image;&tton"android,id#$01id/refres-$ """"android,la+o&t/align5arent<op#$tr&e$ """"android,la+o&t/align5arent6ig-t#$tr&e$ """"android,src#$0drawable/refres-$ """"android,la+o&t/widt-#$wrap/content$ """"android,la+o&t/-eig-t#$wrap/content$ ""/) "" Image;&tton"android,id#$01id/config&re$ """"android,la+o&t/align5arent;ottom#$tr&e$ """"android,la+o&t/align5arent6ig-t#$tr&e$ """"android,src#$0drawable/config&re$ """"android,la+o&t/widt-#$wrap/content$ """"android,la+o&t/-eig-t#$wrap/content$ ""/) "" <extView"android,id#$01id/friend$ """"android,la+o&t/align5arent<op#$tr&e$ """"android,la+o&t/align5arent*eft#$tr&e$ """"android,la+o&t/to*eft2f#$0id/refres-$ """"android,la+o&t/widt-#$wrap/content$ """"android,la+o&t/-eig-t#$wrap/content$ """"android,gravit+#$left$

0$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

""""android,textSt+le#$bold$ """"android,single*ine#$tr&e$ """"android,ellipsiIe#$end$ ""/) "" <extView"android,id#$01id/stat&s$ """"android,la+o&t/below#$0id/friend$ """"android,la+o&t/align5arent*eft#$tr&e$ """"android,la+o&t/to*eft2f#$0id/refres-$ """"android,la+o&t/widt-#$wrap/content$ """"android,la+o&t/-eig-t#$fill/parent$ """"android,gravit+#$top$ """"android,single*ine#$false$ """"android,lines#$F$ ""/) /6elative*a+o&t)

All >e have is a <extView to sho> the latest t>eet, plus another one $or the person issuing the t>eet, an a pair o$ Image;&tton >i gets to allo> the user to manually re$resh the latest t>eet an laun%h the %on$iguration a%tivity.

The BroadcastReceiver
0e;t, >e nee a ;roadcast6eciever that %an get %ontrol >hen An roi >ants us to up ate our 6emoteViews $or our app >i get. 5o simpli$y this, An roi supplies an 3ppWidget5rovider %lass >e %an e;ten , instea o$ the normal ;roadcast6eceiver. 5his simply looks at the re%eive Intent an %alls out to an appropriate li$e%y%le metho base on the re<ueste a%tion. 5he one metho that invariably nee s to be implemente on the provi er is onDpdate(). Gther li$e%y%le metho s may be o$ interest an are is%usse later in this %hapter. (or e;ample, here is the onDpdate() $or <witterWidget* implementation o$ the

3ppWidget5rovider

02verride p&blic"void"onUpdate(Context"ctxt> """""""""""""""""""""3ppWidget9anager"mgr> """""""""""""""""""""intPQ"appWidgetIds)"4 ""ctxt.startService(new"Intent(ctxt>"DpdateService.class)): ?

00
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

.$ our 6emoteViews %oul be rapi ly %onstru%te , >e %oul o the >ork right here. )o>ever, in our %ase, >e nee to make a Web servi%e %all to 5>itter, >hi%h might take a >hile, so >e instea %all startService() on the Service" >e e%lare in our mani$est, to have it make the up ates.

The (ervice
5he real >ork $or <witterWidget is mostly one in an DpdateService inner %lass o$ <witterWidget.
DpdateService IntentService

oes not e;ten Service, but rather e;ten s IntentService. is esigne $or patterns like this one, >here our servi%e is starte multiple times, >ith ea%h IstartI representing a istin%t pie%e o$ >ork to be a%%omplishe &in this %ase, up ating an app >i get $rom 5>itter'. IntentService allo>s us to implement onBandleIntent() to o this >ork, an it arranges $or onBandleIntent() to be %alle on a ba%kgroun threa . )en%e, >e o not nee to eal >ith starting or stopping our threa , or even stopping our servi%e >hen there is no more >ork to be one M An roi han les that automati%ally. )ere is the onBandleIntent() implementation $rom DpdateService*
02verride p&blic"void"on*andleIntent(Intent"intent)"4 ""Component=ame"me#new"Component-ame(t-is> """""""""""""""""""""""""""""""""""<witterWidget.class): ""3ppWidget9anager"mgr#3ppWidget9anager.getInstance(t-is): ""mgr.update&pp,idget(me>"buildUpdate(t-is)): ?

5o up ate the 6emoteViews $or our app >i get, >e nee to buil those 6emoteViews & elegate to a b&ildDpdate() helper metho ' an tell an 3ppWidget9anager to up ate the >i get via &pdate3ppWidget(). .n this %ase, >e use a version o$ &pdate3ppWidget() that takes a Component=ame as the i enti$ier o$ the >i get to be up ate . 0ote that this means that >e >ill up ate all instan%es o$ this app >i get presently in use M the %on%ept o$ multiple app >i get instan%es is %overe in greater etail later in this %hapter.
02
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

Working >ith 6emoteViews is a bit like trying to tie your shoes >hile >earing mittens M it may be possible, but it is a bit %lumsy. .n this %ase, rather than using metho s like findView;+Id() an then %alling metho s on in ivi ual >i gets, >e nee to %all metho s on 6emoteViews itsel$, provi ing the i enti$ier o$ the >i get >e >ish to mo i$y. 5his is so our re<uests $or %hanges %an be serialiCe $or transport to the home s%reen pro%ess. .t oes, ho>ever, mean that our vie>3up ating %o e looks a $air bit i$$erent than it >oul i$ this >ere the main View o$ an a%tivity or ro> o$ a *istView. (or e;ample, here is the b&ildDpdate() metho $rom DpdateService, >hi%h buil s a 6emoteViews %ontaining the latest 5>itter in$ormation, using a%%ount in$ormation pulle $rom share pre$eren%es*
private"6emoteViews"buildUpdate(Context"context)"4 ""6emoteViews"&pdateViews#new"RemoteViews(context.get ac)age-ame()> """"""""""""""""""""""""""""""""""""""""6.la+o&t.widget): ""String"&ser#prefs.getString($&ser$>"n&ll): ""String"password#prefs.getString($password$>"n&ll): ""if"(&serN#n&ll"UU"passwordN#n&ll)"4 """"<witter"client#new"+witter(&ser>"password): """"*ist <witter.Stat&s)"timeline#client.get'riends+imeline(): """"if"(timeline.si.e())%)"4 """"""<witter.Stat&s"s#timeline.get(%): """"""&pdateViews.set+e(tView+e(t(6.id.friend> """""""""""""""""""""""""""""""""s.&ser.screen=ame): """"""&pdateViews.set+e(tView+e(t(6.id.stat&s> """""""""""""""""""""""""""""""""s.text): """"""Intent"i#new"Intent(t-is>"<witterWidget.class): """"""5endingIntent"pi#5endingIntent.getBroadcast(context> """"""""""""""""""""""""""""""""""""""""""""""""%"">"i> """"""""""""""""""""""""""""""""""""""""""""""""%): """"""&pdateViews.set$nClic) endingIntent(6.id.refres-> """"""""""""""""""""""""""""""""""""""""pi): """"""i#new"Intent(t-is>"<W5refs.class): """"""pi#5endingIntent.get&ctivity(context>"%"">"i>"%): """"""&pdateViews.set$nClic) endingIntent(6.id.config&re> """"""""""""""""""""""""""""""""""""""""pi): """"? ""? ""ret&rn(&pdateViews): ?

03
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

5o %reate the 6emoteViews, >e use a %onstru%tor that takes our pa%kage name an the i enti$ier o$ our layout. 5his gives us a 6emoteViews that %ontains all o$ the >i gets >e e%lare in that layout, Lust as i$ >e in$late the layout using a *a+o&tInflater. 5he i$$eren%e, o$ %ourse, is that >e have a 6emoteViews obLe%t, not a View, as the result. We then use metho s like*

to set the te;t on a <extView in the 6emoteViews, given the i enti$ier o$ the <extView >ithin the layout >e >ish to manipulate
set<extView<ext() set2nClic.5endingIntent() to provi e a 5endingIntent get $ire o$$ >hen a ;&tton or Image;&tton is %li%ke

that shoul

0ote, o$ %ourse, that An roi oes not kno> anything about 5>itter M the 5>itter obLe%t %omes $rom a +5>itter +AR lo%ate in the libs/ ire%tory o$ our proLe%t.

The Con*i!uration Activity


Way ba%k in the mani$est, >e in%lu e an activit+) element $or a <W5refs" a%tivity. An , in our >i get meta ata HML $ile, >e sai that <W5refs >as the android,config&re attribute value. .n our 6emoteViews $or the >i get itsel$, >e %onne%t a %on$igure button to laun%h <W5refs >hen %li%ke . 5he net o$ all o$ this is that <W5refs is the %on$iguration a%tivity. #pe%i$i%ally*

.t >ill be laun%he >hen >e re<uest to a s%reen

this >i get to our home

.t >ill be re3laun%he >henever >e %li%k the %on$igure button in the >i get itsel$

(or the latter s%enario, the a%tivity nee be nothing spe%ial. .n $a%t, <W5refs" is mostly Lust a 5reference3ctivit+, up ating the S-ared5references $or this appli%ation >ith the user7s 5>itter s%reen name an pass>or , use $or logging into 5>itter an $et%hing the latest timeline entry.

04
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

5he $ormer s%enario M e$ining a %on$iguration a%tivity in the meta ata M re<uires a bit more >ork, though. .$ >e >ere to leave this out, an not have an android,config&re attribute in the meta ata, on%e the user %hose to a our >i get to their home s%reen, the >i get >oul imme iately appear. /ehin the s%enes, An roi >oul ask our 3ppWidget5rovider to supply the 6emoteViews $or the >i get bo y right a>ay. )o>ever, >hen >e e%lare that >e >ant a %on$iguration a%tivity, >e must buil the initial 6emoteViews ourselves an return them as the a%tivity7s result. /ehin the s%enes, An roi uses start3ctivit+Kor6es&lt() to laun%h our %on$iguration a%tivity, then looks at the result an uses the asso%iate 6emoteViews to %reate the initial look o$ the >i get. 5his approa%h is prone to %o e upli%ation, an it is not %ompletely %lear >hy An roi ele%te to buil the >i get $rame>ork this >ay. 5hat being sai , here is the implementation o$ <W5refs*
pac.age"com.commonsware.android.appwidget: import"android.app.3ctivit+: import"android.appwidget.3ppWidget9anager: import"android.appwidget.3ppWidget5rovider: import"android.content.Component=ame: import"android.content.Intent: import"android.os.;&ndle: import"android.preference.5reference3ctivit+: import"android.view.Ve+8vent: import"android.widget.6emoteViews: p&blic"class"<W5refs"extends"5reference3ctivit+"4 ""private"static"String" C2=KIGD68/3C<I2=#$android.appwidget.action.355WI7G8</C2=KIGD68$: "" ""02verride ""p&blic"void"onCreate(;&ndle"savedInstanceState)"4 """"s&per.onCreate(savedInstanceState): """" """"add references'romResource(6.xml.preferences): ""? "" ""02verride

05
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

""p&blic"boolean"on#ey"own(int".e+Code>"Ve+8vent"event)"4 """"if"(.e+Code##Ve+8vent.V8CC278/;3CV)"4 """"""if"(C2=KIGD68/3C<I2=.equals(getIntent().get&ction()))"4 """"""""Intent"intent#getIntent(): """""""";&ndle"extras#intent.getE(tras(): "" """"""""if"(extrasN#n&ll)"4 """"""""""int"id#extras.getInt(3ppWidget9anager.8W<63/355WI7G8</I7>" """""""""""""""""""""""""""""""3ppWidget9anager.I=V3*I7/355WI7G8</I7): """"""""""3ppWidget9anager"mgr#3ppWidget9anager.getInstance(t-is): """"""""""6emoteViews"views#new"RemoteViews(get ac)age-ame()> """"""""""""""""""""""""""""""""""""""""""6.la+o&t.widget): "" """"""""""mgr.update&pp,idget(id>"views): "" """"""""""Intent"res&lt#new"Intent(): "" """"""""""res&lt.putE(tra(3ppWidget9anager.8W<63/355WI7G8</I7> """""""""""""""""""""""""""id): """"""""""setResult(68SD*</2V>"res&lt): """"""""""sendBroadcast(new"Intent(t-is> """""""""""""""""""""""""""""""""""<witterWidget.class)): """"""""? """"""? """"? """" """"ret&rn(s&per.on#ey"own(.e+Code>"event)): ""? ?

We are using the same a%tivity $or t>o %ases* $or the initial %on$iguration an $or later on3 eman re%on$iguration via the %on$igure button in the >i get. We nee to tell these apart. More importantly, >e nee to get %ontrol at an appropriate time to set our a%tivity result in the initial %on$iguration %ase. Alas, the normal a%tivity li$e%y%le metho s &e.g., on7estro+()' are too late, an 5reference3ctivit+ o$$ers no other e;pli%it hook to $in out >hen the user ismisses the pre$eren%e s%reen. #o, >e have to %heat a bit. #pe%i$i%ally, >e hook onVe+7own() an >at%h $or the ba%k button. When the ba%k button is presse , i$ >e >ere laun%he by a >i get %on$iguration Intent &C2=KIGD68/3C<I2=.e@&als(getIntent().get3ction())', then >e go through an *

26
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

8et our >i get instan%e i enti$ier & es%ribe in greater etail later in this %hapter' 8et our 3ppWidget9anager an %reate a ne> 6emoteViews in$late $rom our >i get layout !ass the empty
6emoteViews

to

the

3ppWidget9anager

via

&pdate3ppWidget()

Call set6es&lt() >ith an Intent >rapping our >i get instan%e i enti$ier, so An roi kno>s >e have properly %on$igure our >i get Raise a broa %ast Intent to ask our Widget5rovider to o the real initial version o$ the >i get

5his minimiCes %o e upli%ation, but it oes mean there is a slight hi%%up, >here the >i get initially appears blank, be$ore the $irst timeline entry appears. 5his is largely unavoi able in this %ase M >e %annot >ait $or 5>itter to respon sin%e onVe+7own() is %alle on the ". threa an >e nee to %all set6es&lt() no> rather than >ait $or 5>itter7s response. "n oubte ly, there are other patterns $or han ling this situation.

The Result
.$ you %ompile an install all o$ this, you >ill have a ne> >i get entry available >hen you long3tap on the home s%reen ba%kgroun *

2Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

!igure -2/ The roster of available )idgets

When you %hoose 5>itter Wi get, you >ill initially be presente >ith the %on$iguration a%tivity*

!igure -3/ The T)itterWidget configuration activity

2%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

Gn%e you set your 5>itter s%reen name an pass>or , an press the ba%k button to e;it the a%tivity, your >i get >ill appear >ith no %ontents*

!igure -4/ T)itterWidget* immediately after being added

A$ter a moment, though, it >ill appear >ith the latest in your 5>itter $rien s timeline*

2.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

!igure -5/ T)itterWidget* )ith a timeline entry

5o %hange your 5>itter %re entials, you %an either tap the %on$igure i%on in the >i get or run the 5>itter Wi get appli%ation in your laun%her. An , %li%king the re$resh button, or >aiting -A minutes, >ill %ause the >i get to up ate its %ontents.

:nother and :nother


As in i%ate above, you %an have multiple instan%es o$ the same app >i get outstan ing at any one time. (or e;ample, one might have multiple pi%ture $rames, or multiple Isho>3me3the3latest3R##3entryI app >i gets, one per $ee . Dou >ill istinguish bet>een these in your %o e via the i enti$ier supplie in the relevant 3ppWidget5rovider %allba%ks &e.g., onDpdate()'. .$ you >ant to support separate app >i get instan%es, you >ill nee to store your state on a per3app3>i get3i enti$ier basis. (or e;ample, >hile <witterWidget uses pre$eren%es $or the 5>itter a%%ount etails, you might nee multiple pre$eren%e $iles, or use a #FLite atabase >ith an app >i get i enti$ier %olumn, or something to istinguish one app >i get instan%e $rom another. Dou >ill also nee to use an appropriate version o$
2$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

&pdate3ppWidget()

on 3ppWidget9anager >hen you up ate the app >i gets, one that takes app >i get i enti$iers as the $irst parameter, so you up ate the proper app >i get instan%es. Conversely, there is nothing re<uiring you to support multiple instan%es as in epen ent entities. (or e;ample, i$ you a more than one <witterWidget" to your home s%reen, nothing blo>s up M they Lust sho> the same t>eet. .n the %ase o$ <witterWidget, they might not even sho> the same t>eet all the time, sin%e they >ill up ate on in epen ent %y%les, so one >ill get ne>er t>eets be$ore another.

:pp Widgets> Their ife and Times


5>itterWi get overro e t>o 3ppWidget5rovider metho s*

elapse

onDpdate(),

invoke >hen the android,&pdate5eriod9illis time has

on6eceive(),

the stan ar ;roadcast6eceiver %allba%k, use to ete%t >hen >e are invoke >ith no a%tion, meaning >e >ant to $or%e an up ate ue to the re$resh button being %li%ke

5here are three other li$e%y%le metho s that 3ppWidget5rovider o$$ers that you may be intereste in*

>ill be %alle >hen the $irst >i get instan%e is %reate $or this parti%ular >i get provi er, so i$ there is anything you nee to o on%e $or all supporte >i gets, you %an implement that logi% here
on8nabled()

>ill be %alle >hen a >i get instan%e is remove $rom the home s%reen, in %ase there is any ata you nee to %lean up spe%i$i% to that instan%e
on7eleted()

>ill be %alle >hen the last >i get instan%e $or this provi er is remove $rom the home s%reen, so you %an %lean up anything relate to all su%h >i gets
on7isabled()

20
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

0ote, ho>ever, that there is a bug in An roi -.Ar2, >here on7eleted() >ill not be properly %alle . Dou >ill nee to implement on6eceive() an >at%h $or the 3C<I2=/355WI7G8</78*8<87 a%tion in the re%eive Intent an %all on7eleted() yoursel$. 5his shoul be $i;e in a $uture e ition o$ An roi .

Controlling 7our #:pp Widget?s& 9estiny


As <witterWidget illustrates, you are not limite to up ating your app >i get only base on the timetable spe%i$ie in your meta ata. 5hat timetable is use$ul i$ you %an get by >ith a $i;e s%he ule. )o>ever, there are %ases in >hi%h that >ill not >ork very >ell*

.$ you >ant the user to be able to %on$igure the polling perio &the meta ata is bake into your A!K an there$ore %annot be mo i$ie at runtime' .$ you >ant the app >i get to be up ate base on e;ternal $a%tors, su%h as a %hange in lo%ation

5he re%ipe sho>n in <witterWidget >ill let you use 3larm9anager & es%ribe in a later %hapter' or pro;imity alerts or >hatever to trigger up ates. All you nee to o is*

Arrange $or something to broa %ast an Intent that >ill be pi%ke up by the ;roadcast6eceiver you are using $or your app >i get provi er )ave the provi er pro%ess that Intent ire%tly or pass it along to a Service &su%h as an IntentService as sho>n in <witterWidget'

Being a 'ood =ost


.n a ition to %reating your o>n app >i gets, it is possible to host app >i gets. 5his is mostly aime $or those %reating alternative home s%reen appli%ations, so they %an take a vantage o$ the same app >i get $rame>ork an all the app >i gets being built $or it. 5his is not very >ell o%umente at this Lun%ture, but it apparently involves the 3ppWidgetBost an 3ppWidgetBostView %lasses. 5he latter is a View an so
22
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sho) 1p :t =ome

shoul be able to resi e in an app >i get host7s ". like any other or inary >i get.

23
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

PART II Advanced Media

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 0

Creating 9ra)ables

7rawable resour%es %ome in all shapes an siCes, an not Lust in terms o$ pi;el imensions. While many 7rawable resour%es >ill be !08 or +!B8 $iles, you %an easily %reate other resour%es that supply other sorts o$ 7rawable" obLe%ts to your appli%ation. .n this %hapter, >e >ill e;amine a $e> o$ these that may prove use$ul as you try to make your appli%ation look its best.

Traversing :long a 'radient


8ra ients have long been use to a Isomething a little e;traI to a user inter$a%e, >hether it is Mi%roso$t a ing them to G$$i%e7s title bars in the late -9907s or the seemingly en less number o$ gra ient buttons a orning IWeb 2.0I sites. An no>, you %an have gra ients in your An roi appli%ations as >ell. 5he easiest >ay to %reate a gra ient is to use an HML $ile to es%ribe the gra ient. /y pla%ing the $ile in res/drawable/, it %an be re$eren%e as a 7rawable resour%e, no i$$erent than any other su%h resour%e, like a !08 $ile. (or e;ample, here is a gra ient 7rawable resour%e, active/row.xml, $rom the 7rawable/Gradient sample proLe%t*

3Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

s-ape"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$" android,s-ape#$rectangle$) "" gradient """"android,startColor#$RFFKK%%%%$ """"android,endColor#$RKKKK%%%%$ """"android,angle#$EG%$ ""/) "" padding """"android,top#$Epx$ """"android,bottom#$Epx$ ""/) "" corners"android,radi&s#$Xpx$"/) /s-ape)

A gra ient is applie to the more general3purpose s-ape) element, in this %ase, a re%tangle. 5he gra ient is e$ine as having a start an en %olor M in this %ase, the gra ient is an in%reasing amount o$ re , >ith only the alpha %hannel varying to %ontrol ho> mu%h the ba%kgroun blen s in. 5he %olor is applie in a ire%tion etermine by the number o$ egrees spe%i$ie by the android,angle attribute, >ith EG% representing I o>nI &start %olor at the top, en %olor at the bottom'. As >ith any other HML3 e$ine shape, you %an %ontrol various aspe%ts o$ the >ay the shape is ra>n. .n this %ase, >e put some pa ing aroun the ra>able an roun o$$ the %orners o$ the re%tangle. 5o
7rawable in +ava %o e, you %an 6.drawable.active/row. Gne possible use o$ a gra ient is ro> sele%tion, as sho>n in 7rawable/Gradient7emo*
pac.age"com.commonsware.android.drawable: import"android.app.*ist3ctivit+: import"android.content.Context: import"android.os.;&ndle: import"android.content.res.ColorState*ist: import"android.view.View: import"android.view.ViewGro&p: import"android.widget.3dapterView: import"android.widget.3rra+3dapter: import"android.widget.*istView: import"android.widget.<extView: p&blic"class"Gradient7emo"extends"*ist3ctivit+"4 ""private"static"ColorState*ist"allW-ite#ColorState*ist.value$f(%xKKKKKKKK): ""private"static"StringPQ"items#4$lorem$>"$ips&m$>"$dolor$>

use

this

re$eren%e it as in %ustom *istView"

3%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

"""""""""""""""""""""""""""""""""$sit$>"$amet$>"$consectet&er$> """""""""""""""""""""""""""""""""$adipiscing$>"$elit$>"$morbi$> """""""""""""""""""""""""""""""""$vel$>"$lig&la$>"$vitae$> """""""""""""""""""""""""""""""""$arc&$>"$ali@&et$>"$mollis$> """""""""""""""""""""""""""""""""$etiam$>"$vel$>"$erat$> """""""""""""""""""""""""""""""""$placerat$>"$ante$> """""""""""""""""""""""""""""""""$porttitor$>"$sodales$> """""""""""""""""""""""""""""""""$pellentes@&e$>"$a&g&e$> """""""""""""""""""""""""""""""""$p&r&s$?: "" ""02verride ""p&blic"void"onCreate(;&ndle"icicle)"4 """"s&per.onCreate(icicle): """"setContentView(6.la+o&t.main): """"setList&dapter(new"/radient&dapter(t-is)): """"getListView().set$nItemSelectedListener(listener): ""? "" ""class"Gradient3dapter"extends"3rra+3dapter"4 """"/radient&dapter(Context"ctxt)"4 """"""s&per(ctxt>"6.la+o&t.row>"items): """"? """" """"02verride """"p&blic"View"getView(int"position>"View"convertView> """""""""""""""""""""""""ViewGro&p"parent)"4 """"""GradientWrapper"wrapper#n&ll: """""" """"""if"(convertView##n&ll)"4 """"""""convertView#getLayoutInflater().inflate(6.la+o&t.row> """"""""""""""""""""""""""""""""""""""""""""""n&ll): """"""""wrapper#new"/radient,rapper(convertView): """"""""convertView.set+ag(wrapper): """"""? """"""else"4 """"""""wrapper#(GradientWrapper)convertView.get+ag(): """"""? """""" """"""wrapper.getLabel().set+e(t(itemsPpositionQ): """""" """"""ret&rn(convertView): """"? ""? "" ""class"GradientWrapper"4 """"View"row#n&ll: """"<extView"label#n&ll: """" """"/radient,rapper(View"row)"4 """"""t-is.row#row: """"? """" """"<extView"getLabel()"4 """"""if"(label##n&ll)"4

3.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

""""""""label#(<extView)row.findViewById(6.id.label): """"""? """""" """"""ret&rn(label): """"? ""? "" ""3dapterView.2nItemSelected*istener"listener#new" 3dapterView.$nItemSelectedListener()"4 """"View"last6ow#n&ll: """" """"p&blic"void"onItemSelected(3dapterView !)"parent> """""""""""""""""""""""""""""View"view>"int"position> """""""""""""""""""""""""""""long"id)"4 """"""if"(last6owN#n&ll)"4 """"""""last6ow.setBac)groundColor(%x%%%%%%%%): """"""? """""" """"""view.setBac)groundResource(6.drawable.active/row): """"""last6ow#view: """"? """" """"p&blic"void"on-ot!ingSelected(3dapterView !)"parent)"4 """"""if"(last6owN#n&ll)"4 """"""""last6ow.setBac)groundColor(%x%%%%%%%%): """"""""last6ow#n&ll: """"""? """"? ""?: ?

.n an earlier %hapter, >e sho>e ho> you %an get %ontrol an %ustomiCe ho> a sele%te ro> appears in a *istView. 5his time, >e apply the gra ient roun e re%tangle as the ba%kgroun o$ the ro>. We %oul have a%%omplishe this via appropriate %hoi%es $or android,listSelector an android,drawSelector2n<op as >ell. 5he result is a sele%tion bar implementing the gra ient*

3$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

!igure %6/ The 'radient9emo sample application

0ote that be%ause the list ba%kgroun is bla%k, the re is mi;e >ith bla%k on the top en o$ the gra ient. .$ the list ba%kgroun >ere >hite, the top en o$ the gra ient >oul be re mi;e >ith >hite, as etermine by the alpha %hannel spe%i$ie on the gra ient7s top %olor.

: Stitch +n Time Saves @ine


As you rea through the An roi o%umentation, you no oubt ran into re$eren%es to Inine3pat%hI or I93pat%hI an >on ere >hat An roi ha to o >ith <uilting. Rest assure , you >ill not nee to take up nee le>ork to be an e$$e%tive An roi eveloper. .$, ho>ever, you are looking to %reate ba%kgroun s $or resiCable >i gets, like a ;&tton, you >ill probably nee to >ork >ith nine3pat%h images. As the An roi o%umentation states, a nine3pat%h is Ia !08 image in >hi%h you e$ine stret%hable se%tions that An roi >ill resiCe to $it the obLe%t at isplay time to a%%ommo ate variable siCe se%tions, su%h as te;t stringsI. /y using a spe%ially3%reate !08 $ile, An roi %an avoi trying to
30
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

use ve%tor3base $ormats &e.g., #,8' an their asso%iate overhea >hen trying to %reate a ba%kgroun at runtime. Det, at the same time, An roi %an still resiCe the ba%kgroun to han le >hatever you >ant to put insi e o$ it, su%h as the te;t o$ a ;&tton. .n this se%tion, >e >ill %over some o$ the basi%s o$ nine3pat%h graphi%s, in%lu ing ho> to %ustomiCe an apply them to your o>n An roi layouts.

The 1ame and the Border


0ine3pat%h graphi%s are !08 $iles >hose names en in .T.png. 5his means they %an be e ite using normal graphi%s tools, but An roi kno>s to apply nine3pat%h rules to their use. What makes a nine3pat%h graphi% i$$erent than an or inary !08 is a one3 pi;el3>i e bor er surroun ing the image. When ra>n, An roi >ill remove that bor er, sho>ing only the stret%he ren ition o$ >hat lies insi e the bor er. 5he bor er is use as a %ontrol %hannel, provi ing instru%tions to An roi $or ho> to eal >ith stret%hing the image to $it its %ontents.

Paddin! and the Bo'


Along the right an bottom si es, you %an ra> one3pi;el3>i e bla%k lines to in i%ate the Ipa ing bo;I. An roi >ill stret%h the image su%h that the %ontents o$ the >i get >ill $it insi e that pa ing bo;. (or e;ample, suppose >e are using a nine3pat%h as the ba%kgroun o$ a ;&tton. When you set the te;t to appear in the button &e.g., I)ello, >orl :I', An roi >ill %ompute the siCe o$ that te;t, in terms o$ >i th an height in pi;els. 5hen, it >ill stret%h the nine3pat%h image su%h that the te;t >ill resi e insi e the pa ing bo;. What lies outsi e the pa ing bo; $orms the bor er o$ the button, typi%ally a roun e re%tangle o$ some $orm.

32
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

!igure %-/ The padding box* as sho)n by a set of control lines to the right and bottom of the stretchable image

(tretch 2ones
5o tell An roi >here on the image to a%tually o the stret%hing, ra> one3 pi;el3>i e bla%k lines on the top an le$t si es o$ the image. An roi >ill s%ale the graphi% only in those areas M areas outsi e the stret%h Cones are not stret%he . !erhaps the most %ommon pattern is the %enter3stret%h, >here the mi le portions o$ the image on both a;es are %onsi ere stret%hable, but the e ges are not*

33
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

!igure %%/ The stretch ;ones* as sho)n by a set of control lines to the right and bottom of the stretchable image

)ere, the stret%h Cones >ill be stret%he Lust enough $or the %ontents to $it in the pa ing bo;. 5he e ges o$ the graphi% are le$t unstret%he . #ome a

itional rules to bear in min * .$ you have multiple is%rete stret%h Cones along an a;is &e.g., t>o Cones separate by >hitespa%e', An roi >ill stret%h both o$ them but keep them in their %urrent proportions. #o, i$ the $irst Cone is t>i%e as >i e as the se%on Cone in the original graphi%, the $irst Cone >ill be t>i%e as >i e as the se%on Cone in the stret%he graphi%. .$ you leave out the %ontrol lines $or the pa ing bo;, it is assume that the pa ing bo; an the stret%h Cones are one an the same.

Toolin!
5o e;periment >ith nine3pat%h images, you may >ish to use the drawTpatc-" program, $oun in the tools/ ire%tory o$ your #@K installation*

34
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

!igure %./ The dra)5patch tool

While a regular graphi%s e itor >oul allo> you to ra> any %olor on any pi;el, drawTpatc- limits you to ra>ing or erasing pi;els in the %ontrol area. .$ you attempt to ra> insi e the main image area itsel$, you >ill be blo%ke *

35
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

!igure %$/ The dra)5patch tool* sho)ing blocked areas

Gn the right, you >ill see samples o$ the image in various stret%he siCes, so you %an see the impa%t as you %hange the stret%hable Cones an pa ing bo;. While this is %onvenient $or >orking >ith the nine3pat%h nature o$ the image, you >ill still nee some other graphi%s e itor to %reate or mo i$y the bo y o$ the image itsel$. (or e;ample, the image sho>n above, $rom the 7rawable/=ine5atc- proLe%t, is a mo i$ie version o$ a nine3pat%h graphi% $rom the #@K7s 3pi7emos, >here the 8.M! >as use to a the neon green stripe a%ross the bottom portion o$ the image.

%sin! 1ine3Patch $ma!es


0ine3pat%h images are most %ommonly use as ba%kgroun s, as illustrate by the $ollo>ing layout*
!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$

46
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

""android,orientation#$vertical$ ""android,la+o&t/widt-#$fill/parent$ ""android,la+o&t/-eig-t#$fill/parent$ "") "" <able*a+o&t """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$wrap/content$ """"android,stretc-Col&mns#$1$ "") """" <able6ow """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$wrap/content$ """") """""" <extView """"""""android,la+o&t/widt-#$wrap/content$ """"""""android,la+o&t/-eig-t#$wrap/content$ """"""""android,la+o&t/gravit+#$center/vertical$ """"""""android,text#$BoriIontal,$ """"""/) """""" See.;ar"android,id#$01id/-oriIontal$ """"""""android,la+o&t/widt-#$fill/parent$ """"""""android,la+o&t/-eig-t#$wrap/content$ """"""/) """" /<able6ow) """" <able6ow """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$wrap/content$ """") """""" <extView """"""""android,la+o&t/widt-#$wrap/content$ """"""""android,la+o&t/-eig-t#$wrap/content$ """"""""android,la+o&t/gravit+#$center/vertical$ """"""""android,text#$Vertical,$ """"""/) """""" See.;ar"android,id#$01id/vertical$ """"""""android,la+o&t/widt-#$fill/parent$ """"""""android,la+o&t/-eig-t#$wrap/content$ """"""/) """" /<able6ow) "" /<able*a+o&t) "" *inear*a+o&t """"android,orientation#$vertical$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$fill/parent$ """") """" ;&tton"android,id#$01id/resiIe$ """"""android,la+o&t/widt-#$F(px$ """"""android,la+o&t/-eig-t#$F(px$ """"""android,text#$BiN$ """"""android,bac.gro&nd#$0drawable/b&tton$ """"/) "" /*inear*a+o&t) /*inear*a+o&t)

4Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

)ere, >e have t>o See.;ar >i gets, labele $or the horiContal an verti%al a;es, plus a ;&tton set up >ith our nine3pat%h graphi% as its ba%kgroun &android,bac.gro&nd"#"$0drawable/b&tton$'. 5he =ine5atc-7emo a%tivity then uses the t>o See.;ar >i gets to let the user %ontrol ho> large the button shoul be ra>n on3s%reen, starting $rom an initial siCe o$ F(px s<uare*
pac.age"com.commonsware.android.drawable: import"android.app.3ctivit+: import"android.os.;&ndle: import"android.view.View: import"android.view.ViewGro&p: import"android.widget.*inear*a+o&t: import"android.widget.See.;ar: p&blic"class"=ine5atc-7emo"extends"3ctivit+"4 ""See.;ar"-oriIontal#n&ll: ""See.;ar"vertical#n&ll: ""View"t-ing<o6esiIe#n&ll: "" ""02verride ""p&blic"void"onCreate(;&ndle"savedInstanceState)"4 """"s&per.onCreate(savedInstanceState): """"setContentView(6.la+o&t.main): """" """"t-ing<o6esiIe#findViewById(6.id.resiIe): "" """"-oriIontal#(See.;ar)findViewById(6.id.-oriIontal):"" """"vertical#(See.;ar)findViewById(6.id.vertical): """" """"-oriIontal.set%a((EGE):""//"JE%"less"F("starting"siIe """"vertical.set%a((EGE):""""//".eep"it"s@&are"0"max """" """"-oriIontal.set$nSee)BarC!angeListener(-): """"vertical.set$nSee)BarC!angeListener(v): ""? "" ""See.;ar.2nSee.;arC-ange*istener"-#new"See.;ar.$nSee)BarC!angeListener()"4 """"p&blic"void"on rogressC!anged(See.;ar"see.;ar> """""""""""""""""""""""""""""""""int"progress> """""""""""""""""""""""""""""""""boolean"from<o&c-)"4 """"""ViewGro&p.*a+o&t5arams"old#t-ing<o6esiIe.getLayout arams(): """"""ViewGro&p.*a+o&t5arams"c&rrent#new"*inear*a+o&t.Layout arams(F(1progress> """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""old.-eig-t): """""" """"""t-ing<o6esiIe.setLayout arams(c&rrent): """"? """" """"p&blic"void"onStart+rac)ing+ouc!(See.;ar"see.;ar)"4 4%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

""""""//"&n&sed """"? """" """"p&blic"void"onStop+rac)ing+ouc!(See.;ar"see.;ar)"4 """"""//"&n&sed """"? ""?: "" ""See.;ar.2nSee.;arC-ange*istener"v#new"See.;ar.$nSee)BarC!angeListener()"4 """"p&blic"void"on rogressC!anged(See.;ar"see.;ar> """""""""""""""""""""""""""""""""int"progress> """""""""""""""""""""""""""""""""boolean"from<o&c-)"4 """"""ViewGro&p.*a+o&t5arams"old#t-ing<o6esiIe.getLayout arams(): """"""ViewGro&p.*a+o&t5arams"c&rrent#new"*inear*a+o&t.Layout arams(old.widt-> """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""F(1progress): """""" """"""t-ing<o6esiIe.setLayout arams(c&rrent): """"? """" """"p&blic"void"onStart+rac)ing+ouc!(See.;ar"see.;ar)"4 """"""//"&n&sed """"? """" """"p&blic"void"onStop+rac)ing+ouc!(See.;ar"see.;ar)"4 """"""//"&n&sed """"? ""?: ?

5he result is an appli%ation that %an be use mu%h like the right pane o$ drawTpatc-, to see ho> the nine3pat%h graphi% looks on an a%tual evi%e or emulator in various siCes*

4.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

!igure %0/ The @inePatch sample proAect* in its initial state

!igure %2/ The @inePatch sample proAect* after making it bigger hori;ontally

4$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Creating 9ra)ables

!igure %3/ The @inePatch sample application* after making it bigger in both dimensions

40
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 4

:nimating Widgets

An roi is $ull o$ things that move. Dou %an s>ipe le$t an right on the home s%reen to vie> other panels o$ the esktop. Dou %an rag i%ons aroun on the home s%reen. Dou %an rag o>n the noti$i%ations area or rag up the appli%ations ra>er. An that is Lust on one s%reen: G$ %ourse, it >oul be ni%e to employ su%h animations in your o>n appli%ation. While this %hapter >ill not %over $ull3$le ge rag3an 3 rop, >e >ill %over some o$ the basi% animations an ho> to apply them to your e;isting >i gets.

+t?s @ot Bust !or Toons :nymore


An roi has a pa%kage o$ %lasses &android.view.animation' animating the movement an behavior o$ >i gets. e i%ate to

5hey %enter aroun an 3nimation base %lass that es%ribes >hat is to be one. /uilt3in animations e;ist to move a >i get &<ranslate3nimation', %hange the transparen%y o$ a >i get &3lp-a3nimation', revolving a >i get &6otate3nimation', an resiCing a >i get &Scale3nimation'. 5here is even a >ay to aggregate animations together into a %omposite 3nimation %alle an 3nimationSet. Later se%tions in this %hapter >ill e;amine the use o$ several o$ these animations. 8iven that you have an animation, to apply it, you have t>o main options*
43
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

:nimating Widgets

Dou may be using a %ontainer that supports animating its %ontents, su%h as a ViewKlipper or <extSwitc-er. 5hese are typi%ally sub%lasses o$ View3nimator an let you e$ine the IinI an IoutI animations to apply. (or e;ample, >ith a ViewKlipper, you %an spe%i$y ho> it $lips bet>een Views in terms o$ >hat animation is use to animate IoutI the %urrently3visible View an >hat animation is use to animate IinI the repla%ement View. B;amples o$ this sort o$ animation %an be $oun in The Busy Coder's Guide to Android De elopment. Dou %an simply tell any View to start3nimation(), given the 3nimation" to apply to itsel$. 5his is the te%hni<ue >e >ill be seeing use in the e;amples in this %hapter.

: Cuirky Translation
Animation takes some getting use to. (re<uently, it takes a $air bit o$ e;perimentation to get it all >orking as you >ish. 5his is parti%ularly true o$ <ranslate3nimation, as not everything about it is intuitive, even to authors o$ An roi books.

/echanics o* Translation
5he simple %onstru%tor $or <ranslate3nimation takes $our parameters es%ribing ho> the >i get shoul move* the be$ore an a$ter H o$$sets $rom the %urrent position, an the be$ore an a$ter D o$$sets $rom the %urrent position. 5he An roi o%umentation re$ers to these as fromW7elta, toW7elta, fromC7elta, an toC7elta. .n An roi 7s pi;el3spa%e, an (W>C) %oor inate o$ (%>%) represents the upper3 le$t %orner o$ the s%reen. )en%e, i$ toW7elta is greater than fromW7elta, the >i get >ill move to the right, i$ toC7elta is greater than fromC7elta, the >i get >ill move o>n, an so on.

44
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

:nimating Widgets

$ma!inin! a (lidin! Panel


#ome An roi appli%ations employ a sli ing panel, one that is o$$3s%reen most o$ the time but %an be %alle up by the user &e.g., via a menu' >hen esire . When an%hore at the bottom o$ the s%reen, the e$$e%t is akin to the An roi menu system, >ith a %ontainer that sli es up $rom the bottom an sli es o>n an out >hen being remove . )o>ever, >hile menus are limite to menu %hoi%es, An roi 7s animation $rame>ork lets one %reate a sli ing panel %ontaining >hatever >i gets you might >ant. Gne >ay to implement su%h a panel is to have a %ontainer &e.g., a *inear*a+o&t' >hose %ontents are absent &G2=8' >hen the panel is %lose an is present &VISI;*8' >hen the ra>er is open. .$ >e simply toggle setVisibilit+() using the a$orementione values, though, the panel >oul >ink open an %lose imme iately, >ithout any sort o$ animation. #o, instea , >e >ant to*

Make the panel visible an animate it up $rom the bottom o$ the s%reen >hen >e open the panel Animate it o>n to the bottom o$ the s%reen an make the panel gone >hen >e %lose the panel

The A*termath
5his brings up a key point >ith respe%t to <ranslate3nimation* the animation temporarily moves the >i get, but i$ you >ant the >i get to stay >here it is >hen the animation is over, you have to han le that yoursel$. Gther>ise, the >i get >ill snap ba%k to its original position >hen the animation %ompletes. .n the %ase o$ the panel opening, >e han le that via the transition $rom G2=8" to VISI;*8. 5e%hni%ally speaking, the panel is al>ays IopenI, in that >e are not, in the en , %hanging its position. /ut >hen the bo y o$ the panel is G2=8, it takes up no spa%e on the s%reenO >hen >e make it VISI;*8, it takes up >hatever spa%e it is suppose to.

45
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

:nimating Widgets

Later in this %hapter, >e >ill %over ho> to use animation listeners to a%%omplish this en $or %losing the panel.

$ntroducin! (lidin!Panel
With all that sai , turn your attention to the 3nimation/Sliding5anel proLe%t an , in parti%ular, the Sliding5anel %lass. 5his %lass implements a layout that >orks as a panel, an%hore to the bottom o$ the s%reen. A toggle() metho %an be %alle by the a%tivity to hi e or sho> the panel. 5he panel itsel$ is a *inear*a+o&t, so you %an put >hatever %ontents you >ant in there. We use t>o $lavors o$ <ranslate3nimation, one $or opening the panel an one $or %losing it. )ere is the opening animation*
anim#new"+ranslate&nimation(%.%f>"%.%f> """""""""""""""""""""""""""getLayout arams().-eig-t> """""""""""""""""""""""""""%.%f):

Gur fromW7elta an toW7elta are both %, sin%e >e are not shi$ting the panel7s position along the horiContal a;is. Gur fromC7elta is the panel7s height a%%or ing to its layout parameters &representing ho> big >e >ant the panel to be', be%ause >e >ant the panel to start the animation at the bottom o$ the s%reenO our toC7elta is % be%ause >e >ant the panel to be at its InaturalI open position at the en o$ the animation. Conversely, here is the %losing animation*
anim#new"+ranslate&nimation(%.%f>"%.%f>"%.%f> """""""""""""""""""""""""""getLayout arams().-eig-t):

.t has the same basi% stru%ture, e;%ept the D values are reverse , sin%e >e >ant the panel to start open an animate to a %lose position.

56
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

:nimating Widgets

5he result is a %ontainer that %an be %lose *

!igure %4/ The SlidingPanel sample application* )ith the panel closed

...or open, in this %ase toggle via a menu %hoi%e in the Sliding5anel7emo" a%tivity*

5Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

:nimating Widgets

!igure %5/ The SlidingPanel sample application* )ith the panel open

%sin! the Animation


When setting up an animation, you also nee to in i%ate ho> long the animation shoul take. 5his is one by %alling set7&ration() on the animation, provi ing the esire length o$ time in millise%on s. When >e are rea y >ith the animation, >e simply %all start3nimation() on the Sliding5anel itsel$, %ausing it to move as spe%i$ie by the <ranslate3nimation instan%e.

!ading To Black/ ,r Some ,ther Color/


allo>s you to $a e a >i get in or out by making it less or more transparent. 5he greater the transparen%y, the more the >i get appears to be I$a ingI.
3lp-a3nimation

5%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

:nimating Widgets

Alpha 1um#ers
Dou may be use to alpha %hannels, >hen use in R3366GG;; %olor notation, or perhaps >hen >orking >ith alpha3%apable image $ormats like !08. #imilarly, 3lp-a3nimation allo>s you to %hange the alpha %hannel $or an entire >i get, $rom $ully3soli to $ully3transparent. .n An roi , a $loat value o$ 1.% in i%ates a $ully3soli >i get, >hile a value o$ %.% in i%ates a $ully3transparent >i get. ,alues in bet>een, o$ %ourse, represent various amounts o$ transparen%y. )en%e, it is %ommon $or an 3lp-a3nimation to either start at 1.% an smoothly %hange the alpha to %.% &a $a e' or vi%e versa.

Animations in 5/"
With <ranslate3nimation, >e sho>e ho> to %onstru%t the animation in +ava sour%e %o e. Gne %an also %reate animation resour%es, >hi%h e$ine the animations using HML. 5his is similar to the pro%ess $or e$ining layouts, albeit mu%h simpler. (or e;ample, there is a se%on animation proLe%t, 3nimation/Sliding5anel8x, >hi%h emonstrates a panel that $a es out as it is %lose . .n there, you >ill $in a res/anim/ ire%tory, >hi%h is >here animation resour%es shoul resi e. .n there, you >ill $in fade.xml*
!xml"version#$1.%$"encoding#$&tf'($!) alp-a"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,from3lp-a#$1.%$ ""android,to3lp-a#$%.%$"/)

5he name o$ the root element in i%ates the type o$ animation &in this %ase, alpha $or an 3lp-a3nimation'. 5he attributes spe%i$y the %hara%teristi%s o$ the animation, in this %ase a $a e $rom 1.% to %.% on the alpha %hannel. 5his HML is the same as %alling new"3lp-a3nimation(1.%f>%.%f) in +ava.
5.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

:nimating Widgets

%sin! 5/" Animations


5o make use o$ HML3 e$ine animations, you nee to in$late them, mu%h as you might in$late a View or 9en& resour%e. 5his is a%%omplishe by using the load3nimation() stati% metho on the 3nimationDtils %lass*
fade2&t#3nimationDtils.load&nimation(ctxt>"6.anim.fade):

)ere, >e are loa ing our $a e animation, given a Context. 5his is being put into an 3nimation variable, so >e neither kno> nor %are that this parti%ular HML that >e are loa ing e$ines an 3lp-a3nimation instea o$, say, a 6otate3nimation.

When +t?s :ll Said :nd 9one


#ometimes, you nee to take a%tion >hen an animation %ompletes. >e %lose the panel, >e >ant to use a <ranslation3nimation to sli e it o>n $rom the open position to %lose ...then keep it %lose . With the system use in Sliding5anel, keeping the panel %lose is a matter o$ %alling setVisibilit+() on the %ontents >ith G2=8. )o>ever, you %annot o that >hen the animation beginsO other>ise, the panel is gone by the time you try to animate its motion. .nstea , you nee to arrange to have it be gone >hen the animation en s. 5o o that, you use a animation listener. An animation listener is simply an instan%e o$ the 3nimation*istener" inter$a%e, provi e to an animation via set3nimation*istener(). 5he listener >ill be invoke >hen the starts, en s, or repeats &the latter %ourtesy o$ C+cleInterpolator, is%usse later in this %hapter'. Dou %an put logi% in the on3nimation8nd() %allba%k in the listener to take a%tion >hen the animation $inishes. (or e;ample, >hen

5$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

:nimating Widgets

(or e;ample, here is the 3nimation*istener $or Sliding5anel*


3nimation.3nimation*istener"collapse*istener#new"3nimation.&nimationListener()"4 ""p&blic"void"on&nimationEnd(3nimation"animation)"4 """"setVisibility(View.G2=8): ""? ""p&blic"void"on&nimationRepeat(3nimation"animation)"4 """"//"not"needed ""? ""p&blic"void"on&nimationStart(3nimation"animation)"4 """"//"not"needed ""? ?:

All >e o is set the Image;&tton7s image to be the up>ar 3pointing arro> an setting our %ontent7s visibility to be G2=8, thereby %losing the panel.

=it The :ccelerator


.n a ition to the 3nimation %lasses themselves, An roi also provi es a set o$ Interpolator %lasses. 5hese provi e instru%tions $or ho> an animation is suppose to behave uring its operating perio . (or e;ample, the 3ccelerateInterpolator in i%ates that, uring the uration o$ an animation, the rate o$ %hange o$ the animation shoul begin slo>ly an a%%elerate until the en . When applie to a <ranslate3nimation, $or e;ample, the sli ing movement >ill start out slo>ly an pi%k up spee until the movement is %omplete. 5here are several implementations o$ the .nterpolator inter$a%e besi es 3ccelerateInterpolator, in%lu ing*

spee in the mi

3ccelerate7ecelerateInterpolator,

>hi%h starts slo>ly, pi%ks up le, an slo>s o>n again at the en >hi%h starts <ui%kly an slo>s o>n

7ecelerateInterpolator,

to>ar s the en
*inearInterpolator,

the e$ault, >hi%h in i%ates the animation shoul pro%ee smoothly $rom start to $inish
50

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

:nimating Widgets

C+cleInterpolator,

>hi%h repeats an animation $or a number o$ %y%les, $ollo>ing the A%%elerate@e%elerate.nterpolator pattern &slo>, then $ast, then slo>'

5o apply an interpolator to an animation, simply %all setInterpolator() on the animation >ith the Interpolator instan%e, su%h as the $ollo>ing line $rom Sliding5anel*
anim.setInterpolator(new"&ccelerateInterpolator(1.%f)):

Dou

android,interpolator attribute

%an

also

spe%i$y

one o$ the sto%k interpolators in your animation HML $ile.

via

the

:nimate/ Set/ 8atch/


(or the 3nimation/Sliding5anel8x proLe%t, though, >e >ant the panel to sli e open, but also $a e >hen it sli es %lose . 5his implies t>o animations >orking at the same time &a $a e an a sli e'. An roi supports this via the 3nimationSet %lass. An 3nimationSet is itsel$ an 3nimation implementation. (ollo>ing the %omposite esign pattern, it simply %as%a es the maLor 3nimation events to ea%h o$ the animations in the set. 5o %reate a set, Lust %reate an 3nimationSet instan%e, a the animations, an %on$igure the set. (or e;ample, here is the logi% $rom the Sliding5anel" implementation in 3nimation/Sliding5anel8x*
p&blic"void"toggle()"4 ""<ranslate3nimation"anim#n&ll: ""3nimationSet"set#new"&nimationSet(tr&e): ""is2pen#Nis2pen: ""if"(is2pen)"4 """"setVisibility(View.VISI;*8): """"anim#new"+ranslate&nimation(%.%f>"%.%f> """""""""""""""""""""""""""""""getLayout arams().-eig-t> """""""""""""""""""""""""""""""%.%f): ""?

52
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

:nimating Widgets

""else"4 """"anim#new"+ranslate&nimation(%.%f>"%.%f>"%.%f> """""""""""""""""""""""""""""""getLayout arams().-eig-t): """"anim.set&nimationListener(collapse*istener): """"set.add&nimation(fade2&t): ""? ""set.add&nimation(anim): ""set.set"uration(speed): ""set.setInterpolator(new"&ccelerateInterpolator(1.%f)): ""start&nimation(set): ?

.$ the panel is to be opene , >e make the %ontents visible &so >e %an animate the motion up>ar s', an %reate a <ranslate3nimation $or the up>ar movement. .$ the panel is to be %lose , >e %reate a <ranslate3nimation $or the o>n>ar movement, but also a a pre3 e$ine 3lp-a3nimation &fade2&t' to an 3nimationSet. .n either %ase, >e a the <ranslate3nimation to the set, give the set a uration an interpolator, an run the animation.

53
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 6

Playing 8edia

!retty mu%h every phone %laiming to be a IsmartphoneI has the ability to at least play ba%k musi%, i$ not vi eo. Bven many more or inary phones are $ull3$le ge M!? players, in a ition to o$$ering ringtones an >hatnot. 0ot surprisingly, An roi has multime ia support $or you, as a eveloper, to buil your o>n games, me ia players, an so on. 5his %hapter is $o%use on au io an vi eo playba%kO other %hapters >ill ta%kle me ia input, in%lu ing the %amera an au io re%or ing.

'et 7our 8edia ,n


.n An roi , you have $ive i$$erent pla%es you %an pull me ia %lips $rom M one o$ these >ill hope$ully $it your nee s* -. Dou %an pa%kage me ia %lips as ra> resour%es &res/raw in your proLe%t', so they are bun le >ith your appli%ation. 5he bene$it is that you7re guarantee the %lips >ill be thereO the o>nsi e is that they %annot be repla%e >ithout upgra ing the appli%ation.

2. Dou %an pa%kage me ia %lips as assets &assets/ in your proLe%t' an re$eren%e them via file,///android/asset/ "RLs in a Dri. 5he bene$it over ra> resour%es is that this lo%ation >orks >ith A!.s that e;pe%t Dri parameters instea o$ resour%e .@s. 5he o>nsi e M

55
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Playing 8edia

assets are only repla%eable >hen the appli%ation is upgra e remains.

?. Dou %an store me ia in an appli%ation3lo%al ire%tory, su%h as %ontent you o>nloa o$$ the .nternet. Dour me ia may or may not be there, an your storage spa%e isn7t in$inite, but you %an repla%e the me ia as nee e . =. Dou %an store me ia M or re$eren%e me ia that the user has store hersel$ M that is on an #@ %ar . 5here is likely more storage spa%e on the %ar than there is on the evi%e, an you %an repla%e the me ia as nee e , but other appli%ations have a%%ess to the #@ %ar as >ell. A. Dou %an, in some %ases, stream me ia o$$ the .nternet, bypassing any lo%al storage, as >ith the #tream(urious appli%ation .nternet streaming is tri%ky, parti%ularly $or vi eo, an is >ell beyon the s%ope o$ this book. (or the 53Mobile 8-, the re%ommen e approa%h $or anything o$ signi$i%ant siCe is to put it on the #@ %ar , as there is very little on3boar $lash memory $or $ile storage.

8aking @oise
5he %ru; o$ playing ba%k au io %omes in the $orm o$ the 9edia5la+er %lass. With it, you %an $ee it an au io %lip, startQstopQpause playba%k, an get noti$ie on key events, su%h as >hen the %lip is rea y to be playe or is one playing. Dou have three >ays to set up a 9edia5la+er an tell it >hat au io %lip to play* -. .$ the %lip is a ra> resour%e, use 9edia5la+er.create() an provi e the resour%e .@ o$ the %lip
9edia5la+er.create()

2. .$ you have a Dri to the %lip, use the Dri3$lavore

version o$

?. .$ you have a string path to the %lip, Lust %reate a 9edia5la+er using the e$ault %onstru%tor, then %all set7ataSo&rce() >ith the path to the %lip
-66
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Playing 8edia

0e;t, you nee to %all prepare() or prepare3s+nc(). /oth >ill set up the %lip to be rea y to play, su%h as $et%hing the $irst $e> se%on s o$$ the $ile or stream. 5he prepare() metho is syn%hronousO as soon as it returns, the %lip is rea y to play. 5he prepare3s+nc() metho is asyn%hronous M more on ho> to use this version later. Gn%e the %lip is prepare , start() begins playba%k, pa&se() pauses playba%k &>ith start() pi%king up playba%k >here pa&se() pause ', an stop() en s playba%k. Gne %aveat* you %annot simply %all start() again on the 9edia5la+er on%e you have %alle stop() M >e7ll %over a >orkaroun a bit later in this se%tion. 5o see this in a%tion, take a look at the 9edia/3&dio sample proLe%t. 5he layout is pretty trivial, >ith three buttons an labels $or play, pause, an stop*
!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ """"android,orientation#$vertical$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$fill/parent$ """") "" *inear*a+o&t """"android,orientation#$-oriIontal$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$wrap/content$ """"android,padding#$Fpx$ "") """" Image;&tton"android,id#$01id/pla+$ """"""android,src#$0drawable/pla+$ """"""android,la+o&t/-eig-t#$wrap/content$ """"""android,la+o&t/widt-#$wrap/content$ """"""android,padding6ig-t#$Fpx$ """"""android,enabled#$false$ """"/) """" <extView """"""android,text#$5la+$ """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$fill/parent$ """"""android,gravit+#$center/vertical$ """"""android,la+o&t/gravit+#$center/vertical$ """"""android,text3ppearance#$!android,attr/text3ppearance*arge$ """"/) "" /*inear*a+o&t) "" *inear*a+o&t """"android,orientation#$-oriIontal$ """"android,la+o&t/widt-#$fill/parent$

-6Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Playing 8edia

""""android,la+o&t/-eig-t#$wrap/content$ """"android,padding#$Fpx$ "") """" Image;&tton"android,id#$01id/pa&se$ """"""android,src#$0drawable/pa&se$ """"""android,la+o&t/-eig-t#$wrap/content$ """"""android,la+o&t/widt-#$wrap/content$ """"""android,padding6ig-t#$Fpx$ """"/) """" <extView """"""android,text#$5a&se$ """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$fill/parent$ """"""android,gravit+#$center/vertical$ """"""android,la+o&t/gravit+#$center/vertical$ """"""android,text3ppearance#$!android,attr/text3ppearance*arge$ """"/) "" /*inear*a+o&t) "" *inear*a+o&t """"android,orientation#$-oriIontal$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$wrap/content$ """"android,padding#$Fpx$ "") """" Image;&tton"android,id#$01id/stop$ """"""android,src#$0drawable/stop$ """"""android,la+o&t/-eig-t#$wrap/content$ """"""android,la+o&t/widt-#$wrap/content$ """"""android,padding6ig-t#$Fpx$ """"/) """" <extView """"""android,text#$Stop$ """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$fill/parent$ """"""android,gravit+#$center/vertical$ """"""android,la+o&t/gravit+#$center/vertical$ """"""android,text3ppearance#$!android,attr/text3ppearance*arge$ """"/) "" /*inear*a+o&t) /*inear*a+o&t)

5he +ava, o$ %ourse, is >here things get interesting*


p&blic"class"3&dio7emo"extends"3ctivit+ ""implements"9edia5la+er.2nCompletion*istener"4 "" ""private"Image;&tton"pla+: ""private"Image;&tton"pa&se: ""private"Image;&tton"stop: ""private"9edia5la+er"mp: ""02verride ""p&blic"void"onCreate(;&ndle"icicle)"4

-6%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Playing 8edia

""""s&per.onCreate(icicle): """"setContentView(6.la+o&t.main): """" """"pla+#(Image;&tton)findViewById(6.id.pla+): """"pa&se#(Image;&tton)findViewById(6.id.pa&se): """"stop#(Image;&tton)findViewById(6.id.stop): """" """"pla+.set$nClic)Listener(new"View.$nClic)Listener()"4 """"""p&blic"void"onClic)(View"view)"4 """"""""play(): """"""? """"?): """" """"pa&se.set$nClic)Listener(new"View.$nClic)Listener()"4 """"""p&blic"void"onClic)(View"view)"4 """"""""pause(): """"""? """"?): """" """"stop.set$nClic)Listener(new"View.$nClic)Listener()"4 """"""p&blic"void"onClic)(View"view)"4 """"""""stop(): """"""? """"?): """" """"setup(): ""? "" ""02verride ""p&blic"void"on"estroy()"4 """"s&per.on"estroy(): """" """"if"(stop.isEnabled())"4 """"""stop(): """"? ""? "" ""p&blic"void"onCompletion(9edia5la+er"mp)"4 """"stop(): ""? "" ""private"void"play()"4 """"mp.start(): """" """"pla+.setEnabled(false): """"pa&se.setEnabled(tr&e): """"stop.setEnabled(tr&e): ""? "" ""private"void"stop()"4 """"mp.stop(): """"mp.release(): """"setup(): ""?

-6.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Playing 8edia

"" ""private"void"pause()"4 """"mp.pause(): """" """"pla+.setEnabled(tr&e): """"pa&se.setEnabled(false): """"stop.setEnabled(tr&e): ""? "" ""private"void"loadClip()"4 """"tr+"4 """"""mp#9edia5la+er.create(t-is>"6.raw.clip): """"""mp.set$nCompletionListener(t-is): """"? """"catc-"(<-rowable"t)"4 """"""goBlooey(t): """"? ""? "" ""private"void"setup()"4 """"loadClip(): """"pla+.setEnabled(tr&e): """"pa&se.setEnabled(false): """"stop.setEnabled(false): ""? "" ""private"void"goBlooey(<-rowable"t)"4 """"3lert7ialog.;&ilder"b&ilder#new"3lert7ialog.Builder(t-is): """" """"b&ilder """""".set+itle($8xceptionN$) """""".set%essage(t.toString()) """""".set ositiveButton($2V$>"n&ll) """""".s!ow(): ""? ?

.n onCreate(), >e >ire up the three buttons to appropriate %allba%ks, then %all set&p(). .n set&p(), >e %reate our 9edia5la+er, set to play a %lip >e pa%kage in the proLe%t as a ra> resour%e. We also %on$igure the a%tivity itsel$ as the %ompletion listener, so >e $in out >hen the %lip is over. 0ote that, sin%e >e use the stati% create() metho on 9edia5la+er, >e have alrea y impli%itly %alle prepare(), so >e o not nee to %all that separately ourselves. 5he buttons simply >ork the 9edia5la+er an toggle ea%h others7 states, via appropriately3name %allba%ks. #o, pla+() starts Me ia!layer playba%k, pa&se() pauses playba%k, an stop() stops playba%k an resets our

-6$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Playing 8edia

9edia5la+er

to play again. 5he stop() %allba%k is also use au io %lip %ompletes o$ its o>n a%%or .

$or >hen the

5o reset the Me ia!layer, the stop() %allba%k %alls release() on the e;isting 9edia5la+er &to release its resour%es', then %alls set&p() again, is%ar ing the use 9edia5la+er an starting a $resh one. 5he ". is nothing spe%ial, but >e are more intereste in the au io in this sample, any>ay*

!igure .6/ The :udio9emo sample application

8oving Pictures
,i eo %lips get their o>n >i get, the VideoView. !ut it in a layout, $ee it an M!= vi eo %lip, an you get playba%k: (or e;ample, take a look at this layout, $rom the 9edia/Video sample proLe%t*
!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$

-60
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Playing 8edia

""""android,orientation#$vertical$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$fill/parent$ """") "" VideoView" """"android,id#$01id/video$" """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$fill/parent$ """"/) /*inear*a+o&t)

5he layout is simply a $ull3s%reen vi eo player. Whether it >ill use the $ull s%reen >ill be epen ent on the vi eo %lip, its aspe%t ratio, an >hether you have the evi%e &or emulator' in portrait or lan s%ape mo e. Wiring up the +ava is almost as simple*
p&blic"class"Video7emo"extends"3ctivit+"4 ""private"VideoView"video: ""private"9ediaController"ctlr: "" ""02verride ""p&blic"void"onCreate(;&ndle"icicle)"4 """"s&per.onCreate(icicle): """"get,indow().set'ormat(5ixelKormat.<63=S*DC8=<): """"setContentView(6.la+o&t.main): "" """"Kile"clip#new"'ile($/sdcard/test.mpF$): """" """"if"(clip.e(ists())"4 """"""video#(VideoView)findViewById(6.id.video): """"""video.setVideo at!(clip.get&bsolute at!()): """""" """"""ctlr#new"%ediaController(t-is): """"""ctlr.set%edia layer(video): """"""video.set%ediaController(ctlr): """"""video.request'ocus(): """"? ""? ?

5he biggest tri%k >ith VideoView is getting a vi eo %lip onto the evi%e. While VideoView oes support some streaming vi eo, the re<uirements on the M!= $ile are $airly stringent. .$ you >ant to be able to play a >i er array o$ vi eo %lips, you nee to have them on the evi%e, pre$erably on an #@ %ar .

-62
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Playing 8edia

5he %ru e Video7emo %lass assumes there is an M!= $ile in /sdcard/test.mpF" on your emulator. 5o make this a reality* -. (in a %lip, su%h as Aaron Rosenberg7s Documentaries and #ou $rom @uke "niversity7s Center $or the #tu y o$ the !ubli% @omain7s Moving .mage Contest, >hi%h >as use in the %reation o$ this book

2. "se m.sdcard &in the An roi #@K7s tools ire%tory' to %reate a suitably3siCe #@ %ar image &e.g., m.sdcard 1E(9"sd.img' ?. "se the 'sdcard s>it%h >hen laun%hing the emulator, provi ing the path to your #@ %ar image, so the #@ %ar is Imounte I >hen the emulator starts =. "se the adb " p&s- %omman &or @@M# or the e<uivalent in your .@B' to %opy the M!= $ile into /sdcard/test.mpF Gn%e there, the +ava %o e sho>n above >ill give you a >orking vi eo player*

!igure .-/ The (ideo9emo sample application* sho)ing a Creative Commons" licensed video clip

5apping on the vi eo >ill pop up the playba%k %ontrols*

-63
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Playing 8edia

!igure .%/ The (ideo9emo sample application* )ith the media controls displayed

5he vi eo >ill s%ale base on spa%e, as sho>n in this rotate vie> o$ the emulator & Ctrl)' K1E)'*

!igure ../ The (ideo9emo sample application* in landscape mode* )ith the video clip scaled to fit

0ote that playba%k may be rather Lerky in the emulator, epen ing on the po>er o$ the !C that is hosting the emulator. (or e;ample, on a !entium3M

-64
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Playing 8edia

-.48)C !C, playba%k in the emulator is e;tremely Lerky, >hile playba%k on the 53Mobile 8- is very smooth.

-65
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 7

1sing the Camera

Most An roi evi%es >ill have a %amera, sin%e they are $airly %ommonpla%e on mobile evi%es these ays. Dou, as an An roi eveloper, %an take a vantage o$ the %amera, $or everything $rom snapping tourist photos to s%anning bar%o es. (or simple operations, the A!.s nee e to use the %amera are $airly straight3$or>ar , re<uiring a bit o$ boilerplate %o e plus your o>n uni<ue appli%ation logi%. What is a problem is using the %amera >ith the emulator. 5he emulator oes not emulate a %amera, nor is there a %onvenient >ay to preten there are pi%tures via @@M# or similar tools. (or the purposes o$ this %hapter, it is assume you have a%%ess to an a%tual An roi 3po>ere har >are evi%e an %an use it $or evelopment purposes.

Sneaking a Peek
(irst, it is $airly %ommon $or a %amera3using appli%ation to support a previe> mo e, to sho> the user >hat the %amera sees. 5his >ill help make sure the %amera is line up on the subLe%t properly, >hether there is su$$i%ient lighting, et%. #o, let us take a look at ho> to %reate an appli%ation that sho>s su%h a live previe>. 5he %o e snippets sho>n in this se%tion are pulle $rom the Camera/5review sample proLe%t.

--Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing the Camera

The Permission
(irst, you nee permission to use the %amera. 5hat >ay, >hen en users install your appli%ation o$$ o$ the .nternet, they >ill be noti$ie that you inten to use the %amera, so they %an etermine i$ they eem that appropriate $or your appli%ation. Dou simply nee the C39863 permission in your 3ndroid9anifest.xml $ile, along >ith >hatever other permissions your appli%ation logi% might re<uire. )ere is the mani$est $rom the Camera/5review sample proLe%t*
!xml"version#$1.%$"encoding#$&tf'($!) manifest"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ """"""pac.age#$com.commonsware.android.camera$ """"""android,versionCode#$1$ """"""android,version=ame#$1.%$) "" &ses'permission"android,name#$android.permission.C39863$"/) """" application"android,label#$0string/app/name$) """""""" activit+"android,name#$.5review7emo$ """"""""""""""""""android,label#$0string/app/name$ """"""""""""""""""android,configC-anges#$.e+boardBiddenYorientation$ """"""""""""""""""android,screen2rientation#$landscape$ """"""""""""""""""android,t-eme#$0android,st+le/<-eme.=o<itle;ar.K&llscreen$) """""""""""" intent'filter) """""""""""""""" action"android,name#$android.intent.action.93I=$"/) """""""""""""""" categor+"android,name#$android.intent.categor+.*3D=CB86$"/) """""""""""" /intent'filter) """""""" /activit+) """" /application) /manifest)

Also note a $e> other things about our 5review7emo a%tivity as registere in this mani$est*

We use android,configC-anges " # " $.e+boardBiddenYorientation$ to ensure >e %ontrol >hat happens >hen the keyboar is hi en or e;pose , rather than have An roi rotate the s%reen $or us We use android,screen2rientation"#"$landscape$ to tell An roi >e are al>ays in lan s%ape mo e. 5his is ne%essary be%ause o$ a bit o$ a bug in the %amera previe> logi%, su%h that it >orks best in lan s%ape mo e.

--%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing the Camera

We use android,t-eme " # " $0android,st+le/K&llscreen$ to get ri o$ the title bar an status bar, so the previe> is truly $ull3s%reen &e.g., =20;?20 on a 53Mobile 8-'.

The (ur*ace,ie+
0e;t, you nee a layout supporting a S&rfaceView. S&rfaceView is use as a ra> %anvas $or isplaying all sorts o$ graphi%s outsi e o$ the realm o$ your or inary >i gets. .n this %ase, An roi kno>s ho> to isplay a live look at >hat the %amera sees on a S&rfaceView, to serve as a previe> pane. (or e;ample, here is a $ull3s%reen S&rfaceView layout as use 5review7emo a%tivity*
!xml"version#$1.%$"encoding#$&tf'($!) android.view.S&rfaceView" xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ """"android,id#$01id/preview$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$fill/parent$ """") /android.view.S&rfaceView)

by the

The Camera
5he biggest step, o$ %ourse, is telling An roi to use the %amera servi%e an tie a %amera to the S&rfaceView to sho> the a%tual previe>. We >ill also eventually nee the %amera servi%e to take real pi%tures, as >ill be es%ribe in the ne;t se%tion. 5here are three maLor %omponents to getting pi%ture previe> >orking* -. 5he S&rfaceView, as e$ine in our layout

2. A S&rfaceBolder, >hi%h is a means o$ %ontrolling behavior o$ the S&rfaceView, su%h as its siCe, or being noti$ie >hen the sur$a%e %hanges, su%h as >hen the previe> is starte ?. A Camera, obtaine $rom the open() stati% metho on the Camera %lass

--.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing the Camera

5o >ire these together, >e $irst nee to*


8et the S&rfaceBolder $or our S&rfaceView via getBolder() Register a S&rfaceBolder.Callbac. >ith the S&rfaceBolder, so >e are noti$ie >hen the S&rfaceView is rea y or %hanges 5ell the S&rfaceView &via the S&rfaceBolder' that it has the SD6K3C8/<C58/5DSB/;DKK86S type &set<+pe()' M this in i%ates something in the system >ill be up ating the S&rfaceView an provi ing the bitmap ata to isplay

5his gives us a %on$igure S&rfaceView &sho>n belo>', but >e still nee to tie in the Camera.
02verride p&blic"void"onCreate(;&ndle"savedInstanceState)"4 ""s&per.onCreate(savedInstanceState): ""setContentView(6.la+o&t.main): ""preview#(S&rfaceView)findViewById(6.id.preview): ""previewBolder#preview.get*older(): ""previewBolder.addCallbac)(s&rfaceCallbac.): ""previewBolder.set+ype(S&rfaceBolder.SD6K3C8/<C58/5DSB/;DKK86S): ?

A Camera obLe%t has a set5review7ispla+() metho that takes a S&rfaceBolder" an , as you might e;pe%t, arranges $or the %amera previe> to be isplaye on the asso%iate S&rfaceView. )o>ever, the S&rfaceView may not be rea y imme iately a$ter being %hange into SD6K3C8/<C58/5DSB/;DKK86S mo e. #o, >hile the previous setup >ork %oul be one in onCreate(), you shoul >ait until the S&rfaceBolder.Callbac. has its s&rfaceCreated() metho %alle , then register the Camera*
p&blic"void"surfaceCreated(S&rfaceBolder"-older)"4 ""camera#Camera.open(): ""tr+"4 """"camera.set review"isplay(previewBolder): ""? ""catc-"(<-rowable"t)"4 """"*og.e($5review7emo's&rfaceCallbac.$> """"""""""$8xception"in"set5review7ispla+()$>"t): """"<oast """""".ma)e+e(t(5review7emo.t-is>"t.get%essage()>"<oast.*8=G<B/*2=G) """""".s!ow(): --$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing the Camera

""? ?

0e;t, on%e the S&rfaceView is set up an siCe by An roi , >e nee to pass %on$iguration ata to the Camera, so it kno>s ho> big to ra> the previe>. #in%e the previe> pane is not a $i;e siCe M it might vary base on har >are M >e %annot sa$ely pre3 etermine the siCe. .t is simplest to >ait $or our S&rfaceBolder.Callbac. to have its s&rfaceC-anged() metho %alle , >hen >e are tol the siCe o$ the sur$a%e. 5hen, >e %an pour that in$ormation into a Camera.5arameters obLe%t, up ate the Camera >ith those parameters, an have the Camera sho> the previe> images via start5review()*
p&blic"void"surfaceC!anged(S&rfaceBolder"-older> """""""""""""""""""""""""int"format>"int"widt-> """""""""""""""""""""""""int"-eig-t)"4 ""Camera.5arameters"parameters#camera.get arameters(): ""parameters.set reviewSi.e(widt->"-eig-t): ""camera.set arameters(parameters): ""camera.start review(): ?

Bventually, the previe> nee s to stop. .n this parti%ular %ase, that >ill be as the a%tivity is being estroye . .t is important to release the Camera at this time M $or many evi%es, there is only one physi%al %amera, so only one a%tivity %an be using it at a time. Gur S&rfaceBolder.Callbac. >ill be tol , via s&rface7estro+ed(), >hen it is being %lose up, an >e %an stop the previe> &stop5review()', release the %amera &release()', an let go o$ it &camera"#"n&ll' at that point*
p&blic"void"surface"estroyed(S&rfaceBolder"-older)"4 ""camera.stop review(): ""camera.release(): ""camera#n&ll: ?

.$ you %ompile an run the Camera/5review sample appli%ation, you >ill see, on3s%reen, >hat the %amera sees. )ere is the $ull S&rfaceBolder.Callbac. implementation*

--0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing the Camera

S&rfaceBolder.Callbac."s&rfaceCallbac.#new"S&rfaceBolder.Callbac)()"4 ""p&blic"void"surfaceCreated(S&rfaceBolder"-older)"4 """"camera#Camera.open(): """"tr+"4 """"""camera.set review"isplay(previewBolder): """"? """"catc-"(<-rowable"t)"4 """"""*og.e($5review7emo's&rfaceCallbac.$> """"""""""""$8xception"in"set5review7ispla+()$>"t): """"""<oast """""""".ma)e+e(t(5review7emo.t-is>"t.get%essage()>"<oast.*8=G<B/*2=G) """""""".s!ow(): """"? ""? ""p&blic"void"surfaceC!anged(S&rfaceBolder"-older> """""""""""""""""""""""""""int"format>"int"widt-> """""""""""""""""""""""""""int"-eig-t)"4 """"Camera.5arameters"parameters#camera.get arameters(): """"parameters.set reviewSi.e(widt->"-eig-t): """"camera.set arameters(parameters): """"camera.start review(): ""? ""p&blic"void"surface"estroyed(S&rfaceBolder"-older)"4 """"camera.stop review(): """"camera.release(): """"camera#n&ll: ""? ?:

+mage +s <verything
#ho>ing the previe> imagery is ni%e an all, but it is probably more important to a%tually take a pi%ture no> an again. 5he previe>s sho> the user >hat the %amera sees, but >e still nee to let our appli%ation kno> >hat the %amera sees at parti%ular points in time. .n prin%iple, this is easy. Where things get a bit %ompli%ate %omes >ith ensuring the appli%ation &an evi%e as a >hole' has e%ent per$orman%e, not slo>ing o>n to pro%ess the pi%tures.

--2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing the Camera

5he %o e snippets sho>n in this se%tion are pulle $rom the Camera/5ict&re" sample proLe%t, >hi%h buil s upon the Camera/5review sample sho>n in the previous se%tion.

As&in! *or a 8ormat


We nee to tell the Camera >hat sort o$ pi%ture to take >hen >e e%i e to take a pi%ture. 5he t>o options are ra> an +!B8. At least, that is the theory. .n pra%ti%e, the 53Mobile 8- oes not support ra> output, only +!B8. #o, >e nee to tell the Camera that >e >ant +!B8 output. 5hat is merely a matter o$ %alling set5ict&reKormat() on the Camera.5arameters obLe%t >hen >e %on$igure our Camera, using the value J58G"

to in i%ate that >e, in ee , >ant +!B8*

p&blic"void"surfaceC!anged(S&rfaceBolder"-older> """""""""""""""""""""""""int"format>"int"widt-> """""""""""""""""""""""""int"-eig-t)"4 ""Camera.5arameters"parameters#camera.get arameters(): ""parameters.set reviewSi.e(widt->"-eig-t): ""parameters.set icture'ormat(5ixelKormat.J58G): ""camera.set arameters(parameters): ""camera.start review(): ?

Connectin! the Camera Button


#omeho>, your appli%ation >ill nee to in i%ate >hen a pi%ture shoul be taken. 5hat %oul be via >i gets on the "., though in our samples here, the previe> is $ull3s%reen. An alternative is to use the %amera har >are button. Like every har >are button other than the )ome button, >e %an $in out >hen the %amera button is %li%ke via onVe+7own()*

--3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing the Camera

02verride p&blic"boolean"on#ey"own(int".e+Code>"Ve+8vent"event)"4 ""if"(.e+Code##Ve+8vent.V8CC278/C39863"YY """""".e+Code##Ve+8vent.V8CC278/S836CB)"4 """"ta)e icture(): """"ret&rn(tr&e): ""? ""ret&rn(s&per.on#ey"own(.e+Code>"event)): ?

#in%e the )5C Magi% oes not have a har >are %amera button, >e also >at%h $or V8CC278/S836CB $or the e i%ate sear%h key, >hi%h is in the upper3right portion o$ the Magi%7s $a%e >hen the evi%e is hel in lan s%ape mo e.

Ta&in! a Picture
Gn%e it is time to take a pi%ture, all you nee to o is*

#top the previe> 5ell the Camera to ta.e5ict&re()

5he ta.e5ict&re() metho takes three parameters, all %allba%k3style obLe%ts* -. A IshutterI %allba%k &Camera.S-&tterCallbac.', >hi%h is noti$ie >hen the pi%ture has been %apture by the har >are but the ata is not yet available M you might use this to play a I%amera %li%kI soun

2. Callba%ks to re%eive the image ata, either in ra> $ormat or +!B8 $ormat #in%e the 53Mobile 8- only supports +!B8 output, an be%ause >e o not >ant to $uss >ith a shutter %li%k, 5ict&re7emo only passes in the thir parameter to ta.e5ict&re()*
private"void"ta)e icture()"4 ""camera.stop review(): ""camera.ta)e icture(n&ll>"n&ll>"p-otoCallbac.): ?

--4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing the Camera

Camera.5ict&reCallbac. &p-otoCallbac.' nee s to implement on5ict&re<a.en(), >hi%h provi es the pi%ture ata as a b+tePQ, plus the Camera obLe%t that took the pi%ture. At this point, it is sa$e to start up the

5he

previe> again. !lus, o$ %ourse, it >oul be ni%e to o something >ith that byte array. 5he %at%h is that the byte array is going to be large M the 53Mobile 8- has a ?3megapi;el %amera, an $uture har >are is more likely to have ri%her har >are than that. Writing that to $lash, or sen ing it over the net>ork, or oing Lust about anything >ith the ata, >ill be slo>. #lo> is $ine...so long as it is not on the ". threa . 5hat means >e nee to o a little more >ork.

%sin! AsyncTas&
.n theory, >e %oul Lust $ork a ba%kgroun threa to save o$$ the image ata or o >hatever it is >e >ante one >ith it. )o>ever, >e %oul >in up >ith several su%h threa s, parti%ularly i$ >e are sen ing the image over the .nternet an o not have a $ast %onne%tion to our estination server. An roi -.A o$$ers a >ork <ueue mo el, in the $orm o$ 3s+nc<as.. 3s+nc<as." manages a threa pool an >ork <ueue M all >e nee to o is han it the >ork to be one. #o, >e %an %reate an 3s+nc<as. implementation, %alle $ollo>s*
Save5-oto<as.,

as

class"Save5-oto<as."extends"3s+nc<as. b+tePQ>"String>"String)"4 ""02verride ""protected"String"doInBac)ground(b+tePQ..."Apeg)"4 """"Kile"p-oto#new"'ile(8nvironment.getE(ternalStorage"irectory()> """""""""""""""""""""""$p-oto.Apg$): """"if"(p-oto.e(ists())"4 """"""p-oto.delete(): """"?

--5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing the Camera

""""tr+"4 """"""Kile2&tp&tStream"fos#new"'ile$utputStream(p-oto.get at!()): """"""fos.write(ApegP%Q): """"""fos.close(): """"? """"catc-"(Aava.io.I28xception"e)"4 """"""*og.e($5ict&re7emo$>"$8xception"in"p-otoCallbac.$>"e): """"? """"ret&rn(n&ll): ""? ?

Gur doIn;ac.gro&nd() implementation gets the byte array >e re%eive $rom An roi . 5he byte array is simply the +!B8 itsel$, so the ata %oul be >ritten to a $ile, trans$orme , sent to a Web servi%e, %onverte into a ;itmap7rawable $or isplay on the s%reen or >hatever. .n the %ase o$ 5ict&re7emo, >e take the simple approa%h o$ >riting the +!B8 $ile as p-oto.Apg in the root o$ the #@ %ar . 5he byte array itsel$ >ill be garbage %olle%te on%e >e are one saving it, so there is no e;pli%it I$reeI operation >e nee to o to release that memory. (inally, >e arrange $or our 5-otoCallbac. to e;e%ute our Save5-oto<as.*
Camera.5ict&reCallbac."p-otoCallbac.#new"Camera. ictureCallbac)()"4 ""p&blic"void"on icture+a)en(b+tePQ"data>"Camera"camera)"4 """"new"Save !oto+as)().e(ecute(data): """"camera.start review(): ""? ?:

-%6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

PART III Advanced System

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 9

Sensors

I#ensorsI is An roi 7s overall term $or >ays that An roi %an ete%t elements o$ the physi%al >orl aroun it, $rom magneti% $lu; to the movement o$ the evi%e. 0ot all evi%es >ill have all possible sensors, an other sensors are likely to be a e over time. .n this %hapter, >e >ill e;plore >hat sensors are theoreti%ally available an ho> to use a $e> o$ them that >ork on early An roi evi%es like the 53Mobile 8-. 5he samples in this %hapter assume that you have a%%ess to a pie%e o$ sensor3e<uippe An roi har >are, su%h as a 53Mobile 8-. 5he Gpen.ntents.org proLe%t has a sensor simulator >hi%h you %an also use, though the use o$ this tool is not %overe here. 5he author >oul like to thank #ean Catlin $or %o e samples that helpe %lear up %on$usion surroun ing the use o$ sensors.

The Sixth Sense/ ,r Possibly the Seventh/


.n theory, An roi supports the $ollo>ing sensor types*

An a%%elerometer, that tells you the motion o$ the evi%e in spa%e through all three imensions An ambient light sensor, telling you ho> bright or surroun ings are ark the

-%.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sensors

A magneti% $iel sensor, to tell you >here magneti% north is &unless some other magneti% $iel is nearby, su%h as $rom an ele%tri%al motor' An orientation sensor, to tell you ho> the evi%e is positione in all three imensions A pro;imity sensor, to tell you ho> $ar the evi%e is $rom some other spe%i$i% obLe%t A temperature sensor, to tell you the temperature o$ the surroun ing environment A tri%or er sensor, to turn the 5ri%or erI evi%e into Ia $ully $un%tional

Clearly, not all o$ these possible sensors are available to ay, su%h as the last one. What e$initely are available to ay on the 53Mobile 8- are the a%%elerometer, the magneti% $iel sensor, an the orientation sensor. 5o a%%ess any o$ these sensors, you nee a Sensor9anager, $oun in the android.-ardware pa%kage. Like other aspe%ts o$ An roi , the Sensor9anager" is a system servi%e, an as su%h is obtaine via the getS+stemService()" metho on your 3ctivit+ or other Context*
mgr#(Sensor9anager)getSystemService(Context.S8=S26/S86VIC8):

,rienting 7ourself
.n prin%iple, to $in out >hi%h ire%tion is north, you >oul use the magneti% $lu; sensor an go through a lovely set o$ %al%ulations to $igure out the appropriate ire%tion. (ortunately $or us, An roi long as the evi%e is hel tabletop'. i all that as part o$ the orientation sensor...so $lat in the horiContal plane &e.g., on a level

Akin to the lo%ation servi%es, there is no >ay to ask the Sensor9anager >hat the %urrent value o$ a sensor is. .nstea , you nee to hook up a
-%$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sensors

Sensor8vent*istener an respon to %hanges in the sensor values. 5o o this, simply %all register*istener() >ith your Sensor8vent*istener an the Sensor you >ish to hear $rom. Dou %an get the Sensor by asking the Sensor9anager $or the e$ault Sensor $or a parti%ular type. (or e;ample, $rom the Sensor/Compass sample proLe%t, here is >here >e register our listener*
mgr.registerListener(listener> """""""""""""""""""""mgr.get"efaultSensor(Sensor.<C58/26I8=<3<I2=)> """""""""""""""""""""Sensor9anager.S8=S26/78*3C/DI):

0ote that you also spe%i$y the rate at >hi%h sensor up ates >ill be re%eive . )ere, >e use S8=S26/78*3C/DI, but you %oul say S8=S26/78*3C/K3S<8S< or various other values. .t is important to unregister the listener >hen the a%tivity %loses o>nO other>ise, the appli%ation >ill never really terminate an the listener >ill get up ates in e$initely. 5o o this, Lust %all &nregister*istener() $rom a likely lo%ation, su%h as on7estro+()*
02verride p&blic"void"on"estroy()"4 ""s&per.on"estroy(): ""mgr.unregisterListener(listener): ?

Dour Sensor8vent*istener implementation >ill nee t>o metho s. 5he one you probably >ill not use that o$ten is on3cc&rac+C-anged(), >hen you >ill be noti$ie as a given sensor7s a%%ura%y %hanges $rom S8=S26/S<3<DS/3CCD63CC/BIGB to S8=S26/S<3<DS/3CCD63CC/987ID9 to S8=S26/S<3<DS/3CCD63CC/*2W to S8=S26/S<3<DS/D=68*I3;*8. 5he one you >ill use more %ommonly is onSensorC-anged(), >here you are provi e a Sensor8vent %ontaining a floatPQ o$ values $or the sensor. 5he tri%ky part is etermining >hat these sensor values mean. .n the %ase o$ <C58/26I8=<3<I2=, the $irst o$ the supplie values represents the orientation o$ the evi%e in egrees o$$ o$ magneti% north. 90 egrees means east, -20 means south, an 210 means >est, Lust like on a regular %ompass.
-%0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sensors

.n Sensor/Compass, >e up ate a <extView >ith the ea%h rea ing*


private"Sensor8vent*istener"listener#new"SensorEventListener()"4 ""p&blic"void"onSensorC!anged(Sensor8vent"e)"4 """"if"(e.sensor.get+ype()##Sensor.<C58/26I8=<3<I2=)"4 """"""degrees.set+e(t(String.value$f(e.val&esP%Q)): """"? ""? ""p&blic"void"on&ccuracyC!anged(Sensor"sensor>"int"acc&rac+)"4 """"//"&n&sed ""? ?:

What you get is a trivial appli%ation sho>ing >here the top o$ the phone is pointing. 0ote that the sensor seems to take a bit to get initially stabiliCe , then >ill ten to lag a%tual motion a bit.

!igure .$/ The Compass9emo application* sho)ing a T"8obile '- pointing south"by"southeast

-%2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sensors

Steering 7our Phone


.n television %ommer%ials $or other mobile evi%es, you may see them being use like a steering >heel, o$ten times $or playing a riving simulation game. An roi %an appli%ation. o this too. Dou %an see it in the Sensor/Steering sample

.n the pre%e ing se%tion, >e note that <C58/26I8=<3<I2= returns in the $irst value o$ the floatPQ the orientation o$ the phone, %ompare to magneti% north, i$ the evi%e is horiContal. When the evi%e is hel like a steering >heel, the se%on value o$ the floatPQ >ill %hange as the evi%e is Isteere I. 5his sample appli%ation is very similar to the Sensor/Compass one sho>n in the previous se%tion. 5he biggest %hange %omes in the Sensor8vent*istener" implementation*
private"Sensor8vent*istener"listener#new"SensorEventListener()"4 ""p&blic"void"onSensorC!anged(Sensor8vent"e)"4 """"if"(e.sensor.get+ype()##Sensor.<C58/26I8=<3<I2=)"4 """"""float"orientation#e.val&esP1Q: """"""if"(prev2rientationN#orientation)"4 """"""""if"(prev2rientation orientation)"4 """"""""""steerLeft(orientation> """"""""""""""""""""orientation'prev2rientation): """"""""? """"""""else"4 """"""""""steerRig!t(orientation> """""""""""""""""""""prev2rientation'orientation): """"""""? """"""""prev2rientation#e.val&esP1Q: """"""? """"? ""? ""p&blic"void"on&ccuracyC!anged(Sensor"sensor>"int"acc&rac+)"4 """"//"&n&sed ""? ?:

-%3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sensors

)ere, >e tra%k the previous orientation &prev2rientation' an %all a steer*eft() or steer6ig-t() metho base on >hi%h ire%tion the I>heelI is turne . (or ea%h, >e provi e the ne> %urrent position o$ the >heel an the amount the >heel turne , measure in egrees. 5he steer*eft() an steer6ig-t() metho s, in turn, simply ump their results to a Itrans%riptI* a <extView insi e a ScrollView, set up to automati%ally keep s%rolling to the bottom*
private"void"steerLeft(float"position>"float"delta)"4 ""String;&ffer"line#new"StringBuffer($Steered"left"b+"$): ""line.append(String.value$f(delta)): ""line.append($"to"$): ""line.append(String.value$f(position)): ""line.append($Zn$): ""transcript.set+e(t(transcript.get+e(t().toString()1line.toString()): ""scroll.fullScroll(View.K2CDS/72W=): ? private"void"steerRig!t(float"position>"float"delta)"4 ""String;&ffer"line#new"StringBuffer($Steered"rig-t"b+"$): ""line.append(String.value$f(delta)): ""line.append($"to"$): ""line.append(String.value$f(position)): ""line.append($Zn$): ""transcript.set+e(t(transcript.get+e(t().toString()1line.toString()): ""scroll.fullScroll(View.K2CDS/72W=): ?

5he result is a log o$ the steering IeventsI as the evi%e is turne like a steering >heel. Gbviously, a real game >oul translate these events into game a%tions, su%h as %hanging your perspe%tive o$ the riving %ourse.

-%4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sensors

!igure .0/ The Steering9emo application

9o DThe ShakeD
Another emo you o$ten see >ith %ertain other mobile evi%es is shaking the evi%e to %ause some on3s%reen e$$e%t, su%h as rolling i%e or s%rambling puCCle pie%es. An roi %an o this as >ell, as you %an see in the Sensor/S-a.er sample appli%ation, >ith our ata provi e by the a%%elerometer sensor &<C58/3CC8*86298<86'. What the a%%elerometer sensor provi es is the a%%leration in ea%h o$ three imensions. At rest, the a%%eleration is e<ual to Barth7s gravity &or the gravity o$ >herever you are, i$ you are not on Barth'. When shaken, the a%%eleration shoul be higher than Barth7s gravity M ho> mu%h higher is epen ent on ho> har the evi%e is being shaken. While the in ivi ual a;es o$ a%%eleration might tell you, at any point in time, >hat ire%tion the evi%e is being shaken in, sin%e a shaking a%tion involves $re<uent %onstant %hanges in ire%tion, >hat >e really >ant to kno> is ho> $ast the evi%e is moving overall M a slo> stea y movement is not a shake, but something more aggressive is. Gn%e again, our ". output is simply a Itrans%riptI <extView as be$ore. 5his time, though, >e separate out the a%tual shake3 ete%tion logi% into a S-a.er" %lass >hi%h our S-a.er7emo a%tivity re$eren%es, as sho>n belo>*
-%5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sensors

pac.age"com.commonsware.android.sensor: import"android.app.3ctivit+: import"android.os.;&ndle: import"android.&til.*og: import"android.view.View: import"android.widget.ScrollView: import"android.widget.<extView: p&blic"class"S-a.er7emo"extends"3ctivit+ ""implements"S-a.er.Callbac."4 ""private"S-a.er"s-a.er#n&ll: ""private"<extView"transcript#n&ll: ""private"ScrollView"scroll#n&ll: "" ""02verride ""p&blic"void"onCreate(;&ndle"savedInstanceState)"4 """"s&per.onCreate(savedInstanceState): """"setContentView(6.la+o&t.main): """" """"transcript#(<extView)findViewById(6.id.transcript): """"scroll#(ScrollView)findViewById(6.id.scroll): """" """"s-a.er#new"S!a)er(t-is>"1.EHd>"H%%>"t-is): ""? "" ""02verride ""p&blic"void"on"estroy()"4 """"s&per.on"estroy(): """" """"s-a.er.close(): ""? "" ""p&blic"void"s!a)ingStarted()"4 """"*og.d($S-a.er7emo$>"$S-a.ing"startedN$): """"transcript.set+e(t(transcript.get+e(t().toString()1$S-a.ing"startedZn$): """"scroll.fullScroll(View.K2CDS/72W=): ""? "" ""p&blic"void"s!a)ingStopped()"4 """"*og.d($S-a.er7emo$>"$S-a.ing"stoppedN$): """"transcript.set+e(t(transcript.get+e(t().toString()1$S-a.ing"stoppedZn$): """"scroll.fullScroll(View.K2CDS/72W=): ""? ?

5he S-a.er takes $our parameters*


A Context, so >e %an get a%%ess to the Sensor9anager servi%e An in i%ation o$ ho> har a shake shoul <uali$y as a shake, e;presse as a ratio applie to Barth7s gravity, so a value o$ 1.EH"

-.6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sensors

means the shake has to be 2AP stronger than gravity to be %onsi ere a shake

An amount o$ time >ith belo>3threshol a%%eleration, a$ter >hi%h the shake is %onsi ere I oneI A S-a.er.Callbac. obLe%t that >ill be noti$ie >hen a shake starts an stops

While in this %ase, the %allba%k metho s &implemente on the S-a.er7emo" a%tivity itsel$' simply log shake events to the trans%ript, a IrealI appli%ation >oul , say, start an animation o$ i%e rolling >hen the shake starts an en the animation shortly a$ter the shake en s. 5he S-a.er simply %onverts the three in ivi ual a%%eleration %omponents into a %ombine a%%eleration value &s<uare root o$ the sum o$ the s<uares', then %ompares that value to Barth7s gravity. .$ the ratio is higher than the supplie threshol , then >e %onsi er the evi%e to be presently shaking, an >e %all the s-a.ingStarted() %allba%k metho i$ the evi%e >as not shaking be$ore. Gn%e shaking en s, an time elapses, >e %all s-a.ingStopped() on the %allba%k obLe%t an assume that the shake has en e . A more robust implementation o$ S-a.er >oul take into a%%ount the possibility that the sensor >ill not be up ate $or a >hile a$ter the shake en s, though in reality, normal human movement >ill ensure that there are some sensor up ates, so >e %an $in out >hen the shaking en s.
pac.age"com.commonsware.android.sensor: import"android.content.Context: import"android.-ardware.Sensor: import"android.-ardware.Sensor8vent: import"android.-ardware.Sensor8vent*istener: import"android.-ardware.Sensor9anager: import"android.os.S+stemCloc.: import"Aava.&til.3rra+*ist: import"Aava.&til.*ist: p&blic"class"S-a.er"4 ""private"Sensor9anager"mgr#n&ll: ""private"long"lastS-a.e<imestamp#%: ""private"do&ble"t-res-old#1.%d: ""private"long"gap#%: ""private"S-a.er.Callbac."cb#n&ll: ""

-.Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sensors

""p&blic"S!a)er(Context"ctxt>"do&ble"t-res-old>"long"gap> """"""""""""""""""S-a.er.Callbac."cb)"4 """"t-is.t-res-old#t-res-oldMt-res-old: """"t-is.t-res-old#t-is.t-res-old """"""""""""""""""""MSensor9anager.G63VI<C/836<B """"""""""""""""""""MSensor9anager.G63VI<C/836<B: """"t-is.gap#gap: """"t-is.cb#cb: """" """"mgr#(Sensor9anager)ctxt.getSystemService(Context.S8=S26/S86VIC8): """"mgr.registerListener(listener> """""""""""""""""""""""""mgr.get"efaultSensor(Sensor.<C58/3CC8*86298<86)> """""""""""""""""""""""""Sensor9anager.S8=S26/78*3C/DI): ""? "" ""p&blic"void"close()"4 """"mgr.unregisterListener(listener): ""? "" ""private"void"isS!a)ing()"4 """"long"now#S+stemCloc..uptime%illis(): """" """"if"(lastS-a.e<imestamp##%)"4 """"""lastS-a.e<imestamp#now: """""" """"""if"(cbN#n&ll)"4 """"""""cb.s!a)ingStarted(): """"""? """"? """"else"4 """"""lastS-a.e<imestamp#now: """"? ""? "" ""private"void"is-otS!a)ing()"4 """"long"now#S+stemCloc..uptime%illis(): """" """"if"(lastS-a.e<imestamp)%)"4 """"""if"(now'lastS-a.e<imestamp)gap)"4 """"""""lastS-a.e<imestamp#%: """""""" """"""""if"(cbN#n&ll)"4 """"""""""cb.s!a)ingStopped(): """"""""? """"""? """"? ""? "" ""p&blic"interface"Callbac."4 """"void"s!a)ingStarted(): """"void"s!a)ingStopped(): ""? "" ""private"Sensor8vent*istener"listener#new"SensorEventListener()"4

-.%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Sensors

""""p&blic"void"onSensorC!anged(Sensor8vent"e)"4 """"""if"(e.sensor.get+ype()##Sensor.<C58/3CC8*86298<86)"4 """"""""do&ble"netKorce#e.val&esP%QMe.val&esP%Q: """""""" """"""""netKorce1#e.val&esP1QMe.val&esP1Q: """"""""netKorce1#e.val&esPEQMe.val&esPEQ: """""""" """"""""if"(t-res-old netKorce)"4 """"""""""isS!a)ing(): """"""""? """"""""else"4 """"""""""is-otS!a)ing(): """"""""? """"""? """"? """" """"p&blic"void"on&ccuracyC!anged(Sensor"sensor>"int"acc&rac+)"4 """"""//"&n&sed """"? ""?: ?

All the trans%ript sho>s, o$ %ourse, is >hen shaking starts an stops*

!igure .2/ The Shaker9emo application* sho)ing a pair of shakes

-..
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 1:

9atabases and Content Providers

.n the abstra%t, >orking >ith #FLite atabases an An roi 3style %ontent provi ers is $airly straight3$or>ar . Ba%h supports a CR"@3style inter$a%e &@&er+(), insert(), &pdate(), delete()' using C&rsor obLe%ts $or <uery results. While implementing a Content5rovider is no pi%ni% $or non3#FLite ata stores, everything else is $airly rote. .n reality, though, atabases an %ontent provi ers %ause more than their $air share o$ hassles. Mostly, this %omes $rom everything outside o$ simple CR"@ operations, su%h as*

)o> o >e get a atabase into our appli%ationJ )o> o >e get ata into our appli%ation on initial installJ Gn an up ateJ Where is the provi ersJ o%umentation $or the built3in An roi %ontent

)o> o >e eal >ith Loins bet>een ata stores, su%h as merging %onta%ts >ith our o>n atabase ataJ

.n this %hapter, >e e;plore these issues, to sho> ho> you %an better >ork >ith atabases an %ontent provi ers in the real >orl .

-.0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

9istributed 9ata
#ome atabases use by An roi appli%ations naturally start empty. (or e;ample, a Ipass>or sa$eI probably has no pass>or s >hen initially laun%he by the user, an an e;pense3tra%king appli%ation probably oes not have any e;penses re%or e at the outset. )o>ever, sometimes, there are atabases that nee to ship >ith an appli%ation that must be pre3populate >ith ata. (or e;ample, you might be implementing an online %atalog, >ith a atabase o$ items $or sale installe >ith the appli%ation an up ate as nee e via %alls to some Web servi%e. 5he same stru%ture >oul hol true $or any sort o$ re$eren%e, $rom %hemi%als to >or translations to histori%al sports re%or s. "n$ortunately, there is no >ay to ship a atabase >ith ata in it via the An roi A!K pa%kaging me%hanism. An A!K is an e;e%utable blob, $rom the stan point o$ An roi an @alvik. More importantly, it is store rea 3 only in a E.! $ile, >hi%h makes up ates to that ata oubly impossible. 5he ne;t3best option is to ship your ata >ith the appli%ation by some other means an loa it into a ne>ly3%reate atabase >hen the appli%ation is $irst run. 5his oes involve t>o %opies o$ the ata* the original in your appli%ation an the >orking %opy in the atabase. 5hat may seem >aste$ul in terms o$ spa%e. )o>ever, %ourtesy o$ E.! %ompression, the original %opy may not take up all that mu%h spa%e. Also, you %an turn this into a $eature, o$$ering some sort o$ IresetI me%hanism to reloa the >orking atabase $rom the original i$ nee e . 5he %hallenge then be%omes ho> to pa%kage the atabase %ontents into the A!K an loa it into the >orking atabase. . eally, this involves as little >ork as possible $rom the eveloper, %an $it into the e;isting buil system, an %an take a vantage o$ e;isting atabase manipulation tools &versus, say, han 3>riting hun re s o$ S[*"I=S86< statements'. 0ote that another possibility e;ists* pa%kage the binary #FLite atabase $ile in the A!K &e.g., in res/raw/' an %opy it into position using binary streams.
-.2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

5his assumes the #FLite atabase $ile your evelopment environment >oul %reate is the same as >hat is e;pe%te by the #FLite engine bake into An roi . 5his %an >ork, but is likely to be more prone to versioning issues M $or e;ample, i$ your evelopment environment is upgra e to a ne>er #FLite that has a slightly i$$erent $ile $ormat.

(;"ite< =n3Device- =n3Des&top


5his be%omes mu%h simpler >hen you realiCe that An roi uses #FLite $or the atabase, an #FLite >orks on Lust about every plat$orm you might nee . .t is trivial to >ork >ith #FLite atabases on your evelopment >orkstation, even easier than >orking >ith atabases insi e an An roi emulator or evi%e. 5he plan, there$ore, is to allo> evelopers to %reate the atabase to be Ishippe I as a #FLite atabase, then buil tools that pa%kage the #FLite %ontents into the An roi A!K an turn it ba%k into a atabase >hen the appli%ation nee s it. 5his allo>s evelopers to use >hatever tools they >ant to manipulate the #FLite atabase, ranging $rom typi%al atabase management ".s to spe%ialiCe %onversion s%ripts to >hatever. 5o make this plan >ork, though, >e nee t>o bits o$ %o e* -. We nee something that e;tra%ts the ata out o$ the #FLite atabase the eveloper has prepare an puts it somepla%e insi e the An roi A!K

2. We nee something that ties in >ith S[*ite2penBelper that takes the A!K3pa%kage ata an turns it into an on3 evi%e atabase >hen the atabase is $irst a%%esse .

E'portin! a Data#ase
(ortunately, the s@liteJ %omman 3line e;e%utable that %omes stan ar >ith #FLite o$$ers a .d&mp %omman to ump the %ontents o$ a table as a
-.3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

series o$ #FL statements* one to %reate the table, plus the ne%essary S[*" I=S86< statements to populate it. All >e nee to o is tie this into the buil system, so the a%t o$ %ompiling the A!K also eals >ith the atabase. Dou %an $in some sample %o e that han les this in the 7atabase/5ac.ager" sample appli%ation. #pe%i$i%ally*

5here is a #FLite atabase %ontaining ata in the db/ proLe%t ire%tory M in this %ase, it is the atabase $rom the Content5rovider/Constants proLe%t $rom The Busy Coder's Guide to Android De elopment 5here is a pac.age/db.rb Ruby s%ript that >raps aroun the .d&mp" %omman to e;port the ata 5here is a %hange to the b&ild.xml Ant s%ript to use this Ruby s%ript

The Ruby Script


Dou may or may not be a $an o$ Ruby. While this sample %o e sho>s this utility as a Ruby s%ript, rest assure that #FLite has inter$a%es to most programming languages &though its +ava support is not the strongest', so you %an %reate your o>n e ition o$ this s%ript in >hatever language suits you. 5he s%ript is $airly short*
re@&ire"Or&b+gemsO re@&ire"Os@liteJO 7irPOdb/MOQ.eac-"do"Ypat-Y ""db#S[*iteJ,,7atabase.new(pat-) "" ""begin """"db.exec&te($S8*8C<"name"K629"s@lite/master"WB868"t+pe#OtableO$)"do"YrowY """"""if"36GV.incl&de!(rowP%Q) """"""""p&ts"\s@liteJ"R4pat-?"$.d&mp"R4rowP%Q?$\ """"""end """"end ""ens&re """"db.close ""end end

-.4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

.t iterates over every $ile in the db/ ire%tory an opens ea%h as a #FLite atabase. .t then <ueries the atabase $or the list o$ tables &S8*8C<"name"K629" s@lite/master " WB868 " t+pe " # " OtableO'. Any table mat%hing a table name passe in on the %omman line is assume to be one nee ing to be e;porte , so it prints to stdo&t the results o$ the s@liteJ .d&mp %omman , run on that atabase an table. We use s@liteJ be%ause there oes not appear to be an A!. %all that implements the .d&mp $un%tionality. 5o run this s%ript, you nee #FLite? installe , >ith s@liteJ in your !A5), an you nee the Ruby interpreter. Dou also nee to run it $rom the proLe%t ire%tory, >ith a db/ ire%tory %ontaining one or more atabase $iles. Running the Ruby s%ript >ill ump the spe%i$ie statements* tables as a set o$ #FL

;8GI="<63=S3C<I2=: C683<8"<3;*8"constants"(/id"I=<8G86"56I936C"V8C"3D<2I=C6898=<>"title"<8W<>"val&e" 683*): I=S86<"I=<2"$constants$"V3*D8S(1>OGravit+>"7eat-"Star"IO>J.HJ%JX1FEHF1(TXe'%G): I=S86<"I=<2"$constants$"V3*D8S(E>OGravit+>"8art-O>T.(%XXH%1X1GFJ1X): I=S86<"I=<2"$constants$"V3*D8S(J>OGravit+>"J&piterO>EJ.1E%%%%(JTEJJF): I=S86<"I=<2"$constants$"V3*D8S(F>OGravit+>"9arsO>J.G1%%%%%J(1FXTG): I=S86<"I=<2"$constants$"V3*D8S(H>OGravit+>"9erc&r+O>J.G%%%%%%FGX(JGE): I=S86<"I=<2"$constants$"V3*D8S(X>OGravit+>"9oonO>1.X%%%%%%EJ(F1(X): I=S86<"I=<2"$constants$"V3*D8S(G>OGravit+>"=ept&neO>11.%): I=S86<"I=<2"$constants$"V3*D8S((>OGravit+>"5l&toO>%.X%%%%%%EJ(F1(H(): I=S86<"I=<2"$constants$"V3*D8S(T>OGravit+>"Sat&rnO>(.TX%%%%%J(1FXTG): I=S86<"I=<2"$constants$"V3*D8S(1%>OGravit+>"S&nO>EGH.%): I=S86<"I=<2"$constants$"V3*D8S(11>OGravit+>"<-e"IslandO>F.(1H1XE1(1(HFEH): I=S86<"I=<2"$constants$"V3*D8S(1E>OGravit+>"Dran&sO>(.X(TTTTH(%J(JJ): I=S86<"I=<2"$constants$"V3*D8S(1J>OGravit+>"Ven&sO>(.(XTTTT((HHHT%(): C299I<:

.n this %ase, the %onstants table is empty, so there are no S[* " I=S86<" statements. )o>ever, you %oul easily a some ro>s to the constants table M perhaps %onstants not available in An roi itsel$ M an ship those along >ith the table s%hema.

"oadin! the E'ported Data#ase


5he other en
res/raw/pac.aged/db.txt

o$ his pro%ess is to take the ra> #FL stores in an Iin$lateI it at runtime into a atabase. #in%e
-.5

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

is esigne to han le su%h operations, it seems to make sense to implement this logi% as a sub%lass. Dou %an $in su%h a %lass M 7atabaseInstaller M in the 7atabase/5ac.ager sample proLe%t*
S[*ite2penBelper
import"android.content.Context: import"android.database.S[*8xception: import"android.database.s@lite.S[*ite2penBelper: import"android.database.s@lite.S[*ite7atabase: import"android.database.s@lite.S[*ite[&er+;&ilder: import"Aava.io.M: abstract"class"7atabaseInstaller"extends"S[*ite2penBelper"4 ""abstract"void"!andleInstallError(<-rowable"t): "" ""private"Context"ctxt#n&ll: "" ""p&blic""atabaseInstaller(Context"context>"String"name> """""""""""""""""""""""""""S[*ite7atabase.C&rsorKactor+"factor+> """""""""""""""""""""""""""int"version)""4 """"s&per(context>"name>"factor+>"version): """" """"t-is.ctxt#context: ""? "" ""02verride ""p&blic"void"onCreate(S[*ite7atabase"db)"4 """"tr+"4 """"""Inp&tStream"stream#ctxt """"""""""""""""""""""""".getResources() """"""""""""""""""""""""".openRawResource(6.raw.pac.aged/db): """"""Inp&tStream6eader"is#new"InputStreamReader(stream): """""";&ffered6eader"in#new"BufferedReader(is): """"""String"str: "" """"""w-ile"((str"#"in.readLine())"N#"n&ll)"4 """"""""if"(Nstr.equals($;8GI="<63=S3C<I2=:$)"UU"Nstr.equals($C299I<:$))"4 """"""""""db.e(ecS0L(str): """"""""? """"""? """""" """"""in.close(): """"? """"catc-"(I28xception"e)"4 """"""!andleInstallError(e): """"? ""? ?

-$6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

5his %lass is abstra%t, e;pe%ting sub%lasses to implement both the onDpgrade() path $rom S[*ite2penBelper an a -andleInstall8rror() %allba%k in %ase something $ails uring onCreate(). Most o$ the smarts are $oun in 7atabaseInstaller7s onCreate()" implementation. #in%e S[*ite7atabase has no means to e;e%ute #FL statements %ontaine in an Inp&tStream, >e are stu%k opening the 6.raw.pac.aged/db resour%e an rea ing the statements out ourselves, one at a time. )o>ever, the e;porte #FL >ill likely %ontain ;8GI= " <63=S3C<I2=: an C299I<: statements, sin%e s@liteJ e;pe%ts that s@liteJ itsel$ >oul be use to re3e;e%ute the umpe #FL s%ript. #in%e transa%tions are han le via A!. %alls >ith S[*ite7atabase, >e %annot e;e%ute ;8GI= " <63=S3C<I2=: an C299I<: statements via execS[*() >ithout getting a Ineste transa%tionI error. #o, >e skip those t>o statements an e;e%ute everything else, one line at a time. 5he net result* onCreate() takes our ra> #FL an turns it into a table in our on3 evi%e atabase. G$ %ourse, to really use this, you >ill nee to %reate a 7atabaseInstaller" sub%lass, su%h as ConstantsInstaller*
import"android.content.Context: import"android.database.s@lite.S[*ite7atabase: import"android.&til.*og: class"ConstantsInstaller""extends"7atabaseInstaller"4 ""p&blic"ConstantsInstaller(Context"context>"String"name> """""""""""""""""""""""""""S[*ite7atabase.C&rsorKactor+"factor+> """""""""""""""""""""""""""int"version)""4 """"s&per(context>"name>"factor+>"version): ""? "" ""void"!andleInstallError(<-rowable"t)"4 """"*og.e($Constants$>"$8xception"installing"database$>"t): ""? ""02verride ""p&blic"void"onUpgrade(S[*ite7atabase"db>"int"oldVersion>

-$Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

"""""""""""""""""""""""""int"newVersion)"4 """"db.e(ecS0L($7625"<3;*8"IK"8WIS<S"constants$): """"onCreate(db): ""? ?

5he rest o$ this proLe%t is largely i enti%al to the Content5rovider/Constants" sample $rom The Busy Coder's Guide to Android De elopment. Gne possible enhan%ement to 7atabaseInstaller is to %reate our o>n transa%tion aroun the loop o$ execS[*() %alls. 5his >oul improve per$orman%e ramati%ally, as other>ise, ea%h execS[*() %all is its o>n transa%tion. 5he proo$ o$ this is le$t to the rea er as an e;er%ise.

<xamining 7our Eelationships


An roi has a built3in %onta%t manager, integrate >ith the phone ialer. Dou %an >ork >ith the %onta%ts via the Contacts %ontent provi er. )o>ever, %ompare to %ontent provi ers $oun in, say, simpli$ie book e;amples, the Contacts %ontent provi er is rather intimi ating. A$ter all, there are -4 %lasses an 9 inter$a%es all involve in a%%essing this %ontent provi er. 5his se%tion >ill attempt to illustrate some o$ the patterns $or making use o$ Contacts.

Contact Permissions
#in%e %onta%ts are privilege ata, you nee %ertain permissions to >ork >ith them. #pe%i$i%ally, you nee the 6837/C2=<3C<S permission to <uery an e;amine the Contacts %ontent an W6I<8/C2=<3C<S to a , mo i$y, or remove %onta%ts $rom the system. (or e;ample, here is the mani$est $or the 7atabase/Contacts sample appli%ation*
!xml"version#$1.%$"encoding#$&tf'($!) manifest"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$

-$%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""""""pac.age#$com.commonsware.android.database$ """"""android,versionCode#$1$ """"""android,version=ame#$1.%$) "" &ses'permission"android,name#$android.permission.6837/C2=<3C<S$"/) """" application"android,label#$0string/app/name$) """""""" activit+"android,name#$.Contacts7emo$ """"""""""""""""""android,label#$0string/app/name$) """""""""""" intent'filter) """""""""""""""" action"android,name#$android.intent.action.93I=$"/) """""""""""""""" categor+"android,name#$android.intent.categor+.*3D=CB86$"/) """""""""""" /intent'filter) """""""" /activit+) """" /application) /manifest)

Pre3>oined Data
While the atabase un erlying the Contacts %ontent provi er is private, one %an imagine that it has several tables* one $or people, one $or their phone numbers, one $or their email a resses, et%. 5hese are tie together by typi%al atabase relations, most likely -*0, so the phone number an email a ress tables >oul have a $oreign key pointing ba%k to the table %ontaining in$ormation about people. 5o simpli$y a%%essing all o$ this through the %ontent provi er inter$a%e, An roi pre3Loins <ueries against some o$ the tables. (or e;ample, one %an <uery $or phone numbers an get the %onta%t name an other ata along >ith the number, >ithout having to someho> o a Loin operation yoursel$.

The (ample Activity


5he Contacts7emo a%tivity is simply a *ist3ctivit+, though it sports a Spinner" to go along >ith the obligatory *istView*
!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ """"android,orientation#$vertical$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$fill/parent$ """") "" Spinner"android,id#$01id/spinner$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$wrap/content$

-$.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""""android,drawSelector2n<op#$tr&e$ ""/) "" *istView """"android,id#$0android,id/list$ """"android,la+o&t/widt-#$fill/parent$" """"android,la+o&t/-eig-t#$fill/parent$ """"android,drawSelector2n<op#$false$ ""/) /*inear*a+o&t)

5he a%tivity itsel$ sets up a listener on the Spinner an toggles the list o$ in$ormation sho>n in the *istView >hen the Spinner value %hanges*
pac.age"com.commonsware.android.database: import"android.app.*ist3ctivit+: import"android.database.C&rsor: import"android.os.;&ndle: import"android.provider.Contacts: import"android.view.View: import"android.widget.3dapterView: import"android.widget.3rra+3dapter: import"android.widget.*ist3dapter: import"android.widget.SimpleC&rsor3dapter: import"android.widget.Spinner: p&blic"class"Contacts7emo"extends"*ist3ctivit+ ""implements"3dapterView.2nItemSelected*istener"4 ""private"static"StringPQ"options#4$Contact"=ames$> """""""""""""""""""""""""""""""""""$Contact"=ames"U"=&mbers$> """""""""""""""""""""""""""""""""""$Contact"=ames"U"8mail"3ddresses$?: ""private"*ist3dapterPQ"list3dapters#new"*ist3dapterPJQ: ""02verride ""p&blic"void"onCreate(;&ndle"savedInstanceState)"4 """"s&per.onCreate(savedInstanceState): """"setContentView(6.la+o&t.main): """" """"initList&dapters(): """" """"Spinner"spin#(Spinner)findViewById(6.id.spinner): """"spin.set$nItemSelectedListener(t-is): """" """"3rra+3dapter String)"aa#new"3rra+3dapter String)(t-is> """""""""""""""""""""""""""""android.6.la+o&t.simple/spinner/item> """""""""""""""""""""""""""""options): """" """"aa.set"rop"ownViewResource( """"""""""""android.6.la+o&t.simple/spinner/dropdown/item): """"spin.set&dapter(aa): ""? ""

-$$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""p&blic"void"onItemSelected(3dapterView !)"parent> """""""""""""""""""""""""""""""View"v>"int"position>"long"id)"4 """"setList&dapter(list3daptersPpositionQ): ""? "" ""p&blic"void"on-ot!ingSelected(3dapterView !)"parent)"4 """"//"ignore ""? "" ""private"void"initList&dapters()"4 """"list3daptersP%Q#build-ame&dapter(): """"list3daptersP1Q#build !ones&dapter(): """"list3daptersPEQ#buildEmail&dapter(): ""? "" ""private"*ist3dapter"build-ame&dapter()"4 """"StringPQ"562J8C<I2=#new"StringPQ"4""Contacts.5eople./I7> """""""""""""""""""""""""""""""""""""""Contacts.5eopleCol&mns.=398 """""""""""""""""""""""""""""""""""""?: """"C&rsor"c#managed0uery(Contacts.5eople.C2=<8=</D6I> """""""""""""""""""""""""562J8C<I2=>"n&ll>"n&ll> """""""""""""""""""""""""Contacts.5eople.78K3D*</S26</26786): """" """"ret&rn(new"SimpleCursor&dapter(""t-is> """""""""""""""""""""""""""""""""""android.6.la+o&t.simple/list/item/1> """""""""""""""""""""""""""""""""""c> """""""""""""""""""""""""""""""""""new"StringPQ"4 """""""""""""""""""""""""""""""""""""Contacts.5eopleCol&mns.=398 """""""""""""""""""""""""""""""""""?> """""""""""""""""""""""""""""""""""new"intPQ"4 """""""""""""""""""""""""""""""""""""android.6.id.text1 """""""""""""""""""""""""""""""""""?)): ""? "" ""private"*ist3dapter"build !ones&dapter()"4 """"StringPQ"562J8C<I2=#new"StringPQ"4""Contacts.5-ones./I7> """""""""""""""""""""""""""""""""""""""Contacts.5-ones.=398> """""""""""""""""""""""""""""""""""""""Contacts.5-ones.=D9;86 """""""""""""""""""""""""""""""""""""?: """"C&rsor"c#managed0uery(Contacts.5-ones.C2=<8=</D6I> """""""""""""""""""""""""562J8C<I2=>"n&ll>"n&ll> """""""""""""""""""""""""Contacts.5-ones.78K3D*</S26</26786): """" """"ret&rn(new"SimpleCursor&dapter(""t-is> """""""""""""""""""""""""""""""""""android.6.la+o&t.simple/list/item/E> """""""""""""""""""""""""""""""""""c> """""""""""""""""""""""""""""""""""new"StringPQ"4 """""""""""""""""""""""""""""""""""""Contacts.5-ones.=398> """""""""""""""""""""""""""""""""""""Contacts.5-ones.=D9;86 """""""""""""""""""""""""""""""""""?> """""""""""""""""""""""""""""""""""new"intPQ"4 """""""""""""""""""""""""""""""""""""android.6.id.text1> """""""""""""""""""""""""""""""""""""android.6.id.textE """""""""""""""""""""""""""""""""""?)):

-$0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""? "" ""private"*ist3dapter"buildEmail&dapter()"4 """"StringPQ"562J8C<I2=#new"StringPQ"4""Contacts.Contact9et-ods./I7> """""""""""""""""""""""""""""""""""""""Contacts.Contact9et-ods.73<3> """""""""""""""""""""""""""""""""""""""Contacts.5eopleCol&mns.=398 """""""""""""""""""""""""""""""""""""?: """"C&rsor"c#managed0uery(Contacts.Contact9et-ods.C2=<8=</893I*/D6I> """""""""""""""""""""""""562J8C<I2=>"n&ll>"n&ll> """""""""""""""""""""""""Contacts.Contact9et-ods.78K3D*</S26</26786): """" """"ret&rn(new"SimpleCursor&dapter(""t-is> """""""""""""""""""""""""""""""""""android.6.la+o&t.simple/list/item/E> """""""""""""""""""""""""""""""""""c> """""""""""""""""""""""""""""""""""new"StringPQ"4 """""""""""""""""""""""""""""""""""""Contacts.5eopleCol&mns.=398> """""""""""""""""""""""""""""""""""""Contacts.Contact9et-ods.73<3 """""""""""""""""""""""""""""""""""?> """""""""""""""""""""""""""""""""""new"intPQ"4 """""""""""""""""""""""""""""""""""""android.6.id.text1> """""""""""""""""""""""""""""""""""""android.6.id.textE """""""""""""""""""""""""""""""""""?)): ""? ?

When the a%tivity is $irst opene , it sets up three 3dapter obLe%ts, one $or ea%h o$ three perspe%tives on the %onta%ts ata. 5he Spinner simply resets the list to use the 3dapter asso%iate >ith the Spinner value sele%te .

Accessin! People
5he $irst 3dapter sho>s the names o$ all o$ the %onta%ts. #in%e all the in$ormation >e seek is in the %onta%t itsel$, >e %an use the C2=<8=</D6I" provi er, retrieve all o$ the %onta%ts in the e$ault sort or er, an pour them into a SimpleC&rsor3dapter set up to sho> ea%h person on its o>n ro>*
private"*ist3dapter"build-ame&dapter()"4 ""StringPQ"562J8C<I2=#new"StringPQ"4""Contacts.5eople./I7> """""""""""""""""""""""""""""""""""""Contacts.5eopleCol&mns.=398 """""""""""""""""""""""""""""""""""?: ""C&rsor"c#managed0uery(Contacts.5eople.C2=<8=</D6I> """""""""""""""""""""""562J8C<I2=>"n&ll>"n&ll> """""""""""""""""""""""Contacts.5eople.78K3D*</S26</26786): ""ret&rn(new"SimpleCursor&dapter(""t-is> """""""""""""""""""""""""""""""""android.6.la+o&t.simple/list/item/1> """""""""""""""""""""""""""""""""c> """""""""""""""""""""""""""""""""new"StringPQ"4 -$2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

"""""""""""""""""""""""""""""""""""Contacts.5eopleCol&mns.=398 """""""""""""""""""""""""""""""""?> """""""""""""""""""""""""""""""""new"intPQ"4 """""""""""""""""""""""""""""""""""android.6.id.text1 """""""""""""""""""""""""""""""""?)): ?

Assuming you have some %onta%ts in the atabase, they >ill appear >hen you $irst open the Contacts7emo a%tivity, sin%e that is the e$ault perspe%tive*

!igure .3/ The Contacts9emo sample application* sho)ing all contacts

Accessin! Phone 1um#ers


Retrieving a list o$ %onta%ts by their phone number %an be <uerying the C2=<8=</D6I %ontent provi er*
private"*ist3dapter"build !ones&dapter()"4 ""StringPQ"562J8C<I2=#new"StringPQ"4""Contacts.5-ones./I7> """""""""""""""""""""""""""""""""""""Contacts.5-ones.=398> """""""""""""""""""""""""""""""""""""Contacts.5-ones.=D9;86 """""""""""""""""""""""""""""""""""?: ""C&rsor"c#managed0uery(Contacts.5-ones.C2=<8=</D6I> """""""""""""""""""""""562J8C<I2=>"n&ll>"n&ll> """""""""""""""""""""""Contacts.5-ones.78K3D*</S26</26786):

one by

-$3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""ret&rn(new"SimpleCursor&dapter(""t-is> """""""""""""""""""""""""""""""""android.6.la+o&t.simple/list/item/E> """""""""""""""""""""""""""""""""c> """""""""""""""""""""""""""""""""new"StringPQ"4 """""""""""""""""""""""""""""""""""Contacts.5-ones.=398> """""""""""""""""""""""""""""""""""Contacts.5-ones.=D9;86 """""""""""""""""""""""""""""""""?> """""""""""""""""""""""""""""""""new"intPQ"4 """""""""""""""""""""""""""""""""""android.6.id.text1> """""""""""""""""""""""""""""""""""android.6.id.textE """""""""""""""""""""""""""""""""?)): ?

#in%e the

Contacts.5eopleCol&mns an

o%umentation $or Contacts.5-ones sho>s that it in%orporates Contacts.5-onesCol&mns, >e kno> >e %an get the phone number an the %onta%t7s name in one <uery, >hi%h is >hy both are in%lu e in our proLe%tion o$ %olumns to retrieve.

!igure .4/ The Contacts9emo sample application* sho)ing all contacts that have phone numbers

Accessin! Email Addresses


#imilarly, to get a list o$ all the email a resses, >e %an use the C2=<8=</893I*/D6I %ontent provi er, >hi%h in%orporates the
-$4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

an Contacts.5eopleCol&mns, so >e %an get a%%ess to the %onta%t name as >ell as the email a ress itsel$ &73<3'*
Contacts.Contact9et-odsCol&mns
private"*ist3dapter"buildEmail&dapter()"4 ""StringPQ"562J8C<I2=#new"StringPQ"4""Contacts.Contact9et-ods./I7> """""""""""""""""""""""""""""""""""""Contacts.Contact9et-ods.73<3> """""""""""""""""""""""""""""""""""""Contacts.5eopleCol&mns.=398 """""""""""""""""""""""""""""""""""?: ""C&rsor"c#managed0uery(Contacts.Contact9et-ods.C2=<8=</893I*/D6I> """""""""""""""""""""""562J8C<I2=>"n&ll>"n&ll> """""""""""""""""""""""Contacts.Contact9et-ods.78K3D*</S26</26786): ""ret&rn(new"SimpleCursor&dapter(""t-is> """""""""""""""""""""""""""""""""android.6.la+o&t.simple/list/item/E> """""""""""""""""""""""""""""""""c> """""""""""""""""""""""""""""""""new"StringPQ"4 """""""""""""""""""""""""""""""""""Contacts.5eopleCol&mns.=398> """""""""""""""""""""""""""""""""""Contacts.Contact9et-ods.73<3 """""""""""""""""""""""""""""""""?> """""""""""""""""""""""""""""""""new"intPQ"4 """""""""""""""""""""""""""""""""""android.6.id.text1> """""""""""""""""""""""""""""""""""android.6.id.textE """""""""""""""""""""""""""""""""?)): ?

Again, the results are isplaye via a t>o3line SimpleC&rsor3dapter*

!igure .5/ The Contacts9emo sample application* sho)ing all contacts )ith email addresses -$5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

Eummaging Through 7our Phone Eecords


5he Call*og %ontent provi er in An roi gives you a%%ess to the %alls asso%iate >ith your phone* the %alls you pla%e , the %alls you re%eive , an the %alls that you misse . 5his is a mu%h simpler stru%ture than the Contacts %ontent provi er es%ribe in the previous se%tion. 5he %olumns available to you %an be $oun in the Call*og.Calls %lass. 5he %ommonly3use ones in%lu e*
=D9;86* the phone 73<8*

number asso%iate >ith the %all

>hen the %all >as pla%e , in millise%on s3sin%e3the3epo%h $ormat


7D63<I2=* <C58*

ho> long the %all laste , in se%on s

in i%ating i$ the %all >as in%oming, outgoing, or misse by the sto%k ;aseCol&mns, >hi%h

5hese, o$ %ourse, are augmente Call*og.Calls inherits $rom.

#o, $or e;ample, here is a proLe%tion use against the %all log, $rom the Join7emo a%tivity in the 7atabase/JoinC&rsor proLe%t*
private"static"StringPQ"562J8C<I2=#new"StringPQ"4"Call*og.Calls./I7> """"""""""""""""""""""""""""""""""""""""""""""""Call*og.Calls.=D9;86> """"""""""""""""""""""""""""""""""""""""""""""""Call*og.Calls.73<8> """"""""""""""""""""""""""""""""""""""""""""""""Call*og.Calls.7D63<I2= """"""""""""""""""""""""""""""""""""""""""""""?:

)ere is >here >e get a C&rsor on that proLe%tion, >ith the most3re%ent %alls $irst in the list*
C&rsor"c#managed0uery(android.provider.Call*og.Calls.C2=<8=</D6I> """""""""""""""""""""562J8C<I2=>"n&ll>"n&ll> """""""""""""""""""""Call*og.Calls.73<81$"78SC$):

"nlike %onta%ts, the %all log appears unmo i$iable by An roi appli%ations. #o >hile you %an <uery the log, you %annot a your o>n %alls, elete %alls, et%.
-06
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

Also note that, to a%%ess the %all log, you nee permission.

the 6837/C2=<3C<S"

Come Together* Eight @o)


.$ you have multiple tables >ithin a atabase, an you >ant a C&rsor that represents a Loin o$ those tables, you %an a%%omplish that simply through a >ell3%onstru%te <uery. )o>ever, i$ you have multiple atabases, or you >ish to Loin ata in your atabase >ith ata $rom a thir 3party Content5rovider, the Loin be%omes signi$i%antly more i$$i%ult. Dou %annot simply %onstru%t a <uery, sin%e #FLite has no $a%ility &to ay' to <uery a Content5rovider, let alone Loin a Content5rovider7s %ontents >ith those $rom native tables. Gne solution is to o the Loin at the C&rsor itsel$. An roi 7s C&rsors o$$er a $airly vanilla inter$a%e, an An roi even supplies a C&rsorWrapper %lass that %an han le mu%h o$ the e$$ort $or us. .n this se%tion, >e >ill e;amine the use o$ C&rsorWrapper to %reate a JoinC&rsor, blen ing ata $rom a #FLite table >ith that $rom the Call*og. 0ote that the implementation sho>n here is $or illustrative purposes only. .t may su$$er $rom signi$i%ant per$orman%e issues, parti%ularly memory %onsumption, that >oul nee to be a resse in a serious pro u%tion appli%ation. .$ you are intereste in perhaps pursuing an open sour%e proLe%t to implement a better version o$ JoinC&rsor, %onta%t the author. Also note that there is a C&rsorJoiner %lass in the android.database pa%kage in the #@K. A C&rsorJoiner takes t>o C&rsor obLe%ts plus a list o$ key %olumns, using the key %olumns to Loin the C&rsor values together. 5his is more e$$i%ient but some>hat less $le;ible that the implemenation sho>n here.

-0Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

Cursor rapper
As the name suggests, C&rsorWrapper >raps a C&rsor obLe%t. #pe%i$i%ally, C&rsorWrapper implements the C&rsor inter$a%e itsel$ an elegates all o$ the inter$a%e7s %alls to the >rappe C&rsor. Gn the sur$a%e, this seems pointless. A$ter all, i$ C&rsorWrapper simply serves as a pass3through to the C&rsor, >hy not use the un erlying C&rsor ire%tlyJ 5he key is not C&rsorWrapper itsel$, but rather %ustom sub%lasses o$ C&rsorWrapper. Dou %an then overri e %ertain C&rsor metho s, to per$orm >ork in a ition to, or perhaps instea o$, passing the %all to the >rappe C&rsor. .n this %ase, >e >ant to %reate a C&rsorWrapper sub%lass that allo>s us to inLe%t a itional %olumns into the results. 5hese %olumns >ill be the result o$ a Loin operation bet>een a #FLite table an the Call*og. #pe%i$i%ally, the @atabaseQ+oinCursor proLe%t a s I%all notesI M a blo%k o$ te;t about a spe%i$i% %all one ma e. Dou %oul use this %on%ept in a %onta%t management system, $or e;ample, to annotate >hat all >as is%usse in a %all or other>ise o%ument the %all itsel$. #in%e Call*og is not mo i$iable an has no $iel $or I%all notesI any>ay, >e %annot store su%h notes in the Call*og. .nstea , >e store those notes in a %allRnotes #FLite table, mapping the Call*og ro> /id to the note. (or simpli%ity, this e;ample >ill assume that there are 0 or - notes per %all, not several. 5hat allo>s the JoinC&rsor to simply inLe%t the %all note into the Call*og C&rsor results, >ithout having to >orry about ealing >ith several possible notes. We o, ho>ever, nee to eal >ith the %ase >here the %all oes not yet have a note.

$mplementin! a >oinCursor
A JoinC&rsor is a relatively %omple; %lass. #ome o$ that %omple;ity is ue to repeate boilerplate %o e, an some is ue to the problem being solve .
-0%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

What >e nee the JoinC&rsor to o is*


Gverri e C&rsor3relate metho s that involve the %olumns Che%k to see i$ there is a note $or the %urrent ro> A Lust the results o$ the metho to a%%omo ate the possibility &or reality' o$ a note

Dou %an see an implementation o$ this in the JoinC&rsor %lass in the 7atabase/JoinC&rsor proLe%t*
import"android.content.ContentVal&es: import"android.database.C&rsor: import"android.database.C&rsorWrapper: import"Aava.&til.*in.edBas-9ap: import"Aava.&til.9ap: class"JoinC&rsor"extends"C&rsorWrapper"4 ""private"I/JoinBandler"Aoin#n&ll: ""private"JoinCac-e"cac-e#new"JoinCac!e(1%%): "" ""JoinCursor(C&rsor"main>"I/JoinBandler"Aoin)"4 """"s&per(main): """" """"t-is.Aoin#Aoin: ""? "" ""p&blic"int"getColumnCount()"4 """"ret&rn(s&per.getColumnCount()1Aoin.getColumn-ames().lengt-): ""? "" ""p&blic"int"getColumnInde((String"col&mn=ame)"4 """"for"(int"i#%:i Aoin.getColumn-ames().lengt-:i11)"4 """"""if"(col&mn=ame.equals(Aoin.getColumn-ames()PiQ))"4 """"""""ret&rn(s&per.getColumnCount()1i): """"""? """"? """" """"ret&rn(s&per.getColumnInde((col&mn=ame)): ""? "" ""p&blic"int"getColumnInde($r+!row(String"col&mn=ame)"4 """"for"(int"i#%:i Aoin.getColumn-ames().lengt-:i11)"4 """"""if"(col&mn=ame.equals(Aoin.getColumn-ames()PiQ))"4 """"""""ret&rn(s&per.getColumnCount()1i): """"""? """"? """" """"ret&rn(s&per.getColumnInde($r+!row(col&mn=ame)): ""?

-0.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

"" ""p&blic"String"getColumn-ame(int"col&mnIndex)"4 """"if"(col&mnIndex)#s&per.getColumnCount())"4 """"""ret&rn(Aoin.getColumn-ames()Pcol&mnIndex's&per.getColumnCount()Q): """"? """" """"ret&rn(s&per.getColumn-ame(col&mnIndex)): ""? "" ""p&blic"b+tePQ"getBlob(int"col&mnIndex)"4 """"if"(col&mnIndex)#s&per.getColumnCount())"4 """"""ContentVal&es"extras#cac-e.get(Aoin.getCac!e#ey(t-is)): """"""int"offset#col&mnIndex's&per.getColumnCount(): """""" """"""ret&rn(extras.get&sByte&rray(Aoin.getColumn-ames()PoffsetQ)): """"? """" """"ret&rn(s&per.getBlob(col&mnIndex)): ""? "" ""p&blic"do&ble"get"ouble(int"col&mnIndex)"4 """"if"(col&mnIndex)#s&per.getColumnCount())"4 """"""ContentVal&es"extras#cac-e.get(Aoin.getCac!e#ey(t-is)): """"""int"offset#col&mnIndex's&per.getColumnCount(): """""" """"""ret&rn(extras.get&s"ouble(Aoin.getColumn-ames()PoffsetQ)): """"? """" """"ret&rn(s&per.get"ouble(col&mnIndex)): ""? "" ""p&blic"float"get'loat(int"col&mnIndex)"4 """"if"(col&mnIndex)#s&per.getColumnCount())"4 """"""ContentVal&es"extras#cac-e.get(Aoin.getCac!e#ey(t-is)): """"""int"offset#col&mnIndex's&per.getColumnCount(): """""" """"""ret&rn(extras.get&s'loat(Aoin.getColumn-ames()PoffsetQ)): """"? """" """"ret&rn(s&per.get'loat(col&mnIndex)): ""? "" ""p&blic"int"getInt(int"col&mnIndex)"4 """"if"(col&mnIndex)#s&per.getColumnCount())"4 """"""ContentVal&es"extras#cac-e.get(Aoin.getCac!e#ey(t-is)): """"""int"offset#col&mnIndex's&per.getColumnCount(): """""" """"""ret&rn(extras.get&sInteger(Aoin.getColumn-ames()PoffsetQ)): """"? """" """"ret&rn(s&per.getInt(col&mnIndex)): ""? "" ""p&blic"long"getLong(int"col&mnIndex)"4

-0$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""""if"(col&mnIndex)#s&per.getColumnCount())"4 """"""ContentVal&es"extras#cac-e.get(Aoin.getCac!e#ey(t-is)): """"""int"offset#col&mnIndex's&per.getColumnCount(): """""" """"""ret&rn(extras.get&sLong(Aoin.getColumn-ames()PoffsetQ)): """"? """" """"ret&rn(s&per.getLong(col&mnIndex)): ""? "" ""p&blic"s-ort"getS!ort(int"col&mnIndex)"4 """"if"(col&mnIndex)#s&per.getColumnCount())"4 """"""ContentVal&es"extras#cac-e.get(Aoin.getCac!e#ey(t-is)): """"""int"offset#col&mnIndex's&per.getColumnCount(): """""" """"""ret&rn(extras.get&sS!ort(Aoin.getColumn-ames()PoffsetQ)): """"? """" """"ret&rn(s&per.getS!ort(col&mnIndex)): ""? "" ""p&blic"String"getString(int"col&mnIndex)"4 """"if"(col&mnIndex)#s&per.getColumnCount())"4 """"""ContentVal&es"extras#cac-e.get(Aoin.getCac!e#ey(t-is)): """"""int"offset#col&mnIndex's&per.getColumnCount(): """""" """"""ret&rn(extras.get&sString(Aoin.getColumn-ames()PoffsetQ)): """"? """" """"ret&rn(s&per.getString(col&mnIndex)): ""? "" ""p&blic"boolean"is-ull(int"col&mnIndex)"4 """"if"(col&mnIndex)#s&per.getColumnCount())"4 """"""ContentVal&es"extras#cac-e.get(Aoin.getCac!e#ey(t-is)): """"""int"offset#col&mnIndex's&per.getColumnCount(): """""" """"""ret&rn(extras.get(Aoin.getColumn-ames()PoffsetQ)##n&ll): """"? """" """"ret&rn(s&per.is-ull(col&mnIndex)): ""? "" ""p&blic"boolean"requery()"4 """"cac-e.clear(): """" """"ret&rn(s&per.requery()): ""? "" ""class"JoinCac-e"extends"*in.edBas-9ap String>"ContentVal&es)"4 """"private"int"capacit+#1%%: """" """"JoinCac!e(int"capacit+)"4 """"""s&per(capacit+11>"1.1f>"tr&e):

-00
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""""""t-is.capacit+#capacit+: """"? """" """"protected"boolean"removeEldestEntry(8ntr+ String>"ContentVal&es)"eldest)"4 """"""ret&rn(si.e())capacit+): """"? """" """"ContentVal&es"get(String".e+)"4 """"""ContentVal&es"res&lt#s&per.get(.e+): """""" """"""if"(res&lt##n&ll)"4 """"""""res&lt#Aoin.getJoin(JoinC&rsor.t-is): """"""""put(.e+>"res&lt): """"""? """""" """"""ret&rn(res&lt): """"? ""? ?

JoinC&rsor, >hen instantiate , I/JoinBandler instan%e. 5he Loin

%olumns $or a given ro>*

gets both the C&rsor to >rap an an han ler is responsible $or getting the e;tra

import"android.content.ContentVal&es: import"android.database.C&rsor: import"Aava.&til.9ap: p&blic"interface"I/JoinBandler"4 ""StringPQ"getColumn-ames(): ""String"getCac!e#ey(C&rsor"c): ""ContentVal&es"getJoin(C&rsor"c): ?

Most o$ JoinC&rsor is then using the I/JoinBandler in$ormation to a Lust the results o$ various C&rsor metho s. (or e;ample*

returns the sum o$ the C&rsor7s %olumn %ount an the number o$ e;tra %olumns returne by the Loin han ler
getCol&mnCo&nt() getCol&mnIndex()

an kin nee to sear%h through the Loin han ler7s %olumns as >ell as the C&rsor7s to $in the mat%h, i$ any
getInt(), is=&ll(), both the C&rsor an

an kin nee to support retrieving values $rom the Loin han ler

-02
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

5o improve per$orman%e, JoinC&rsor keeps a %a%he o$ the e;tra values $or re<ueste ro>s, using an ILR" %a%heI3style *in.edBas-9ap an an inner JoinCac-e %lass. 5he JoinCac-e keeps the ContentVal&es returne by I/JoinBandler on a getJoin() %all, representing the e;tra %olumns &i$ any' $or that parti%ular C&rsor ro>. #in%e >e are %a%hing ata, ho>ever, >e nee to $lush that %a%he sometimesO in this %ase, >e overri e re@&er+() to $lush the %a%he i$ the C&rsor itsel$ is being proa%tively up ate .

%sin! a >oinCursor
5o use a JoinC&rsor, o$ %ourse, you nee an implementation o$ I/JoinBandler, su%h as this one $rom the Join7emo a%tivity*
I/JoinBandler"Aoin#new"I1Join*andler()"4 ""StringPQ"col&mns#4=2<8/I7>"=2<8?: ""p&blic"StringPQ"getColumn-ames()"4 """"""ret&rn(col&mns): ""? ""p&blic"String"getCac!e#ey(C&rsor"c)"4 """"""ret&rn(String.value$f(c.getInt(c.getColumnInde((Call*og.Calls./I7)))): ""? ""p&blic"ContentVal&es"getJoin(C&rsor"c)"4 """"StringPQ"args#4getCac!e#ey(c)?: """"C&rsor"A#get"b().raw0uery($S8*8C<"/I7>"note"K629"call/notes"WB868" call/id#!$>"args): """"ContentVal&es"res&lt#new"ContentValues(): """"A.move+o'irst(): """"if"(A.is&fterLast())"4 """"""res&lt.put(col&mnsP%Q>"'1): """"""res&lt.put(col&mnsP1Q>"(String)n&ll): """"? """"else"4 """"""res&lt.put(col&mnsP%Q>"A.getInt(%)): """"""res&lt.put(col&mnsP1Q>"A.getString(1)): """"? """"A.close(): """"ret&rn(res&lt): ""? ?:

-03
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

5he %olumns are a $i;e pair &the note7s .@ an the note itsel$'. 5hese are retrieve via getJoin() $rom the call/notes #FLite table. 5he %all notes themselves are keye by the %all7s o>n /id, >hi%h is also use as the key $or the JoinC&rsor7s %a%he o$ results. 5he net e$$e%t is that >e only ever retrieve a note on%e $or a given %all, at least until a re@&er+(). An , i$ there is no note $or the %all, >e use a n&ll note to in i%ate that >e are, in ee , note3 $ree $or this %all. 5he note in$ormation is then use by our C&rsor3dapter sub%lass &Call5l&s3dapter' an its asso%iate ViewWrapper, also $oun in the Join7emo" a%tivity*
class"Call5l&s3dapter"extends"C&rsor3dapter"4 ""Call lus&dapter(C&rsor"c)"4 """"s&per(Join7emo.t-is>"c): ""? ""02verride ""p&blic"void"bindView(View"row>"Context"ctxt> """""""""""""""""""""""C&rsor"c)"4 """"ViewWrapper"wrapper#(ViewWrapper)row.get+ag(): """"wrapper.update(c): ""? ""02verride ""p&blic"View"newView(Context"ctxt>"C&rsor"c> """""""""""""""""""""""ViewGro&p"parent)"4 """"*a+o&tInflater"inflater#getLayoutInflater(): """"View"row#inflater.inflate(6.la+o&t.row>"n&ll): """"ViewWrapper"wrapper#new"View,rapper(row): """"row.set+ag(wrapper): """"wrapper.update(c): """"ret&rn(row): ""? ? class"ViewWrapper"4 ""View"base: ""<extView"n&mber#n&ll: ""<extView"d&ration#n&ll: ""<extView"time#n&ll: ""ImageView"icon#n&ll: ""View,rapper(View"base)"4 """"t-is.base#base:

-04
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""? ""<extView"get-umber()"4 """"if"(n&mber##n&ll)"4 """"""n&mber#(<extView)base.findViewById(6.id.n&mber): """"? """"ret&rn(n&mber): ""? ""<extView"get"uration()"4 """"if"(d&ration##n&ll)"4 """"""d&ration#(<extView)base.findViewById(6.id.d&ration): """"? """"ret&rn(d&ration): ""? ""<extView"get+ime()"4 """"if"(time##n&ll)"4 """"""time#(<extView)base.findViewById(6.id.time): """"? """"ret&rn(time): ""? ""ImageView"getIcon()"4 """"if"(icon##n&ll)"4 """"""icon#(ImageView)base.findViewById(6.id.note): """"? """"ret&rn(icon): ""? ""void"update(C&rsor"c)"4 """"get-umber().set+e(t(c.getString(c.getColumnInde((Call*og.Calls.=D9;86))): """"get+ime().set+e(t(K2693<.format(c.getInt(c.getColumnInde((Call*og.Calls.73<8 )))): """"get"uration().set+e(t(c.getString(c.getColumnInde((Call*og.Calls.7D63<I2=)) 1$"seconds$): """"String"note#c.getString(c.getColumnInde((=2<8)): """"if"(noteN#n&ll"UU"note.lengt!())%)"4 """"""getIcon().setVisibility(View.VISI;*8): """"? """"else"4 """"""getIcon().setVisibility(View.G2=8): """"? ""? ?

-05
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

Mostly, >e are populating a ro> to go in a *istView base o$$ o$ the %all ata &e.g., uration'. )o>ever, i$ there is a non3n&ll note, >e also isplay an i%on in the ro>, in i%ating that a note is available. 5he Join7emo a%tivity itsel$ is Lust a *ist3ctivit+, using the Call5l&s3dapter" an the Call*og C&rsor >e sa> in the previous se%tion*
import"android.app.*ist3ctivit+: import"android.content.ContentVal&es: import"android.content.Context: import"android.content.Intent: import"android.database.C&rsor: import"android.database.s@lite.S[*ite7atabase: import"android.os.;&ndle: import"android.provider.Call*og: import"android.view.View: import"android.view.ViewGro&p: import"android.view.*a+o&tInflater: import"android.widget.C&rsor3dapter: import"android.widget.ImageView: import"android.widget.*istView: import"android.widget.<extView: import"Aava.text.Simple7ateKormat: p&blic"class"Join7emo"extends"*ist3ctivit+"4 ""p&blic"static"String"=2<8#$/=2<8$: ""private"static"String"=2<8/I7#$=2<8/I7$: ""private"static"StringPQ"562J8C<I2=#new"StringPQ"4"Call*og.Calls./I7> """"""""""""""""""""""""""""""""""""""""""""""""""Call*og.Calls.=D9;86> """"""""""""""""""""""""""""""""""""""""""""""""""Call*og.Calls.73<8> """"""""""""""""""""""""""""""""""""""""""""""""""Call*og.Calls.7D63<I2= """"""""""""""""""""""""""""""""""""""""""""""""?: ""private"static"Simple7ateKormat"K2693<#new"Simple"ate'ormat($99/d"-,mm"a$): ""private"C&rsor"c&rsor#n&ll: ""private"int"noteCol&mn#'1: ""private"int"idCol&mn#'1: ""private"int"noteIdCol&mn#'1: ""private"S[*ite7atabase"db#n&ll: "" ""02verride ""p&blic"void"onCreate(;&ndle"savedInstanceState)"4 """"s&per.onCreate(savedInstanceState): """" """"C&rsor"c#managed0uery(android.provider.Call*og.Calls.C2=<8=</D6I> """""""""""""""""""""""""562J8C<I2=>"n&ll>"n&ll> """""""""""""""""""""""""Call*og.Calls.73<81$"78SC$): """" """"c&rsor#new"JoinCursor(c>"Aoin): """"noteCol&mn#c&rsor.getColumnInde((=2<8): """"idCol&mn#c&rsor.getColumnInde((Call*og.Calls./I7): """"noteIdCol&mn#c&rsor.getColumnInde((=2<8/I7):

-26
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""""setList&dapter(new"Call lus&dapter(c&rsor)): ""? "" ""02verride ""p&blic"void"onResume()"4 """"s&per.onResume(): """" """"c&rsor.requery(): ""? "" ""02verride ""p&blic"void"on"estroy()"4 """"s&per.on"estroy(): """" """"if"(dbN#n&ll)"4 """"""db.close(): """"? ""? "" ""02verride ""protected"void"onListItemClic)(*istView"l>"View"v> """""""""""""""""""""""""""""""""int"position>"long"id)"4 """"c&rsor.move+o osition(position): """" """"String"note#c&rsor.getString(noteCol&mn): """" """"if"(note##n&ll"YY"note.lengt!()##%)"4 """"""Intent"i#new"Intent(t-is>"=ote8ditor.class): """""" """"""i.putE(tra(=2<8>"note): """"""i.putE(tra($call/id$>"c&rsor.getInt(idCol&mn)): """"""i.putE(tra($note/id$>"c&rsor.getInt(noteIdCol&mn)): """"""start&ctivity'orResult(i>"1): """"? """"else"4 """"""Intent"i#new"Intent(t-is>"=ote3ctivit+.class): """""" """"""i.putE(tra(=2<8>"note): """"""start&ctivity(i): """"? ""? "" ""02verride ""protected"void"on&ctivityResult(int"re@&estCode> """""""""""""""""""""""""""""""""""int"res&ltCode> """""""""""""""""""""""""""""""""""Intent"data)"4 """"String"note#data.getStringE(tra(=2<8): """" """"if"(noteN#n&ll)"4 """"""int"noteId#data.getIntE(tra(=2<8/I7>"'1): """"""ContentVal&es"cv#new"ContentValues(): """""" """"""cv.put($note$>"note): """"""

-2Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""""""if"(noteId##'1)"4 """"""""int"callId#data.getIntE(tra($call/id$>"'1): """""""" """"""""cv.put($call/id$>"callId): """""""" """"""""get"b().insert$r+!row($call/notes$>"$/id$>"cv): """"""? """"""else"4 """"""""StringPQ"args#4String.value$f(noteId)?: """""""" """"""""get"b().update($call/notes$>"cv>"$/I7$>"args): """"""? """"? ""? "" ""S[*ite7atabase"get"b()"4 """"if"(db##n&ll)"4 """"""db#(new"-otesInstaller(Join7emo.t-is)).get,ritable"atabase(): """"? """" """"ret&rn(db): ""? "" ""I/JoinBandler"Aoin#new"I1Join*andler()"4 """"StringPQ"col&mns#4=2<8/I7>"=2<8?: """" """"p&blic"StringPQ"getColumn-ames()"4 """"""""ret&rn(col&mns): """"? """" """"p&blic"String"getCac!e#ey(C&rsor"c)"4 """"""""ret&rn(String.value$f(c.getInt(c.getColumnInde((Call*og.Calls./I7)))): """"? """" """"p&blic"ContentVal&es"getJoin(C&rsor"c)"4 """"""StringPQ"args#4getCac!e#ey(c)?: """"""C&rsor"A#get"b().raw0uery($S8*8C<"/I7>"note"K629"call/notes"WB868" call/id#!$>"args): """"""ContentVal&es"res&lt#new"ContentValues(): """""" """"""A.move+o'irst(): """""" """"""if"(A.is&fterLast())"4 """"""""res&lt.put(col&mnsP%Q>"'1): """"""""res&lt.put(col&mnsP1Q>"(String)n&ll): """"""? """"""else"4 """"""""res&lt.put(col&mnsP%Q>"A.getInt(%)): """"""""res&lt.put(col&mnsP1Q>"A.getString(1)): """"""? """""" """"""A.close(): """""" """"""ret&rn(res&lt):

-2%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

""""? ""?: "" ""class"Call5l&s3dapter"extends"C&rsor3dapter"4 """"Call lus&dapter(C&rsor"c)"4 """"""s&per(Join7emo.t-is>"c): """"? """" """"02verride """"p&blic"void"bindView(View"row>"Context"ctxt> """""""""""""""""""""""""C&rsor"c)"4 """"""ViewWrapper"wrapper#(ViewWrapper)row.get+ag(): """""" """"""wrapper.update(c): """"? """" """"02verride """"p&blic"View"newView(Context"ctxt>"C&rsor"c> """""""""""""""""""""""""ViewGro&p"parent)"4 """"""*a+o&tInflater"inflater#getLayoutInflater(): """""" """"""View"row#inflater.inflate(6.la+o&t.row>"n&ll): """"""ViewWrapper"wrapper#new"View,rapper(row): """""" """"""row.set+ag(wrapper): """"""wrapper.update(c): """""" """"""ret&rn(row): """"? ""? ""class"ViewWrapper"4 """"View"base: """"<extView"n&mber#n&ll: """"<extView"d&ration#n&ll: """"<extView"time#n&ll: """"ImageView"icon#n&ll: """" """"View,rapper(View"base)"4 """"""t-is.base#base: """"? """" """"<extView"get-umber()"4 """"""if"(n&mber##n&ll)"4 """"""""n&mber#(<extView)base.findViewById(6.id.n&mber): """"""? """""" """"""ret&rn(n&mber): """"? """" """"<extView"get"uration()"4 """"""if"(d&ration##n&ll)"4 """"""""d&ration#(<extView)base.findViewById(6.id.d&ration): """"""?

-2.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

"""""" """"""ret&rn(d&ration): """"? """" """"<extView"get+ime()"4 """"""if"(time##n&ll)"4 """"""""time#(<extView)base.findViewById(6.id.time): """"""? """""" """"""ret&rn(time): """"? """" """"ImageView"getIcon()"4 """"""if"(icon##n&ll)"4 """"""""icon#(ImageView)base.findViewById(6.id.note): """"""? """""" """"""ret&rn(icon): """"? """" """"void"update(C&rsor"c)"4 """"""get-umber().set+e(t(c.getString(c.getColumnInde((Call*og.Calls.=D9;86))): """"""get+ime().set+e(t(K2693<.format(c.getInt(c.getColumnInde((Call*og.Calls.73 <8)))): """"""get"uration().set+e(t(c.getString(c.getColumnInde((Call*og.Calls.7D63<I2=) )1$"seconds$): """""" """"""String"note#c.getString(c.getColumnInde((=2<8)): """""" """"""if"(noteN#n&ll"UU"note.lengt!())%)"4 """"""""getIcon().setVisibility(View.VISI;*8): """"""? """"""else"4 """"""""getIcon().setVisibility(View.G2=8): """"""? """"? ""? ?

When the user %li%ks on a ro>, epen ing on >hether there is a note, >e either spa>n a =ote8ditor &to %reate a ne> note' or a =ote3ctivit+ &to vie> an e;isting note'. .n a real implementation o$ this $un%tionality, o$ %ourse, >e >oul allo> users to e it e;isting notes, elete notes, an the like, all o$ >hi%h is skippe in this simpli$ie sample appli%ation. ,isually, the a%tivity oes not look like mu%h, but you >ill see the note i%on on %alls %ontaining notes &>ith some phone numbers smu ge $or priva%y'*

-2$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

9atabases and Content Providers

!igure $6/ The BoinCursor sample application* sho)ing one call )ith a note

-20
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 11

=andling System <vents

.$ you have ever looke at the list o$ available Intent a%tions in the #@K o%umentation $or the Intent %lass, you >ill see that there are lots o$ possible a%tions. Lots an lots an lots o$ possible a%tions. 5here are even a%tions that are not liste in that spot in the o%umentation, but are s%attere throughout the rest o$ the #@K o%umentation. 5he vast maLority o$ these you >ill never raise yoursel$. .nstea , they are broa %ast by An roi , to signi$y %ertain system events that have o%%urre an that you might >ant to take note o$, i$ they a$$e%t the operation o$ your appli%ation. 5his %hapter e;amines a $e> o$ these, to give you the sense o$ >hat is possible an ho> to make use o$ these sorts o$ events.

'et 8oving* !irst Thing


A popular re<uest is to have a servi%e get %ontrol >hen the po>ere on. evi%e is

-23
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

=andling System <vents

5his is oable but some>hat angerous, in that too many on3boot re<uests slo> o>n the evi%e startup an may make things sluggish $or the user. Moreover, the more servi%es that are running all the time, the >orse the evi%e per$orman%e >ill be. A better pattern is to get %ontrol on boot to arrange $or a servi%e to o something perio i%ally using the 3larm9anager or via other system events. .n this se%tion, >e >ill e;amine the on3boot portion o$ the problem M in the ne;t %hapter, >e >ill investigate 3larm9anager an ho> it %an keep servi%es a%tive yet not ne%essarily resi ent in memory all the time.

The Permission
.n or er to be noti$ie >hen the evi%e has %omplete is system boot pro%ess, you >ill nee to re<uest the 68C8IV8/;22</C295*8<87 permission. Without this, even i$ you arrange to re%eive the boot broa %ast .ntent, it >ill not be ispat%he to your re%eiver. As the An roi o%umentation es%ribes it*

Thou"h holdin" this permission does not ha e any security implications$ it can ha e a ne"ati e impact on the user e%pe& rience by increasin" the amount o' time it takes the system to start and allowin" applications to ha e themsel es run& nin" without the user bein" aware o' them. As such$ you must e%plicitly declare your use o' this 'acility to make that isible to the user.

The Receiver Element


5here are t>o >ays you %an re%eive a broa %ast Intent. Gne is to use $rom an e;isting 3ctivit+, Service, or Content5rovider. 5he other is to register your interest in the Intent in the mani$est in the $orm o$ a receiver) element*
register6eceiver()

-24
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

=andling System <vents

!xml"version#$1.%$"encoding#$&tf'($!) manifest"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ """"""pac.age#$com.commonsware.android.s+sevents.boot$ """"""android,versionCode#$1$ """"""android,version=ame#$1.%$) "" &ses'permission"android,name#$android.permission.68C8IV8/;22</C295*8<87$"/) """" application"android,label#$0string/app/name$) """""""" receiver"android,name#$.2n;oot6eceiver$) """""""""""" intent'filter) """""""""""""""" action"android,name#$android.intent.action.;22</C295*8<87$"/) """""""""""" /intent'filter) """""""" /receiver) """" /application) /manifest)

5he above 3ndroid9anifest.xml, $rom the S+stem8vents/2n;oot sample proLe%t, sho>s that >e have registere a broa %ast re%eiver name 2n;oot6eceiver, set to be given %ontrol >hen the android.intent.action.;22</C295*8<87 .ntent is broa %ast. .n this %ase, >e have no %hoi%e but to implement our re%eiver this >ay M by the time any o$ our other %omponents &e.g., an 3ctivit+' >ere to get %ontrol an be able to %all register6eceiver(), the ;22</C295*8<87 Intent >ill be long gone.

The Receiver $mplementation


0o> that >e have tol An roi that >e >oul like to be noti$ie >hen the boot has %omplete , an given that >e have been grante permission to o so by the user, >e no> nee to a%tually o something to re%eive the .ntent. 5his is a simple matter o$ %reating a ;roadcast6eceiver, su%h as seen in the 2n;ootCompleted implementation sho>n belo>*
pac.age"com.commonsware.android.s+sevents.boot: import"android.content.;roadcast6eceiver: import"android.content.Context: import"android.content.Intent: import"android.&til.*og: p&blic"class"2n;oot6eceiver"extends";roadcast6eceiver"4 ""02verride ""p&blic"void"onReceive(Context"context>"Intent"intent)"4 """"*og.d($2n;oot6eceiver$>"$Bi>"9omN$):

-25
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

=andling System <vents

""? ?

A ;roadcast6eceiver is not a Context, an so it gets passe a suitable Context" obLe%t in on6eceive() to use $or a%%essing resour%es an the like. 5he on6eceive() metho also is passe the Intent that %ause our ;roadcast6eceiver to be %reate , in %ase there are Ie;trasI >e nee to pull out &none in this %ase'. .n on6eceive(), >e %an o >hatever >e >ant, subLe%t to some limitations* -. We are not a Context, like an 3ctivit+, so >e %annot mo i$y a ". or anything su%h as that

2. .$ >e >ant to o anything signi$i%ant, it is better to elegate that logi% to a servi%e that >e start $rom here &e.g., %alling startService()" on the supplie Context' rather than a%tually oing it here, sin%e ;roadcast6eceiver implementations nee to be $ast ?. We %annot start any ba%kgroun threa s, ire%tly or in ire%tly, sin%e the ;roadcast6eceiver gets is%ar e as soon as on6eceive()" returns .n this %ase, >e simply log the $a%t that >e got %ontrol. .n the ne;t %hapter, >e >ill see >hat else >e %an o at boot time, to ensure one o$ our servi%es gets %ontrol later on as nee e . 5o test this, install it on an emulator &or evi%e', shut o>n the emulator, then restart it.

+ Sense a Connection Bet)een 1s///


8enerally speaking, An roi appli%ations o not %are >hat sort o$ .nternet %onne%tion is being use M ?8, 8!R#, Wi(i, lots o$ traine %arrier pigeons, or >hatever. #o long as there is an .nternet %onne%tion, the appli%ation is happy.

-36
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

=andling System <vents

#ometimes, though, you may spe%i$i%ally >ant Wi(i. 5his >oul be true i$ your appli%ation is ban >i th3intensive an you >ant to ensure that, shoul Wi(i stop being available, you %ut ba%k on your >ork so as not to %onsume too mu%h ?8Q8!R# ban >i th, >hi%h is usually subLe%t to some sort o$ %ap or metering. 5here is an android.net.wifi.WIKI/S<3<8/CB3=G87 Intent that >ill be broa %ast, as the name suggests, >henever the state o$ the Wi(i %onne%tion %hanges. Dou %an arrange to re%eive this broa %ast an take appropriate steps >ithin your appli%ation. 5his Intent re<uires no spe%ial permission, unlike the ;22</C295*8<87 .ntent $rom the previous se%tion. )en%e, all you nee to o is register a ;roadcast6eceiver $or android.net.wifi.WIKI/S<3<8/CB3=G87, either via register6eceiver(), or via the receiver) element in 3ndroid9anifest.xml, su%h as the one sho>n belo>, $rom the S+stem8vents/2nWiKiC-ange sample proLe%t*
!xml"version#$1.%$"encoding#$&tf'($!) manifest"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ """"""pac.age#$com.commonsware.android.s+sevents.wifi$ """"""android,versionCode#$1$ """"""android,version=ame#$1.%$) """" application"android,label#$0string/app/name$) """""""" receiver"android,name#$.2nWiKiC-ange6eceiver$) """""""""""" intent'filter) """""""""""""""" action"android,name#$android.net.wifi.WIKI/S<3<8/CB3=G87$"/) """""""""""" /intent'filter) """""""" /receiver) """" /application) /manifest)

All >e o in the mani$est is tell An roi to %reate an 2nWiKiC-ange6eceiver" obLe%t >hen a android.net.wifi.WIKI/S<3<8/CB3=G87 Intent is broa %ast, so the re%eiver %an o something use$ul. .n the %ase o$ 2nWiKiC-ange6eceiver, it e;amines the value o$ the 8W<63/WIKI/S<3<8 Ie;traI in the supplie Intent an logs an appropriate message*

-3Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

=andling System <vents

pac.age"com.commonsware.android.s+sevents.wifi: import"android.content.;roadcast6eceiver: import"android.content.Context: import"android.content.Intent: import"android.net.wifi.Wifi9anager: import"android.&til.*og: p&blic"class"2nWiKiC-ange6eceiver"extends";roadcast6eceiver"4 ""02verride ""p&blic"void"onReceive(Context"context>"Intent"intent)"4 """"int"state#intent.getIntE(tra(Wifi9anager.8W<63/WIKI/S<3<8>"'1): """"String"msg#n&ll: """" """"switc-"(state)"4 """"""case"Wifi9anager.WIKI/S<3<8/7IS3;*87, """"""""msg#$is"disabled$: """"""""brea.: """""" """"""case"Wifi9anager.WIKI/S<3<8/7IS3;*I=G, """"""""msg#$is"disabling$: """"""""brea.: """""" """"""case"Wifi9anager.WIKI/S<3<8/8=3;*87, """"""""msg#$is"enabled$: """"""""brea.: """""" """"""case"Wifi9anager.WIKI/S<3<8/8=3;*I=G, """"""""msg#$is"enabling$: """"""""brea.: """""" """"""case"Wifi9anager.WIKI/S<3<8/D=V=2W=", """"""""msg#$-as"an"error$: """"""""brea.: """""" """"""defa&lt, """"""""msg#$is"acting"strangel+$: """"""""brea.: """"? """" """"if"(msgN#n&ll)"4 """"""*og.d($2nWiKiC-anged$>"$WiKi"$1msg): """"? ""? ?

5he 8W<63/WIKI/S<3<8 Ie;traI tells you >hat the state has be%ome &e.g., >e are no> isabling or are no> isable ', so you %an take appropriate steps in your appli%ation.

-3%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

=andling System <vents

0ote that, to test this, you >ill nee an a%tual An roi evi%e, as the emulator oes not spe%i$i%ally support simulating Wi(i %onne%tions.

!eeling 9rained
Gne theme >ith system events is to use them to help make your users happier by re u%ing your impa%ts on the evi%e >hile the evi%e is not in a great state. .n the pre%e ing se%tion, >e sa> ho> you %oul $in out >hen Wi(i >as isable , so you might not use as mu%h ban >i th >hen on ?8Q8!R#. )o>ever, not every appli%ation uses so mu%h ban >i th as to make this optimiCation >orth>hile. )o>ever, most appli%ations are impa%te by battery li$e. @ea batteries run no apps. #o >hether you are implementing a battery monitor or simply >ant to is%ontinue ba%kgroun operations >hen the battery gets lo>, you may >ish to $in out ho> the battery is oing. 5here is an 3C<I2=/;3<<86C/CB3=G87 Intent that gets broa %ast as the battery status %hanges, both in terms o$ %harge &e.g., 20P %harge ' an %harging &e.g., the evi%e is no> plugge into AC po>er'. Dou simply nee to register to re%eive this Intent >hen it is broa %ast, then take appropriate steps. Gne o$ the limitations o$ 3C<I2=/;3<<86C/CB3=G87 is that you have to use register6eceiver() to set up a ;roadcast6eceiver to get this Intent >hen broa %ast. Dou %annot use a mani$est3 e%lare re%eiver as sho>n in the pre%e ing t>o se%tions. .n S+stem8vents/2n;atter+, you >ill $in a layout %ontaining a 5rogress;ar, a <extView, an an ImageView, to serve as a battery monitor*
!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,orientation#$vertical$ ""android,la+o&t/widt-#$fill/parent$ ""android,la+o&t/-eig-t#$fill/parent$

-3.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

=andling System <vents

"") "" 5rogress;ar"android,id#$01id/bar$ """"st+le#$!android,attr/progress;arSt+leBoriIontal$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$wrap/content$"/) "" *inear*a+o&t """"android,orientation#$-oriIontal$ """"android,la+o&t/widt-#$fill/parent$ """"android,la+o&t/-eig-t#$wrap/content$ """") """" <extView"android,id#$01id/level$ """"""android,la+o&t/widt-#$%px$ """"""android,la+o&t/-eig-t#$wrap/content$ """"""android,la+o&t/weig-t#$1$ """"""android,textSiIe#$1Xpt$ """"/) """" ImageView"android,id#$01id/stat&s$ """"""android,la+o&t/widt-#$%px$ """"""android,la+o&t/-eig-t#$wrap/content$ """"""android,la+o&t/weig-t#$1$ """"/) "" /*inear*a+o&t) /*inear*a+o&t)

5his layout is use by a ;atter+9onitor a%tivity, >hi%h registers to re%eive the 3C<I2=/;3<<86C/CB3=G87 Intent in on6es&me() an unregisters in on5a&se()*
pac.age"com.commonsware.android.s+sevents.batter+: import"android.app.3ctivit+: import"android.content.;roadcast6eceiver: import"android.content.Context: import"android.content.Intent: import"android.content.IntentKilter: import"android.os.;&ndle: import"android.os.;atter+9anager: import"android.widget.5rogress;ar: import"android.widget.ImageView: import"android.widget.<extView: p&blic"class";atter+9onitor"extends"3ctivit+"4 ""private"5rogress;ar"bar#n&ll: ""private"ImageView"stat&s#n&ll: ""private"<extView"level#n&ll: "" ""02verride ""p&blic"void"onCreate(;&ndle"savedInstanceState)"4 """"s&per.onCreate(savedInstanceState): """"setContentView(6.la+o&t.main): """" """"bar#(5rogress;ar)findViewById(6.id.bar):

-3$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

=andling System <vents

""""stat&s#(ImageView)findViewById(6.id.stat&s): """"level#(<extView)findViewById(6.id.level): ""? "" ""02verride ""p&blic"void"onResume()"4 """"s&per.onResume(): """" """"registerReceiver(on;atter+C-anged> """""""""""""""""""""new"Intent'ilter(Intent.3C<I2=/;3<<86C/CB3=G87)): ""? "" ""02verride ""p&blic"void"on ause()"4 """"s&per.on ause(): """" """"unregisterReceiver(on;atter+C-anged): ""? "" "";roadcast6eceiver"on;atter+C-anged#new"BroadcastReceiver()"4 """"p&blic"void"onReceive(Context"context>"Intent"intent)"4 """"""int"pct#1%%Mintent.getIntE(tra($level$>"1)/intent.getIntE(tra($scale$>"1): """""" """"""bar.set rogress(pct): """"""level.set+e(t(String.value$f(pct)): """""" """"""switc-(intent.getIntE(tra($stat&s$>"'1))"4 """"""""case";atter+9anager.;3<<86C/S<3<DS/CB36GI=G, """"""""""stat&s.setImageResource(6.drawable.c-arging): """"""""""brea.: """""""" """"""""case";atter+9anager.;3<<86C/S<3<DS/KD**, """"""""""int"pl&gged#intent.getIntE(tra($pl&gged$>"'1): """""""""" """"""""""if"(pl&gged##;atter+9anager.;3<<86C/5*DGG87/3C"YY """"""""""""""pl&gged##;atter+9anager.;3<<86C/5*DGG87/DS;)"4 """"""""""""stat&s.setImageResource(6.drawable.f&ll): """"""""""? """"""""""else"4 """"""""""""stat&s.setImageResource(6.drawable.&npl&gged): """"""""""? """"""""""brea.: """""""" """"""""defa&lt, """"""""""stat&s.setImageResource(6.drawable.&npl&gged): """"""""""brea.: """"""? """"? ""?: ?

5he key to 3C<I2=/;3<<86C/CB3=G87 is in the Ie;trasI. Many Ie;trasI are pa%kage in the Intent, to es%ribe the %urrent state o$ the battery, su%h as*
-30
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

=andling System <vents

-ealt-, >hi%h shoul level,

generally be ;3<<86C/B83*<B/G227

>hi%h is the proportion o$ battery li$e remaining as an integer, spe%i$ie on the s%ale es%ribe by the s%ale Ie;traI
pl&gged, >hi%h >ill in i%ate i$ the evi%e is plugge into &;3<<86C/5*DGG87/3C' or "#/ po>er &;3<<86C/5*DGG87/DS;'

AC po>er &e.g.,

scale, >hi%h in i%ates the ma;imum possible value o$ level 1%%, in i%ating that level is a per%entage o$ %harge remaining' stat&s, >hi%h >ill tell you i$ the battery &;3<<86C/S<3<DS/CB36GI=G', $ull &;3<<86C/S<3<DS/KD**', &;3<<86C/S<3<DS/7ISCB36GI=G' tec-nolog+, $*i'Ion$'

is %harging or is%harging &e.g.,

>hi%h in i%ates >hat sort o$ battery is installe

temperat&re,

>hi%h tells you ho> >arm the battery is, in tenths o$ a egree Celsius &e.g., E1J is 2-.? egrees Celsius' elivere by the

voltage, in i%ating the %urrent voltage being battery, in millivolts

.n the %ase o$ ;atter+9onitor, >hen >e re%eive an 3C<I2=/;3<<86C/CB3=G87" .ntent, >e o three things* -. We %ompute the per%entage o$ battery li$e remaining, by ivi ing the level by the s%ale

2. We up ate the 5rogress;ar an <extView to isplay the battery li$e as a per%entage ?. We isplay an i%on, >ith the i%on sele%tion epen ing on >hether >e are %harging &stat&s is ;3<<86C/S<3<DS/CB36GI=G', $ull but on the %harger &stat&s is ;3<<86C/S<3<DS/KD** an pl&gged is ;3<<86C/5*DGG87/3C or ;3<<86C/5*DGG87/DS;', or are not plugge in 5his only really >orks on a evi%e, >here you %an plug an unplug it, plus get a varying %harge level*

-32
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

=andling System <vents

!igure $-/ The Battery8onitor application

-33
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 12

1sing System Services

o$$ers a number o$ system servi%es, usually obtaine by $rom your 3ctivit+, Service, or other Context. 5hese are your gate>ay to all sorts o$ %apabilities, $rom settings to volume to Wi(i. 5hroughout the %ourse o$ this book an its %ompanion, >e have seen several o$ these system servi%es. .n this %hapter, >e >ill take a look at others that may be o$ value to you in buil ing %ompelling An roi appli%ations.
getS+stemService()

An roi

'et :larmed
A %ommon <uestion >hen oing An roi up cron LobsJI evelopment is I>here o . set

5he cron utility M popular in Linu; M is a >ay o$ s%he uling >ork to be one perio i%ally. Dou tea%h cron >hat to run an >hen to run it &e.g., >eek ays at noon', an cron takes %are o$ the rest. #in%e An roi has a Linu; kernel at its heart, one might think that cron might literally be available. While cron itsel$ is not, An roi oes have a system servi%e name 3larm9anager >hi%h $ills a similar role. Dou give it a 5endingIntent an a time &an optional a perio $or repeating' an it >ill $ire o$$ the Intent as nee e . /y this me%hanism, you %an get a similar e$$e%t to cron. 5here is one small %at%h, though* An roi is esigne to run on mobile evi%es, parti%ularly ones po>ere by all3too3tiny batteries. .$ you >ant
-35
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

your perio i% tasks to be run even i$ the evi%e is IasleepI, you >ill nee to take a $air number o$ e;tra steps, mostly stemming aroun the %on%ept o$ the Wa.e*oc..

Concept o*

a&e"oc&s

Most o$ the time in An roi , you are eveloping %o e that >ill run >hile the user is a%tually using the evi%e. A%tivities, $or e;ample, only really make sense >hen the evi%e is $ully a>ake an the user is tapping on the s%reen or keyboar . !arti%ularly >ith s%he ule ba%kgroun tasks, though, you nee to bear in min that the evi%e >ill eventually Igo to sleepI. .n $ull sleep mo e, the isplay, main C!", an keyboar are all po>ere o$$, to ma;imiCe battery li$e. Gnly on a lo>3level system event, like an in%oming phone %all, >ill anything >ake up. Another thing that >ill partially >ake up the phone is an Intent raise by the 3larm9anager. #o long as broa %ast re%eivers are pro%essing that Intent, the 3larm9anager ensures the C!" >ill be running &though the s%reen an keyboar are still o$$'. Gn%e the broa %ast re%eivers are one, the 3larm9anager lets the evi%e go ba%k to sleep. Dou %an a%hieve the same e$$e%t in your %o e via a Wa.e*oc., obtaine via the 5ower9anager system servi%e. When you a%<uire a Ipartial Wa.e*oc.I &536<I3*/W3V8/*2CV', you prevent the C!" $rom going ba%k to sleep until you release sai Wa.e*oc.. /y proper use o$ a partial Wa.e*oc., you %an ensure the C!" >ill not get shut o$$ >hile you are trying to o ba%kgroun >ork, >hile still allo>ing the evi%e to sleep most o$ the time, in bet>een alarm events. )o>ever, using a Wa.e*oc. is a bit tri%ky, parti%ularly >hen respon ing to an alarm Intent, as >e >ill see in the ne;t $e> se%tions.

-46
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

(chedulin! Alarms
5he $irst step to %reating a cron >orkalike is to arrange to get %ontrol >hen the evi%e boots. A$ter all, the cron aemon starts on boot as >ell, an >e have no other >ay o$ ensuring that our ba%kgroun tasks start $iring a$ter a phone is reset. We sa> ho> to o that in a previous %hapter M set up an

68C8IV8/;22</C295*8<87 ;roadcast6eceiver, >ith appropriate permissions. )ere, $or e;ample, is the 3ndroid9anifest.xml $rom S+stemServices/3larm*
!xml"version#$1.%$"encoding#$&tf'($!) manifest"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ """"""pac.age#$com.commonsware.android.s+ssvc.alarm$ """"""android,versionCode#$1$ """"""android,version=ame#$1.%$) "" &ses'permission"android,name#$android.permission.68C8IV8/;22</C295*8<87$"/) "" &ses'permission"android,name#$android.permission.W3V8/*2CV$"/) "" application"android,label#$0string/app/name$) """""" receiver"android,name#$.2n;oot6eceiver$) """""""""" intent'filter) """""""""""""" action"android,name#$android.intent.action.;22</C295*8<87$"/) """""""""" /intent'filter) """""" /receiver) """""" receiver"android,name#$.2n3larm6eceiver$) """""" /receiver) """""" service"android,name#$.3ppService$) """""" /service) "" /application) /manifest)

We ask $or an 2n;oot6eceiver to get %ontrol >hen the evi%e starts up, an it is in 2n;oot6eceiver that >e s%he ule our re%urring alarm*
pac.age"com.commonsware.android.s+ssvc.alarm: import"android.app.3larm9anager: import"android.app.5endingIntent: import"android.content.;roadcast6eceiver: import"android.content.Context: import"android.content.Intent: import"android.os.S+stemCloc.: import"android.&til.*og: p&blic"class"2n;oot6eceiver"extends";roadcast6eceiver"4 ""private"static"final"int"586I27#J%%%%%:""//"H"min&tes ""

-4Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

""02verride ""p&blic"void"onReceive(Context"context>"Intent"intent)"4 """"3larm9anager" mgr#(3larm9anager)context.getSystemService(Context.3*369/S86VIC8): """"Intent"i#new"Intent(context>"2n3larm6eceiver.class): """"5endingIntent"pi#5endingIntent.getBroadcast(context>"%> """"""""""""""""""""""""""""""""""""""""""""i>"%): """" """"mgr.setRepeating(3larm9anager.8*35S87/683*<I98/W3V8D5> """""""""""""""""""""S+stemCloc..elapsedRealtime()> """""""""""""""""""""586I27> """""""""""""""""""""pi): ""? ?

We get the 3larm9anager via getS+stemService(), %reate an Intent re$eren%ing another ;roadcast6eceiver &2n3larm6eceiver', >rap that Intent in a 5endingIntent, an tell the 3larm9anager to set up a repeating alarm via set6epeating(). /y saying >e >ant a 8*35S87/683*<I98/W3V8D5 alarm, >e in i%ate that >e >ant the alarm to >ake up the evi%e &even i$ it is asleep' an to e;press all times using the time base use by S+stemCloc..elapsed6ealtime(). .n this %ase, our alarm is set to go o$$ every $ive minutes. 5his >ill %ause the 3larm9anager to raise our Intent imminently, an every $ive minutes therea$ter.

Arran!in! *or

or& 8rom Alarms

When an alarm goes o$$, our 2n3larm6eceiver >ill get %ontrol. .t nee s to arrange $or a servi%e &in this %ase, name 3ppService' to o its >ork in the ba%kgroun , but then release %ontrol <ui%kly M on6eceive() %annot take very mu%h time. )ere is the tiny implementation o$
2n3larm6eceiver

S+stemServices/3larm*

$rom

pac.age"com.commonsware.android.s+ssvc.alarm: import"android.content.;roadcast6eceiver: import"android.content.Context: import"android.content.Intent:

-4%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

import"android.&til.*og: p&blic"class"2n3larm6eceiver"extends";roadcast6eceiver"4 ""02verride ""p&blic"void"onReceive(Context"context>"Intent"intent)"4 """"Wa.ef&lIntentService.acquireStaticLoc)(context): """" """"context.startService(new"Intent(context>"3ppService.class)): ""? ?

While there is very little %o e in this %lass, it is merely e%eptively simple. (irst, >e a%<uire a Wa.e*oc. $rom our 3ppService7s parent %lass, Wa.ef&lIntentService via ac@&ireStatic*oc.(), sho>n belo>*
p&blic"static"void"acquireStaticLoc)(Context"context)"4 ""getLoc)(context).acquire(): ? s+nc-roniIed"private"static"5ower9anager.Wa.e*oc."getLoc)(Context"context)"4 ""if"(loc.Static##n&ll)"4 """"5ower9anager" mgr#(5ower9anager)context.getSystemService(Context.52W86/S86VIC8): """"loc.Static#mgr.new,a)eLoc)(5ower9anager.536<I3*/W3V8/*2CV> """""""""""""""""""""""""*2CV/=398/S<3<IC): """"loc.Static.setReferenceCounted(tr&e): ""? ""ret&rn(loc.Static): ?

5he get*oc.() implementation laCy3%reates our Wa.e*oc. by getting the 5ower9anager, %reating a ne> partial Wa.e*oc., an setting it to be re$eren%e %ounte &meaning i$ it is a%<uire several times, it takes a %orrespon ing number o$ release() %alls to truly release the lo%k'. .$ >e have alrea y retrieve the Wa.e*oc. in a previous invo%ation, >e reuse the same lo%k. /a%k in 2n3larm6eceiver, up until this point, the C!" >as running be%ause 3larm9anager hel a partial Wa.e*oc.. 0o>, the C!" is running be%ause both 3larm9anager and Wa.ef&lIntentService hol a partial Wa.e*oc.. 5hen,
2n3larm6eceiver starts ac@&ireStatic*oc.() >as a

the 3ppService instan%e &remember* static metho ' an e;its. 0otably,


-4.

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

oes not release the Wa.e*oc. it a%<uire . 5his is important, as >e nee to ensure that the servi%e %an get its >ork one >hile the C!" is running. )a >e release the Wa.e*oc. be$ore returning, it is possible that the evi%e >oul $all ba%k asleep be$ore our servi%e ha a %han%e to a%<uire a $resh Wa.e*oc.. 5his is one o$ the keys o$ using Wa.e*oc. su%%ess$ully M as nee e , use overlapping Wa.e*oc. instan%es to ensure %onstant %overage as you pass $rom %omponent to %omponent.
2n3larm6eceiver

0o>, our servi%e >ill start up an be able to o something, >hile the C!" is running ue to our a%<uire Wa.e*oc..

(tayin! A+a&e At

or&

#o, 3ppService >ill no> get %ontrol, un er an a%tive Wa.e*oc.. At minimum, our servi%e >ill be %alle via onStart(), an possibly also onCreate() i$ the servi%e ha been previously stoppe . Gur mission is to o our >ork an release the Wa.e*oc.. #in%e servi%es shoul not o long3running tasks in onStart(), >e %oul $ork a <-read, have it o the >ork in the ba%kgroun , then have it release the Wa.e*oc.. 0ote that >e %annot release the Wa.e*oc. in onStart() in this %ase M Lust be%ause >e have a ba%kgroun threa oes not mean the evi%e >ill keep the C!" running. 5here are issues >ith $orking a <-read $or every in%oming re<uest, though*

.$ the >ork nee e to be one sometimes takes longer than the alarm perio , >e %oul >in up >ith many ba%kgroun threa s, >hi%h is ine$$i%ient. .t also means our Wa.e*oc. management gets mu%h tri%kier, sin%e >e >ill not have release the Wa.e*oc. be$ore the alarm tries to ac@&ire() it again. .$ >e also are invoke in onStart() via some $oregroun a%tivity, >e might >in up >ith many more bits o$ >ork to be one, again %ausing %on$usion >ith our Wa.e*oc. an perhaps slo>ing things o>n ue to too many ba%kgroun threa s.

-4$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

An roi has a %lass that helps >ith parts o$ this, IntentService. .t arranges $or a >ork <ueue o$ inboun Intents M rather than overri ing onStart(), you overri e onBandleIntent(), >hi%h is %alle $rom a ba%kgroun threa . An roi han les all the etails o$ shutting o>n your servi%e >hen there is no more outstan ing >ork, managing the ba%kgroun threa , an so on. )o>ever, IntentService oes not o anything to hol a Wa.e*oc.. )en%e, this sample proLe%t implements Wa.ef&lIntentService as a sub%lass o$ IntentService. Wa.ef&lIntentService han les most o$ the Wa.e*oc. logi%, so 3ppService &inheriting $rom Wa.ef&lIntentService' %an Lust $o%us on the >ork it nee s to o.
Wa.ef&lIntentService

han les the Wa.e*oc. logi% in $our %omponents*

-.

.t o$$ers the publi% stati% metho ac@&ireStatic*oc.(), >hi%h nee s to be %alle by >hoever is %alling startService() on our Wa.ef&lIntentService sub%lass.

2. .n onCreate(), it %reates &but oes not a%<uire' another Wa.e*oc.. 5he stati% Wa.e*oc. >ill be use to keep the evi%e a>ake >hile the ;roadcast6eceiver &or >hoever else is %alling startService()' starts up the servi%e. 5he lo%al Wa.e*oc. >ill be use to keep the evi%e a>ake so long as there is >ork to be one. ?. .n onStart(), it a%<uires the lo%al Wa.e*oc., lets the super%lass o its >ork to en<ueue the supplie .ntent $or later pro%essing, then releases the stati% Wa.e*oc.. At this point, the evi%e still must remain a>ake, be%ause even though the 3larm9anager Wa.e*oc. &use uring the %all to on6eceive() in our ;roadcast6eceiver' is release , an our stati% Wa.e*oc. is release , our lo%al Wa.e*oc. is still hel . =. .n onBandleIntent(), it releases the lo%al Wa.e*oc.. #in%e this Wa.e*oc. is re$eren%e3%ounte , the lo%k >ill only $ully release on%e every Intent en<ueue by onStart() has been han le by onBandleIntent(). )ere is the $ull implementation o$ Wa.ef&lIntentService*

-40
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

pac.age"com.commonsware.android.s+ssvc.alarm: import"android.app.3larm9anager: import"android.app.5endingIntent: import"android.app.IntentService: import"android.content.Context: import"android.content.Intent: import"android.os.I;inder: import"android.os.5ower9anager: import"android.&til.*og: p&blic"class"Wa.ef&lIntentService"extends"IntentService"4 ""p&blic"static"final"String" *2CV/=398/S<3<IC#$com.commonsware.android.s+ssvc.3ppService.Static$: ""p&blic"static"final"String" *2CV/=398/*2C3*#$com.commonsware.android.s+ssvc.3ppService.*ocal$: ""private"static"5ower9anager.Wa.e*oc."loc.Static#n&ll: ""private"5ower9anager.Wa.e*oc."loc.*ocal#n&ll: "" ""p&blic"static"void"acquireStaticLoc)(Context"context)"4 """"getLoc)(context).acquire(): ""? "" ""s+nc-roniIed"private"static"5ower9anager.Wa.e*oc."getLoc)(Context"context)"4 """"if"(loc.Static##n&ll)"4 """"""5ower9anager" mgr#(5ower9anager)context.getSystemService(Context.52W86/S86VIC8): """""" """"""loc.Static#mgr.new,a)eLoc)(5ower9anager.536<I3*/W3V8/*2CV> """""""""""""""""""""""""""*2CV/=398/S<3<IC): """"""loc.Static.setReferenceCounted(tr&e): """"? """" """"ret&rn(loc.Static): ""? "" ""p&blic",a)efulIntentService(String"name)"4 """"s&per(name): ""? "" ""p&blic"void"onCreate()"4 """"s&per.onCreate(): """" """"5ower9anager"mgr#(5ower9anager)getSystemService(Context.52W86/S86VIC8): """" """"loc.*ocal#mgr.new,a)eLoc)(5ower9anager.536<I3*/W3V8/*2CV> """""""""""""""""""""""""""""*2CV/=398/*2C3*): """"loc.*ocal.setReferenceCounted(tr&e): ""? "" ""02verride ""p&blic"void"onStart(Intent"intent>"final"int"startId)"4 """"loc.*ocal.acquire(): """" """"s&per.onStart(intent>"startId): -42
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

"""" """"getLoc)(t-is).release(): ""? "" ""02verride ""protected"void"on*andleIntent(Intent"intent)"4 """"loc.*ocal.release(): ""? ?

With all that behin us, 3ppService nee only implement onBandleIntent(), o its >ork, an then %hain up>ar to the Wa.ef&lIntentService7s implementation o$ onBandleIntent()*
pac.age"com.commonsware.android.s+ssvc.alarm: import"android.content.Intent: import"android.os.8nvironment: import"android.&til.*og: import"Aava.io.;&fferedWriter: import"Aava.io.Kile: import"Aava.io.KileWriter: import"Aava.io.I28xception: import"Aava.&til.7ate: p&blic"class"3ppService"extends"Wa.ef&lIntentService"4 ""p&blic"&ppService()"4 """"s&per($3ppService$): ""? ""02verride ""protected"void"on*andleIntent(Intent"intent)"4 """"Kile"log#new"'ile(8nvironment.getE(ternalStorage"irectory()> """""""""""""""""""""$3larm*og.txt$): """" """"tr+"4 """""";&fferedWriter"o&t#new"Buffered,riter(new" 'ile,riter(log.get&bsolute at!()>"tr&e)): """""" """"""o&t.write(new""ate().toString()): """"""o&t.write($Zn$): """"""o&t.close(): """"? """"catc-"(I28xception"e)"4 """"""*og.e($3ppService$>"$8xception"appending"to"log"file$>"e): """"? """" """"s&per.on*andleIntent(intent): ""? ?

-43
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

5he I$ake >orkI being one by this 3ppService is simply logging the $a%t that >ork nee e to be one to a log $ile on the #@ %ar . 0ote that i$ you attempt to buil an run this proLe%t that you >ill nee an #@ %ar in the evi%e &or %ar image atta%he to your emulator'.

Setting <xpectations
.$ you have an An roi evi%e, you probably have spent some time in the #ettings appli%ation, t>eaking your evi%e to >ork ho> you >ant M ringtones, Wi(i settings, "#/ ebugging, et%. Many o$ those settings are also available via Settings %lass &in the android.provider pa%kage', an parti%ularly the Settings.S+stem an Settings.Sec&re publi% inner %lasses.

Basic (ettin!s
Settings.S+stem allo>s you to get an , >ith the W6I<8/S8<<I=GS permission, alter these settings. As one might e;pe%t, there are a series o$ type getter an setter metho s on Settings.S+stem, ea%h taking a key as a parameter. 5he keys are %lass %onstants, su%h as*

to %ontrol >hether you %an install appli%ations on a evi%e $rom outsi e o$ the An roi Market
I=S<3**/=2=/936V8</355S *2CV/53<<86=/8=3;*87 *2CV/53<<86=/VISI;*8

to %ontrol >hether the user nee s to enter a lo%k pattern to enable use o$ the evi%e to %ontrol >hether the lo%k pattern is ra>n on3s%reen as it is s>ipe by the user, or i$ the s>ipes are IinvisibleI has a
SettingsSetter

5he S+stemServices/Settings proLe%t appli%ation that isplays a %he%klist*

sample

!xml"version#$1.%$"encoding#$&tf'($!) *istView"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,id#$0android,id/list$ ""android,la+o&t/widt-#$fill/parent$ ""android,la+o&t/-eig-t#$fill/parent$ /)

-44
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

!igure $%/ The SettingsSetter application

5he %he%klist itsel$ is $ille >ith a $e> ;ooleanSetting obLe%ts, >hi%h map a isplay name >ith a Settings.S+stem key*
static"class";ooleanSetting"4 ""String".e+: ""String"displa+=ame: ""BooleanSetting(String".e+>"String"displa+=ame)"4 """"t-is..e+#.e+: """"t-is.displa+=ame#displa+=ame: ""? ""02verride ""p&blic"String"toString()"4 """"ret&rn(displa+=ame): ""? ""boolean"isC!ec)ed(Content6esolver"cr)"4 """"tr+"4 """"""int"val&e#Settings.S+stem.getInt(cr>".e+): """"""ret&rn(val&eN#%): """"? """"catc-"(Settings.Setting=otKo&nd8xception"e)"4 """"""*og.e($SettingsSetter$>"e.get%essage()): """"? """"ret&rn(false): -45
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

""? ""void"setC!ec)ed(Content6esolver"cr>"boolean"val&e)"4 """"Settings.S+stem.putInt(cr>".e+>"(val&e"!"1","%)): ""? ?

5hree su%h settings are put in the list, an as the %he%kbo;es are %he%ke an un%he%ke , the values are passe along to the settings themselves*
02verride p&blic"void"onCreate(;&ndle"savedInstanceState)"4 ""s&per.onCreate(savedInstanceState): ""setContentView(6.la+o&t.main): ""getListView().setC!oice%ode(*istView.CB2IC8/9278/9D*<I5*8): ""setList&dapter(new"&rray&dapter(t-is> """""""""""""""""""""""""""""""""android.6.la+o&t.simple/list/item/m&ltiple/c-oi ce> """""""""""""""""""""""""""""""""settings)): ""Content6esolver"cr#getContentResolver(): ""for"(int"i#%:i settings.si.e():i11)"4 """";ooleanSetting"s#settings.get(i): """"getListView().setItemC!ec)ed(i>"s.isC!ec)ed(cr)): ""? ? 02verride protected"void"onListItemClic)(*istView"l>"View"v> """""""""""""""""""""""""""""int"position>"long"id)"4 ""s&per.onListItemClic)(l>"v>"position>"id): "";ooleanSetting"s#settings.get(position): ""s.setC!ec)ed(getContentResolver()> """"""""""""""l.isItemC!ec)ed(position)): ?

5he SettingsSetter a%tivity also has an option menu %ontaining $our items*
!xml"version#$1.%$"encoding#$&tf'($!) men&"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$) "" item"android,id#$01id/app$ """"android,title#$3pplication$ """"android,icon#$0android,drawable/ic/men&/manage$"/) "" item"android,id#$01id/sec&rit+$ """"android,title#$Sec&rit+$ """"android,icon#$0android,drawable/ic/men&/close/clear/cancel$"/) -56
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

"" item"android,id#$01id/wireless$ """"android,title#$Wireless$ """"android,icon#$0android,drawable/ic/men&/set/as$"/) "" item"android,id#$01id/all$ """"android,title#$3ll"Settings$ """"android,icon#$0android,drawable/ic/men&/preferences$"/) /men&)

5hese items %orrespon Settings %lass*

to $our a%tivity Intent values i enti$ie

by the

men&3ctivities.put(6.id.app> """"""""""""""""""Settings.3C<I2=/355*IC3<I2=/S8<<I=GS): men&3ctivities.put(6.id.sec&rit+> """"""""""""""""""Settings.3C<I2=/S8CD6I<C/S8<<I=GS): men&3ctivities.put(6.id.wireless> """"""""""""""""""Settings.3C<I2=/WI68*8SS/S8<<I=GS): men&3ctivities.put(6.id.all> """"""""""""""""""Settings.3C<I2=/S8<<I=GS):

When an option menu is %hosen, the %orrespon ing a%tivity is laun%he *


02verride p&blic"boolean"on$ptionsItemSelected(9en&Item"item)"4 ""String"activit+#men&3ctivities.get(item.getItemId()): ""if"(activit+N#n&ll)"4 """"start&ctivity(new"Intent(activit+)): """"ret&rn(tr&e): ""? ""ret&rn(s&per.on$ptionsItemSelected(item)): ?

5his >ay, you have your %hoi%e o$ either ire%tly manipulating the settings or merely making it easier $or users to get to the An roi 3supplie a%tivity $or manipulating those settings.

(ecure (ettin!s
Dou >ill noti%e that i$ you use the above %o e an try %hanging the value o$ IAllo> non3Market app installsI, the %hange oes not Isti%kI M on%e you e;it an reopen the appli%ation, the setting returns to its original state.

-5Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

Moreover, i$ you use the #ettings appli%ation an e;amine the setting, it is %lear that SettingsSetter is not a%tually %hanging that parti%ular setting. Gn%e upon a time M An roi -.- an earlier M it i . 0o>, though, that setting is one that An roi eems Ise%ureI. 5he %onstant has been move $rom Settings.S+stem to Settings.Sec&re, though the ol %onstant is still there, $lagge as epre%ate . 5hese so3%alle Ise%ureI settings are one that An roi oes not allo> appli%ations to %hange. 0o permission resolves this problem. 5he only option is to isplay the o$$i%ial #ettings a%tivity an let the user %hange the setting.

Can 7ou =ear 8e @o)F ,G* =o) :bout @o)F


5he $an%ier the evi%e, the more %ompli%ate %ontrolling soun volume be%omes. Gn a simple M!? player, there is usually only one volume %ontrol. 5hat is be%ause there is only one sour%e o$ soun * the musi% itsel$, playe through speakers or hea phones. .n An roi , though, there are several sour%es o$ soun s*

Ringing, to signi$y an in%oming %all ,oi%e %alls Alarms, su%h as those raise by the Alarm Clo%k appli%ation #ystem soun s &error beeps, "#/ %onne%tion signal, et%.' Musi%, as might %ome $rom the M!? player

An roi allo>s the user to %on$igure ea%h o$ these volume levels separately. "sually, the user oes this via the volume ro%ker buttons on the evi%e, in the %onte;t o$ >hatever soun is being playe &e.g., >hen on a %all, the
-5%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

volume buttons %hange the voi%e %all volume'. Also, there is a s%reen in the An roi #ettings appli%ation that allo>s you to %on$igure various volume levels. 5he 3&dioService in An roi allo>s you, the eveloper, to also %ontrol these volume levels, $or all $ive IstreamsI &i.e., sour%es o$ soun '. .n the S+stemServices/Vol&me proLe%t, >e %reate a Vol&miIer appli%ation that isplays an mo i$ies all $ive volume levels, reusing the 9eter >i get >e %reate in an earlier %hapter.

Reusin! /eter
8iven that 9eter >as originally evelope in a separate proLe%t, >e ha to o a $e> things to make it usable here. (irst, >e ha to %opy over the layout &res/la+o&t/meter.xml', sour%e &src/com/commonsware/android/widget/9eter.Aava', an t>o 7rawable" resour%es &res/drawable/incr.png an res/drawable/decr.png'. We then move it all into the same pa%kage as everything else &com.commonsware.android.s+ssvc.vol&me'. 5his, o$ %ourse, e$eats mu%h o$ the reusability. Gn%e better >i get reuse mo els be%ome apparent, e;pe%t up ates to this book to %over them.

Attachin! /eters to ,olume (treams


8iven that >e have our 9eter >i get to >ork >ith, setting up 9eter >i gets to >ork >ith volume streams is $airly straight$or>ar . (irst, >e nee to %reate a layout >ith a 9eter per stream*
!xml"version#$1.%$"encoding#$&tf'($!) <able*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""xmlns,app#$-ttp,//sc-emas.android.com/ap./res/com.commonsware.android.s+ssvc.v ol&me$ ""android,stretc-Col&mns#$1$ ""android,la+o&t/widt-#$fill/parent$

-5.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

""android,la+o&t/-eig-t#$fill/parent$ ) "" <able6ow """"android,padding<op#$1%px$ """"android,padding;ottom#$E%px$) """" <extView"android,text#$3larm,$"/) """" com.commonsware.android.s+ssvc.vol&me.9eter """"""android,id#$01id/alarm$ """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$wrap/content$ """"""app,incr#$1$ """"""app,decr#$1$ """"/)""""""""""""""""""""""""""""""""""""" "" /<able6ow) "" <able6ow """"android,padding;ottom#$E%px$) """" <extView"android,text#$9&sic,$"/) """" com.commonsware.android.s+ssvc.vol&me.9eter """"""android,id#$01id/m&sic$ """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$wrap/content$ """"""app,incr#$1$ """"""app,decr#$1$ """"/)""""""""""""""""""""""""""""""""""""" "" /<able6ow) "" <able6ow """"android,padding;ottom#$E%px$) """" <extView"android,text#$6ing,$"/) """" com.commonsware.android.s+ssvc.vol&me.9eter """"""android,id#$01id/ring$ """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$wrap/content$ """"""app,incr#$1$ """"""app,decr#$1$ """"/)""""""""""""""""""""""""""""""""""""" "" /<able6ow) "" <able6ow """"android,padding;ottom#$E%px$) """" <extView"android,text#$S+stem,$"/) """" com.commonsware.android.s+ssvc.vol&me.9eter """"""android,id#$01id/s+stem$ """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$wrap/content$ """"""app,incr#$1$ """"""app,decr#$1$ """"/)""""""""""""""""""""""""""""""""""""" "" /<able6ow) "" <able6ow) """" <extView"android,text#$Voice,$"/) """" com.commonsware.android.s+ssvc.vol&me.9eter """"""android,id#$01id/voice$ """"""android,la+o&t/widt-#$fill/parent$ """"""android,la+o&t/-eig-t#$wrap/content$ """"""app,incr#$1$

-5$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

""""""app,decr#$1$ """"/)""""""""""""""""""""""""""""""""""""" "" /<able6ow) /<able*a+o&t)

5hen, >e nee Vol&miIer*

to >ire up ea%h o$ those meters in the onCreate() $or

9eter"alarm#n&ll: 9eter"m&sic#n&ll: 9eter"ring#n&ll: 9eter"s+stem#n&ll: 9eter"voice#n&ll: 3&dio9anager"mgr#n&ll: 02verride p&blic"void"onCreate(;&ndle"savedInstanceState)"4 ""s&per.onCreate(savedInstanceState): ""setContentView(6.la+o&t.main): ""mgr#(3&dio9anager)getSystemService(Context.3D7I2/S86VIC8): ""alarm#(9eter)findViewById(6.id.alarm): ""m&sic#(9eter)findViewById(6.id.m&sic): ""ring#(9eter)findViewById(6.id.ring): ""s+stem#(9eter)findViewById(6.id.s+stem): ""voice#(9eter)findViewById(6.id.voice): ""alarm.set+ag(3&dio9anager.S<6839/3*369): ""m&sic.set+ag(3&dio9anager.S<6839/9DSIC): ""ring.set+ag(3&dio9anager.S<6839/6I=G): ""s+stem.set+ag(3&dio9anager.S<6839/SCS<89): ""voice.set+ag(3&dio9anager.S<6839/V2IC8/C3**): ""init%eter(alarm): ""init%eter(m&sic): ""init%eter(ring): ""init%eter(s+stem): ""init%eter(voice): ?

We use the tag $or ea%h 9eter to hol the i enti$ier $or the stream asso%iate >ith that spe%i$i% 9eter. 5hat >ay, ea%h 9eter kno>s its stream. .n init9eter(), >e set the appropriate siCe $or the 9eter bar via set9ax(), set the initial value via set5rogress(), an >ire our in%rement an e%rement events to the appropriate metho s on Vol&me9anager*

-50
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

1sing System Services

"""final"int"stream#((Integer)meter.get+ag()).intValue(): """" """"meter.set%a((mgr.getStream%a(Volume(stream)): """"meter.set rogress(mgr.getStreamVolume(stream)): """"meter.set$nIncrListener(new"View.$nClic)Listener()"4 """"""p&blic"void"onClic)(View"v)"4 """"""""mgr.ad2ustStreamVolume(stream> """""""""""""""""""""""""""""""3&dio9anager.37JDS</63IS8>"%): """"""? """"?): """"meter.set$n"ecrListener(new"View.$nClic)Listener()"4 """"""p&blic"void"onClic)(View"v)"4 """"""""mgr.ad2ustStreamVolume(stream> """""""""""""""""""""""""""""""3&dio9anager.37JDS</*2W86>"%): """"""? """"?): ""? ?

5he net result is that >hen the user %li%ks the buttons on a meter, it a Lusts the stream to mat%h*

!igure $./ The (olumi;er application

-52
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 1)

7our ,)n #:dvanced& Services

.n The Busy Coder's Guide to Android De elopment , >e %overe ho> to %reate an %onsume servi%es. 0o>, >e %an get into some more interesting $a%ets o$ servi%e implementations, notably remote servi%es, so your servi%e %an serve a%tivities outsi e o$ your appli%ation.

When +PC :ttacks!


#ervi%es >ill ten to o$$er inter3pro%ess %ommuni%ation &.!C' as a means o$ intera%ting >ith a%tivities or other An roi %omponents. Ba%h servi%e e%lares >hat metho s it is making available over .!CO those metho s are then available $or other %omponents to %all, >ith An roi han ling all the messy etails involve >ith making metho %alls a%ross %omponent or pro%ess boun aries. 5he guts o$ this, $rom the stan point o$ the eveloper, is e;presse in A.@L* the An roi .nter$a%e @es%ription Language. .$ you have use .!C me%hanisms like CGM, CGR/A, or the like, you >ill re%ogniCe the notion o$ .@L. A.@L es%ribes the publi% .!C inter$a%e, an An roi supplies tools to buil the %lient an server si e o$ that inter$a%e. With that in min , let7s take a look at A.@L an .!C.

-53
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

rite the A$D"


.@Ls are $re<uently >ritten in a Ilanguage3neutralI synta;. A.@L, on the other han , looks a lot like a +ava inter$a%e. (or e;ample, here is some A.@L*
pac.age"com.commonsware.android.advservice: //"7eclare"t-e"interface. interface"IScript"4 ""void"e(ecuteScript(String"script): ?

As >ith a +ava inter$a%e, you e%lare a pa%kage at the top. As >ith a +ava inter$a%e, the metho s are >rappe in an inter$a%e e%laration &interface" IScript"4"..."?'. An , as >ith a +ava inter$a%e, you list the metho s you are making available. 5he i$$eren%es, though, are %riti%al. (irst, not every +ava type %an be use as a parameter. Dour %hoi%es are*

!rimitive values &int, float, do&ble, boolean, et%.'


String an C-arSe@&ence *ist an 9ap

&$rom Aava.&til'

Any other A.@L3 e$ine inter$a%es Any +ava %lasses that implement the 5arcelable inter$a%e, >hi%h is An roi 7s $lavor o$ serialiCation

.n the %ase o$ the latter t>o %ategories, you nee to in%lu e import" statements re$eren%ing the names o$ the %lasses or inter$a%es that you are using &e.g., import"com.commonsware.android.ISomet-ing'. 5his is true even i$ these %lasses are in your o>n pa%kage M you have to import them any>ay. 0e;t, parameters %an be %lassi$ie as in, o&t, or ino&t. ,alues that are o&t or ino&t %an be %hange by the servi%e an those %hanges >ill be propagate

-54
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

ba%k to the %lient. !rimitives &e.g., int' %an only be inO >e in%lu e in $or the A.@L $or enable() Lust $or illustration purposes. Also, you %annot thro> any e;%eptions. Dou >ill nee to %at%h all e;%eptions in your %o e, eal >ith them, an return $ailure in i%ations some other >ay &e.g., error %o e return values'. 0ame your A.@L $iles >ith the .aidl e;tension an proper ire%tory base on the pa%kage name. pla%e them in the

When you buil your proLe%t, either via an .@B or via Ant, the aidl utility $rom the An roi #@K >ill translate your A.@L into a server stub an a %lient pro;y.

$mplement the $nter*ace


8iven the A.@L3%reate server stub, no> you nee to implement the servi%e, either ire%tly in the stub, or by routing the stub implementation to other metho s you have alrea y >ritten. 5he me%hani%s o$ this are $airly straight$or>ar *

Create a private instan%e o$ the A.@L3generate IScript.St&b'

.St&b

%lass &e.g.,

.mplement metho s mat%hing up >ith ea%h o$ the metho s you pla%e in the A.@L Return this private instan%e $rom your on;ind() metho Service sub%lass in the

0ote that A.@L .!C %alls are syn%hronous, an so the %aller is blo%ke until the .!C metho returns. )en%e, your servi%es nee to be <ui%k about their >ork. We >ill see e;amples o$ servi%e stubs later in this %hapter.

-55
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

: Consumer <conomy
G$ %ourse, >e nee to have a %lient $or A.@L3 e$ine servi%es, lest these servi%es $eel lonely.

Bound *or (uccess


5o use an A.@L3 e$ine servi%e, you $irst nee to %reate an instan%e o$ your o>n ServiceConnection %lass. ServiceConnection, as the name suggests, represents your %onne%tion to the servi%e $or the purposes o$ making .!C %alls. Dour ServiceConnection sub%lass nee s to implement t>o metho s* -.
onServiceConnected(),

the servi%e

>hi%h is %alle on%e your a%tivity is boun to

2. onService7isconnected(), >hi%h is %alle i$ your %onne%tion en s normally, su%h as you unbin ing your a%tivity $rom the servi%e Ba%h o$ those metho s re%eives a Component=ame, >hi%h simply i enti$ies the servi%e you %onne%te to. More importantly, onServiceConnected() re%eives an I;inder instan%e, >hi%h is your gate>ay to the .!C inter$a%e. Dou >ill >ant to %onvert the I;inder into an instan%e o$ your A.@L inter$a%e %lass, so you %an use .!C as i$ you >ere %alling regular metho s on a regular +ava %lass &IScript.St&b.asInterface(binder)'. 5o a%tually hook your a%tivity to the servi%e, %all bindService() on the a%tivity*
bindService(new"Intent(IScript.class.get-ame())> """"""""""""svcConn>"Context.;I=7/3D<2/C683<8):

5he bindService() metho takes three parameters* -. An Intent representing the servi%e you >ish to invoke

2. Dour ServiceConnection instan%e

%66
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

?. A set o$ $lags M most times, you >ill >ant to pass in ;I=7/3D<2/C683<8, >hi%h >ill start up the servi%e i$ it is not alrea y running A$ter your bindService() %all, your onServiceConnected() %allba%k in the ServiceConnection >ill eventually be invoke , at >hi%h time your %onne%tion is rea y $or use.

Re?uest *or (ervice


Gn%e your servi%e inter$a%e obLe%t is rea y &IScript.St&b.asInterface(binder)', you %an start %alling metho s on it as you nee to. .n $a%t, i$ you isable some >i gets a>aiting the %onne%tion, no> is a $ine time to re3enable them. )o>ever, you >ill >ant to trap t>o e;%eptions. Gne is 7ead2bAect8xception" M i$ this is raise , your servi%e %onne%tion terminate une;pe%te ly. .n this %ase, you shoul un>in your use o$ the servi%e, perhaps by %alling onService7isconnected() manually, as sho>n above. 5he other is 6emote8xception, >hi%h is a more general3purpose e;%eption in i%ating a %ross3pro%ess %ommuni%ations problem. Again, you shoul probably %ease your use o$ the servi%e.

Prometheus %n#ound
When you are one >ith the .!C inter$a%e, %all &nbindService(), passing in the ServiceConnection. Bventually, your %onne%tion7s onService7isconnected() %allba%k >ill be invoke , at >hi%h point you shoul null out your inter$a%e obLe%t, isable relevant >i gets, or other>ise $lag yoursel$ as no longer being able to use the servi%e. (or obLe%t. e;ample, in the Weather!lus implementation o$ sho>n above, >e null out the IWeat-er servi%e

onService7isconnected()

%6Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

Dou %an al>ays re%onne%t to the servi%e, via bindService(), i$ you nee to use it again.

Service !rom :far


Bverything $rom the pre%e ing t>o se%tions %oul be use by lo%al servi%es. .n $a%t, that prose originally appeare in The Busy Coder's Guide to Android De elopment spe%i$i%ally in the %onte;t o$ lo%al servi%es. )o>ever, A.@L a s a $air bit o$ overhea , >hi%h is not ne%essary >ith lo%al servi%es. A$ter all, A.@L is esigne to marshal its parameters an transport them a%ross pro%ess boun aries, >hi%h is >hy there are so many <uirky rules about >hat you %an an %annot pass as parameters to your A.@L3 e$ine A!.s. #o, given our A.@L es%ription, let us e;amine some implementations, spe%i$i%ally $or remote servi%es. Gur sample appli%ations M sho>n in the 3dvServices/6emoteService an 3dvServices/6emoteClient sample proLe%ts M %onvert our /eanshell emo $rom The Busy Coder's Guide to Android De elopment into a remote servi%e. .$ you a%tually >ante to use s%ripting in an An roi appli%ation, >ith s%ripts loa e o$$ o$ the .nternet, isolating their e;e%ution into a servi%e might not be a ba i ea. .n the servi%e, those s%ripts are san bo;e , only able to a%%ess $iles an A!.s available to that servi%e. 5he s%ripts %annot a%%ess your o>n appli%ation7s atabases, $or e;ample. .$ the s%ript3e;e%uting servi%e is kept tightly %ontrolle , it minimiCes the mis%hie$ a rogue s%ript %oul possibly o.

(ervice 1ames
5o bin to a servi%e7s A.@L3 e$ine A!., you nee to %ra$t an .ntent that %an i enti$y the servi%e in <uestion. .n the %ase o$ a lo%al servi%e, that .ntent %an use the lo%al approa%h o$ ire%tly re$eren%ing the servi%e %lass. Gbviously, that is not possible in a remote servi%e %ase, >here the servi%e %lass is not in the same pro%ess, an may not even be kno>n by name to the %lient.
%6%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

When you e$ine a servi%e to be use by remote, you nee to a an intent3 $ilter element to your servi%e e%laration in the mani$est, in i%ating ho> you >ant that servi%e to be re$erre to by %lients. 5he mani$est $or 6emoteService is sho>n belo>*
!xml"version#$1.%$"encoding#$&tf'($!) manifest"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ """"""pac.age#$com.commonsware.android.advservice$ """"""android,versionCode#$1$ """"""android,version=ame#$1.%$) "" application"android,label#$0string/app/name$) """" service"android,name#$.;s-Service$) """""" intent'filter) """""""" action"android,name#$com.commonsware.android.advservice.IScript$"/) """""" /intent'filter) """" /service) "" /application) /manifest)

)ere, >e say that the servi%e %an be i enti$ie by the name com.commonsware.android.advservice.IScript. #o long as the %lient uses this name to i enti$y the servi%e, it %an bin to that servi%e7s A!.. .n this %ase, the name is not an implementation, but the A.@L A!., as you >ill see belo>. .n e$$e%t, this means that so long as some servi%e e;ists on the evi%e that implements this A!., the %lient >ill be able to bin to something.

The (ervice
/eyon the mani$est, the servi%e implementation is not too unusual. 5here is the A.@L inter$a%e, IScript*
pac.age"com.commonsware.android.advservice: //"7eclare"t-e"interface. interface"IScript"4 ""void"e(ecuteScript(String"script): ?

An there is the a%tual servi%e %lass itsel$, ;s-Service*

%6.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

pac.age"com.commonsware.android.advservice: import"android.app.Service: import"android.content.Intent: import"android.os.I;inder: import"android.&til.*og: import"bs-.Interpreter: p&blic"class";s-Service"extends"Service"4 ""private"final"IScript.St&b"binder#new"IScript.Stub()"4 """"p&blic"void"e(ecuteScript(String"script)"4 """"""e(ecuteScriptImpl(script): """"? ""?: ""private"Interpreter"i#new"Interpreter(): "" ""02verride ""p&blic"void"onCreate()"4 """"s&per.onCreate(): """" """"tr+"4 """"""i.set($context$>"t-is): """"? """"catc-"(bs-.8val8rror"e)"4 """"""*og.e($;s-Service$>"$8rror"exec&ting"script$>"e): """"? ""? "" ""02verride ""p&blic"I;inder"onBind(Intent"intent)"4 """"ret&rn(binder): ""? "" ""02verride ""p&blic"void"on"estroy()"4 """"s&per.on"estroy(): ""? "" ""private"void"e(ecuteScriptImpl(String"script)"4 """"tr+"4 """"""i.eval(script): """"? """"catc-"(bs-.8val8rror"e)"4 """"""*og.e($;s-Service$>"$8rror"exec&ting"script$>"e): """"? ""? ?

.$ you have seen the servi%e an /eanshell samples in then this implementation >ill seem $amiliar. 5he biggest thing to note is that the servi%e returns no result an han les any errors lo%ally. )en%e, the %lient >ill not get any response ba%k $rom the s%ript M the s%ript >ill Lust run. .n a
%6$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

real implementation, this >oul be silly, an >e >ill >ork to re%ti$y this later in this %hapter. Also note that, in this implementation, the s%ript is e;e%ute ire%tly by the servi%e on the %alling threa . Gne might think this is not a problem, sin%e the servi%e is in its o>n pro%ess an , there$ore, %annot possibly be using the %lient7s ". threa . )o>ever, A.@L .!C %alls are syn%hronous, so the %lient >ill still blo%k >aiting $or the s%ript to be e;e%ute . 5his too >ill be %orre%te later in this %hapter.

The Client
5he %lient M ;s-Service7emo out o$ 3dvServices/6emoteClient M is a $airly straight3$or>ar mashup o$ the servi%e an /eanshell %lients, >ith t>o t>ists*
pac.age"com.commonsware.android.advservice.client: import"android.app.3ctivit+: import"android.app.3lert7ialog: import"android.content.Component=ame: import"android.content.Context: import"android.content.Intent: import"android.content.ServiceConnection: import"android.os.;&ndle: import"android.os.I;inder: import"android.view.View: import"android.widget.;&tton: import"android.widget.8dit<ext: import"com.commonsware.android.advservice.IScript: p&blic"class";s-Service7emo"extends"3ctivit+"4 ""private"IScript"service#n&ll: ""private"ServiceConnection"svcConn#new"ServiceConnection()"4 """"p&blic"void"onServiceConnected(Component=ame"class=ame> """""""""""""""""""""""""""""""""""I;inder"binder)"4 """"""service#IScript.St&b.asInterface(binder): """"? """"p&blic"void"onService"isconnected(Component=ame"class=ame)"4 """"""service#n&ll: """"? ""?: ""02verride ""p&blic"void"onCreate(;&ndle"icicle)"4

%60
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

""""s&per.onCreate(icicle): """"setContentView(6.la+o&t.main): "" """";&tton"btn#(;&tton)findViewById(6.id.eval): """"final"8dit<ext"script#(8dit<ext)findViewById(6.id.script): """" """"btn.set$nClic)Listener(new"View.$nClic)Listener()"4 """"""p&blic"void"onClic)(View"view)"4 """"""""String"src#script.get+e(t().toString(): """""""" """"""""tr+"4 """"""""""service.e(ecuteScript(src): """"""""? """"""""catc-"(android.os.6emote8xception"e)"4 """"""""""3lert7ialog.;&ilder"b&ilder# """"""""""""""""""""new"3lert7ialog.Builder(;s-Service7emo.t-is): """""""""" """"""""""b&ilder """""""""""".set+itle($8xceptionN$) """""""""""".set%essage(e.toString()) """""""""""".set ositiveButton($2V$>"n&ll) """""""""""".s!ow(): """"""""? """"""? """"?): """" """"bindService(new"Intent(IScript.class.get-ame())> """"""""""""""""svcConn>"Context.;I=7/3D<2/C683<8): ""? "" ""02verride ""p&blic"void"on"estroy()"4 """"s&per.on"estroy(): """" """"unbindService(svcConn): ""? ?

Gne t>ist is that the %lient nee s its o>n %opy o$ IScript.aidl. A$ter all, it is a totally separate appli%ation, an there$ore oes not share sour%e %o e >ith the servi%e. .n a pro u%tion environment, >e might %ra$t an istribute a +AR $ile that %ontains the IScript %lasses, so both %lient an servi%e %an >ork o$$ the same e$inition &see the up%oming %hapter on reusable %omponents'. (or no>, >e >ill Lust have a %opy o$ the A.@L. 5hen, the bindService() %all uses a slightly i$$erent Intent, one that re$eren%es the name o$ the A.@L inter$a%e7s %lass implementation. 5hat happens to be the name the servi%e is registere un er, an that is the glue that allo>s the %lient to $in the mat%hing servi%e.
%62
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

.$ you %ompile both appli%ations an uploa them to the evi%e, then start up the %lient, you %an enter in /eanshell %o e an have it be e;e%ute by the servi%e. 0ote, though, that you %annot per$orm ". operations &e.g., raise a <oast' $rom the servi%e. .$ you %hoose some s%ript that is long3running, you >ill see that the 8o: button is blo%ke until the s%ript is %omplete*

!igure $$/ The BshService9emo application* running a long script

Servicing the Service


5he pre%e ing se%tion outline /eanshell remote servi%e* -. t>o $la>s in the implementation o$ the

5he %lient re%eive no results $rom the s%ript e;e%ution

2. 5he %lient blo%ke >aiting $or the s%ript to %omplete .$ >e >ere not >orrie about the blo%king3%all issue, >e %oul simply have the exec&teScript() e;porte A!. return some sort o$ result &e.g., toString()" on the result o$ the /eanshell eval() %all'. )o>ever, that >oul not solve the $a%t that %alls to servi%e A!.s are syn%hronous even $or remote servi%es.

%63
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

Another approa%h >oul be to pass some sort o$ %allba%k obLe%t >ith exec&teScript(), su%h that the server %oul run the s%ript asyn%hronously an invoke the %allba%k on su%%ess or $ailure. 5his, though, implies that there is some >ay to have the a%tivity e;port an A!. to the servi%e. (ortunately, this is eminently oable, as you >ill see in this se%tion, an the a%%ompanying samples &3dvServices/6emoteService8x an 3dvServices/6emoteClient8x'.

Call#ac&s via A$D"


A.@L oes not have any %on%ept o$ ire%tion. .t Lust kno>s inter$a%es an stub implementations. .n the pre%e ing e;ample, >e use A.@L to have the servi%e $lesh out the stub implementation an have the %lient a%%ess the servi%e via the A.@L3 e$ine inter$a%e. )o>ever, there is nothing magi% about servi%es implementing an %lients a%%essing M it is e<ually possible to reverse matters an have the %lient implement something the servi%e uses via an inter$a%e. #o, $or e;ample, >e %oul %reate an IScript6es&lt.aidl $ile*
pac.age"com.commonsware.android.advservice: //"7eclare"t-e"interface. interface"IScript6es&lt"4 ""void"success(String"res&lt): ""void"failure(String"error): ?

5hen, >e %an augment IScript itsel$, to pass an IScript6es&lt >ith exec&teScript()*
pac.age"com.commonsware.android.advservice: import"com.commonsware.android.advservice.IScript6es&lt: //"7eclare"t-e"interface. interface"IScript"4 ""void"e(ecuteScript(String"script>"IScript6es&lt"cb): ?

%64
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

0oti%e that >e nee to spe%i$i%ally import IScript6es&lt, Lust like >e might import some IregularI +ava inter$a%e. An , as be$ore, >e nee to make sure the %lient an the server are >orking o$$ o$ the same A.@L e$initions, so these t>o A.@L $iles nee to be repli%ate a%ross ea%h proLe%t. /ut other than that one little t>ist, this is all that is re<uire , at the A.@L level, to have the %lient pass a %allba%k obLe%t to the servi%e* e$ine the A.@L $or the %allba%k an a it as a parameter to some servi%e A!. %all. G$ %ourse, there is a little more >ork to o on the %lient an server si e to make use o$ this %allba%k obLe%t.

Revisin! the Client


Gn the %lient, >e nee to implement an IScript6es&lt. Gn s&ccess(), >e %an o something like raise a <oastO on fail&re(), >e %an perhaps sho> an 3lert7ialog. 5he %at%h is that >e %annot be %ertain >e are being %alle on the ". threa in our %allba%k obLe%t. #o, the sa$est >ay to o that is to make the %allba%k obLe%t use something like r&n2nDi<-read() to ensure the results are isplaye on the ". threa *
private"final"IScript6es&lt.St&b"callbac.#new"IScript6es&lt.Stub()"4 ""p&blic"void"success(final"String"res&lt)"4 """"run$nUi+!read(new"Runnable()"4 """"""p&blic"void"run()"4 """"""""successImpl(res&lt): """"""? """"?): ""? ""p&blic"void"failure(final"String"error)"4 """"run$nUi+!read(new"Runnable()"4 """"""p&blic"void"run()"4 """"""""failureImpl(error): """"""? """"?): ""? ?:

%65
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

private"void"successImpl(String"res&lt)"4 ""<oast """".ma)e+e(t(;s-Service7emo.t-is>"res&lt>"<oast.*8=G<B/*2=G) """".s!ow(): ? private"void"failureImpl(String"error)"4 ""3lert7ialog.;&ilder"b&ilder# """"""""""""new"3lert7ialog.Builder(;s-Service7emo.t-is): ""b&ilder """".set+itle($8xceptionN$) """".set%essage(error) """".set ositiveButton($2V$>"n&ll) """".s!ow(): ?

An , o$ %ourse, >e nee to up ate our %all to exec&teScript() to pass the %allba%k obLe%t to the remote servi%e*
02verride p&blic"void"onCreate(;&ndle"icicle)"4 ""s&per.onCreate(icicle): ""setContentView(6.la+o&t.main): "";&tton"btn#(;&tton)findViewById(6.id.eval): ""final"8dit<ext"script#(8dit<ext)findViewById(6.id.script): ""btn.set$nClic)Listener(new"View.$nClic)Listener()"4 """"p&blic"void"onClic)(View"view)"4 """"""String"src#script.get+e(t().toString(): """"""tr+"4 """"""""service.e(ecuteScript(src>"callbac.): """"""? """"""catc-"(android.os.6emote8xception"e)"4 """"""""failureImpl(e.toString()): """"""? """"? ""?): ""bindService(new"Intent(IScript.class.get-ame())> """"""""""""""svcConn>"Context.;I=7/3D<2/C683<8): ?

%-6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

Revisin! the (ervice


5he servi%e also nee s %hanging, to both e;e%ute the s%ripts asyn%hronously an use the supplie %allba%k obLe%t $or the en results o$ the s%ript7s e;e%ution. As >as in the %hapter on Camera, ;s-Service $rom 3dvServices/6emoteService8x uses the *in.ed;loc.ing[&e&e pattern to manage a ba%kgroun threa . An 8xec&teScriptJob >raps up the s%ript an %allba%kO >hen the Lob is eventually pro%esse , it uses the %allba%k to supply the results o$ the eval() &on su%%ess' or the message o$ the 8xception &on $ailure'*
pac.age"com.commonsware.android.advservice: import"android.app.Service: import"android.content.Intent: import"android.os.I;inder: import"android.&til.*og: import"Aava.&til.conc&rrent.*in.ed;loc.ing[&e&e: import"bs-.Interpreter: p&blic"class";s-Service"extends"Service"4 ""private"final"IScript.St&b"binder#new"IScript.Stub()"4 """"p&blic"void"e(ecuteScript(String"script>"IScript6es&lt"cb)"4 """"""e(ecuteScriptImpl(script>"cb): """"? ""?: ""private"Interpreter"i#new"Interpreter(): ""private"*in.ed;loc.ing[&e&e Job)"@#new"*in.ed;loc.ing[&e&e Job)(): "" ""02verride ""p&blic"void"onCreate()"4 """"s&per.onCreate(): """" """"new"+!read(@5rocessor).start(): """" """"tr+"4 """"""i.set($context$>"t-is): """"? """"catc-"(bs-.8val8rror"e)"4 """"""*og.e($;s-Service$>"$8rror"exec&ting"script$>"e): """"? ""? "" ""02verride ""p&blic"I;inder"onBind(Intent"intent)"4 """"ret&rn(binder):

emonstrate

%-Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

""? "" ""02verride ""p&blic"void"on"estroy()"4 """"s&per.on"estroy(): """" """"@.add(new"#illJob()): ""? "" ""private"void"e(ecuteScriptImpl(String"script> """""""""""""""""""""""""""""""""IScript6es&lt"cb)"4 """"@.add(new"E(ecuteScriptJob(script>"cb)):"""" ""? "" ""6&nnable"@5rocessor#new"Runnable()"4 """"p&blic"void"run()"4 """"""w-ile"(tr&e)"4 """"""""tr+"4 """"""""""Job"A#@.ta)e(): """""""""" """"""""""if"(A.stop+!read())"4 """"""""""""brea.: """"""""""? """"""""""else"4 """"""""""""A.process(): """"""""""? """"""""? """"""""catc-"(Interr&pted8xception"e)"4 """"""""""brea.: """"""""? """"""? """"? ""?: "" ""class"Job"4 """"boolean"stop+!read()"4 """"""ret&rn(false): """"? """" """"void"process()"4 """"""//"no'op """"? ""? "" ""class"VillJob"extends"Job"4 """"02verride """"boolean"stop+!read()"4 """"""ret&rn(tr&e): """"? ""? "" ""class"8xec&teScriptJob"extends"Job"4 """"IScript6es&lt"cb: """"String"script:

%-%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

7our ,)n #:dvanced& Services

"""" """"E(ecuteScriptJob(String"script>"IScript6es&lt"cb)"4 """"""t-is.script#script: """"""t-is.cb#cb: """"? """" """"void"process()"4 """"""tr+"4 """"""""cb.success(i.eval(script).toString()): """"""? """"""catc-"(<-rowable"e)"4 """"""""*og.e($;s-Service$>"$8rror"exec&ting"script$>"e): """""""" """"""""tr+"4 """"""""""cb.failure(e.get%essage()): """"""""? """"""""catc-"(<-rowable"t)"4 """"""""""*og.e($;s-Service$> """"""""""""""""$8rror"ret&rning"exception"to"client$> """"""""""""""""t): """"""""? """"""? """"? ""? ?

0oti%e that the servi%e7s o>n A!. Lust nee s the IScript6es&lt parameter, >hi%h %an be passe aroun an use like any other +ava obLe%t. 5he $a%t that it happens to %ause %alls to be ma e syn%hronously ba%k to the remote %lient is invisible to the servi%e. 5he net result is that the %lient %an %all the servi%e an >ithout tying up the %lient7s ". threa . get its results

%-.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 1.

!inding :vailable :ctions via +ntrospection

#ometimes, you kno> Lust >hat you >ant to o, su%h as isplay one o$ your other a%tivities. #ometimes, you have a pretty goo i ea o$ >hat you >ant to o, su%h as vie> the %ontent represente by a Dri, or have the user pi%k a pie%e o$ %ontent o$ some M.MB type. #ometimes, you7re lost. All you have is a %ontent Dri, an you on7t really kno> >hat you %an o >ith it. (or e;ample, suppose you >ere %reating a %ommon tagging subsystem $or An roi , >here users %oul tag pie%es o$ %ontent M %onta%ts, Web "RLs, geographi% lo%ations, et%. Dour subsystem >oul hol onto the Dri o$ the %ontent plus the asso%iate tags, so other subsystems %oul , say, ask $or all pie%es o$ %ontent re$eren%ing some tag. 5hat7s all >ell an goo . )o>ever, you probably nee some sort o$ maintenan%e a%tivity, >here users %oul vie> all their tags an the pie%es o$ %ontent so tagge . 5his might even serve as a <uasi3bookmark servi%e $or items on their phone. 5he problem is, the user is going to e;pe%t to be able to o use$ul things >ith the %ontent they $in in your subsystem, su%h as ial a %onta%t or sho> a map $or a lo%ation.

%-0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

!inding :vailable :ctions via +ntrospection

5he problem is, you have absolutely no i ea >hat is all possible >ith any given %ontent Dri. Dou probably %an vie> any o$ them, but %an you e it themJ Can you ial themJ #in%e ne> appli%ations >ith ne> types o$ %ontent %oul be a e by any user at any time, you %an7t even assume you kno> all possible %ombinations Lust by looking at the sto%k appli%ations shippe on all An roi evi%es. (ortunately, the An roi evelopers thought o$ this.

An roi o$$ers various means by >hi%h you %an present to your users a set o$ likely a%tivities to spa>n $or a given %ontent Dri...even i$ you have no i ea >hat that %ontent Dri really represents. 5his %hapter e;plores some o$ these Dri a%tion introspe%tion tools.

Pick ?<m
#ometimes, you kno> your %ontent Dri represents a %olle%tion o$ some type, su%h as content,//contacts/people representing the list o$ %onta%ts in the sto%k An roi %onta%ts list. .n this %ase, you %an let the user pi%k a %onta%t that your a%tivity %an then use &e.g., tag it, ial it'. 5o o this, you nee to %reate an intent $or the 3C<I2=/5ICV on the target Dri, then start a sub a%tivity &via start3ctivit+Kor6es&lt()' to allo> the user to pi%k a pie%e o$ %ontent o$ the spe%i$ie type. .$ your on3ctivit+6es&lt()" %allba%k $or this re<uest gets a 68SD*</2V result %o e, your ata string %an be parse into a Dri representing the %hosen pie%e o$ %ontent. (or e;ample, take a look at Introspection/5ic. in the sample appli%ations. 5his a%tivity gives you a $iel $or a %olle%tion Dri &>ith content,//contacts/people pre3$ille in $or your %onvenien%e', plus a really big 68imme:9 button*
!xml"version#$1.%$"encoding#$&tf'($!) *inear*a+o&t"xmlns,android#$-ttp,//sc-emas.android.com/ap./res/android$ ""android,orientation#$vertical$ ""android,la+o&t/widt-#$fill/parent$ ""android,la+o&t/-eig-t#$fill/parent$ "") %-2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

!inding :vailable :ctions via +ntrospection

"" 8dit<ext"android,id#$01id/t+pe$ """"android,la+o&t/widt-#$fill/parent$" """"android,la+o&t/-eig-t#$wrap/content$ """"android,c&rsorVisible#$tr&e$ """"android,editable#$tr&e$ """"android,single*ine#$tr&e$ """"android,text#$content,//contacts/people$ ""/) "" ;&tton """"android,id#$01id/pic.$ """"android,la+o&t/widt-#$fill/parent$" """"android,la+o&t/-eig-t#$fill/parent$ """"android,text#$GimmeN$ """"android,la+o&t/weig-t#$1$ ""/) /*inear*a+o&t)

"pon being %li%ke , the button %reates the 3C<I2=/5ICV on the user3 supplie %olle%tion Dri an starts the sub3a%tivity. When that sub3a%tivity %ompletes >ith 68SD*</2V, the 3C<I2=/VI8W is invoke on the resulting %ontent Dri.
p&blic"class"5ic.7emo"extends"3ctivit+"4 ""static"final"int"5ICV/68[D8S<#1JJG: ""private"8dit<ext"t+pe: ""02verride ""p&blic"void"onCreate(;&ndle"icicle)"4 """"s&per.onCreate(icicle): """"setContentView(6.la+o&t.main): """"t+pe#(8dit<ext)findViewById(6.id.t+pe): """" """";&tton"btn#(;&tton)findViewById(6.id.pic.): """" """"btn.set$nClic)Listener(new"View.$nClic)Listener()"4 """"""p&blic"void"onClic)(View"view)"4 """"""""Intent"i#new"Intent(Intent.3C<I2=/5ICV> """"""""""""""""""""Dri.parse(t+pe.get+e(t().toString())): """"""""start&ctivity'orResult(i>"5ICV/68[D8S<): """"""? """"?): ""? ""02verride ""protected"void"on&ctivityResult(int"re@&estCode>"int"res&ltCode> """""""""""""""""""""""""""""""""""Intent"data)"4 """"if"(re@&estCode##5ICV/68[D8S<)"4 """"""if"(res&ltCode##68SD*</2V)"4 """"""""""start&ctivity(new"Intent(Intent.3C<I2=/VI8W> """""""""""""""""""""""""""""""""""data.get"ata())):

%-3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

!inding :vailable :ctions via +ntrospection

""""""? """"? ""? ?

5he result* the user %hooses a %olle%tion, pi%ks a pie%e o$ %ontent, an vie>s it.

!igure $0/ The Pick9emo sample application* as initially launched

%-4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

!inding :vailable :ctions via +ntrospection

!igure $2/ The same application* after clicking the D'imme!D button* sho)ing the list of available people

!igure $3/ : vie) of a contact* launched by Pick9emo after choosing one of the people from the pick list

%-5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

!inding :vailable :ctions via +ntrospection

Would 7ou ike to See the 8enuF


Another >ay to give the user >ays to take a%tions on a pie%e o$ %ontent, >ithout you kno>ing >hat a%tions are possible, is to inLe%t a set o$ menu %hoi%es into the options menu via addIntent2ptions(). 5his metho , available on 9en&, takes an Intent an other parameters an $ills in a set o$ menu %hoi%es on the 9en& instan%e, ea%h representing one possible a%tion. Choosing one o$ those menu %hoi%es spa>ns the asso%iate a%tivity. 5he %anoni%al e;ample o$ using addIntent2ptions() illustrates another $lavor o$ having a pie%e o$ %ontent an not kno>ing the a%tions that %an be taken. An roi appli%ations are per$e%tly %apable o$ a ing ne> a%tions to e;isting %ontent types, so even though you >rote your appli%ation an kno> >hat you e;pe%t to be one >ith your %ontent, there may be other options you are una>are o$ that are available to users. (or e;ample, imagine the tagging subsystem mentione in the intro u%tion to this %hapter. .t >oul be very annoying to users i$, every time they >ante to tag a pie%e o$ %ontent, they ha to go to a separate tagging tool, then turn aroun an pi%k the %ontent they Lust ha been >orking on &i$ that is even te%hni%ally possible' be$ore asso%iating tags >ith it. .nstea , they >oul probably pre$er a menu %hoi%e in the %ontent7s o>n 6home9 a%tivity >here they %an in i%ate they >ant to tag it, >hi%h lea s them to the set3a3tag a%tivity an tells that a%tivity >hat %ontent shoul get tagge . 5o a%%omplish this, the tagging subsystem shoul set up an intent $ilter, supporting any pie%e o$ %ontent, >ith their o>n a%tion &e.g., 3C<I2=/<3G' an a %ategory o$ C3<8G26C/3*<86=3<IV8. 5he %ategory C3<8G26C/3*<86=3<IV8" is the %onvention $or one appli%ation a ing a%tions to another appli%ation7s %ontent. .$ you >ant to >rite a%tivities that are a>are o$ possible a 3ons like tagging, you shoul use addIntent2ptions() to a those a 3ons7 a%tions to your options menu, su%h as the $ollo>ing*
Intent"intent"#"new"Intent(n&ll>"m+ContentDri):

%%6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

!inding :vailable :ctions via +ntrospection

intent.addCategory(Intent.3*<86=3<IV8/C3<8G26C): men&.addIntent$ptions(9en&.3*<86=3<IV8>"%> """""""""""""""""""""new"Component-ame(t-is> """""""""""""""""""""""""""""""""""""""9+3ctivit+.class)> """""""""""""""""""""n&ll>"intent>"%>"n&ll):

)ere, m+ContentDri is the %ontent Dri o$ >hatever is being vie>e by the user in this a%tivity, 9+3ctivit+ is the name o$ the a%tivity %lass, an men& is the menu being mo i$ie . .n this %ase, the Intent >e are using to pi%k a%tions $rom re<uires that appropriate intent re%eivers support the C3<8G26C/3*<86=3<IV8. 5hen, >e a the options to the menu >ith addIntent2ptions() an the $ollo>ing parameters*

5he sort position $or this set o$ menu %hoi%es, typi%ally set to %" &appear in the or er a e to the menu' or 3*<86=3<IV8 &appear a$ter other menu %hoi%es' A uni<ue number $or this set o$ menu %hoi%es, or % i$ you o not nee a number A Component=ame instan%e representing the a%tivity that is populating its menu M this is use to $ilter out the a%tivity7s o>n a%tions, so the a%tivity %an han le its o>n a%tions as it sees $it An array o$ Intent instan%es that are the 6spe%i$i%9 mat%hes M any a%tions mat%hing those intents are sho>n $irst in the menu be$ore any other possible a%tions 5he Intent $or >hi%h you >ant the available a%tions A set o$ $lags. 5he only one o$ likely relevan%e is represente as 93<CB/78K3D*</2=*C, >hi%h means mat%hing a%tions must also implement the 78K3D*</C3<8G26C %ategory. .$ you o not nee this, use a value o$ % $or the $lags. An array o$ 9en&.Item, >hi%h >ill hol the menu items mat%hing the array o$ Intent instan%es supplie as the 6spe%i$i%s9, or n&ll i$ you o not nee those items &or are not using 6spe%i$i%s9'

%%Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

!inding :vailable :ctions via +ntrospection

:sking :round
5he addIntent2ptions() metho in turn uses @&er+Intent3ctivit+2ptions()" $or the 6heavy li$ting9 o$ $in ing possible a%tions. 5he @&er+Intent3ctivit+2ptions() metho is implemente on 5ac.age9anager, >hi%h is available to your a%tivity via get5ac.age9anager(). 5he @&er+Intent3ctivit+2ptions() metho takes some o$ the same parameters as oes addIntent2ptions(), notably the %aller Component=ame, the 6spe%i$i%s9 array o$ Intent instan%es, the overall Intent representing the a%tions you are seeking, an the set o$ $lags. .t returns a *ist o$ Intent" instan%es mat%hing the state %riteria, >ith the 6spe%i$i%s9 ones $irst. .$ you >oul like to o$$er alternative a%tions to users, but by means other than addIntent2ptions(), you %oul %all @&er+Intent3ctivit+2ptions(), get the Intent instan%es, then use them to populate some other user inter$a%e &e.g., a toolbar'.

%%%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

PART IV Advanced Development

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

CHAPTER 10

Testing 7our Patience

!resumably, you >ill >ant to test your %o e, beyon Lust playing aroun >ith it yoursel$ by han . 5o that en , An roi in%lu es the +"nit test $rame>ork in the #@K, along >ith spe%ial test %lasses that >ill help you buil test %ases that e;er%ise An roi %omponents, like a%tivities an servi%es. Bven better, An roi -.A has Igone the e;tra mileI an %an pre3generate your test harness $or you, to make it easier $or you to a in your o>n tests. 5his %hapter assumes you have some $amiliarity >ith +"nit, though you %ertainly o not nee to be an e;pert. Dou %an learn more about +"nit at the +"nit site, $rom various books, an $rom the +"nit Dahoo $orum.

7ou 'et What They 'ive 7ou


When you %reate a proLe%t in An roi -.A using an roi %reate proLe%t, An roi automati%ally %reates a ne> tests/ ire%tory insi e the proLe%t ire%tory. .$ you look in there, you >ill see a %omplete set o$ An roi proLe%t arti$a%ts* mani$est, sour%e ire%tories, resour%es, et%. 5his is a%tually a test proLe%t, esigne to partner >ith the main proLe%t to %reate a %omplete testing solution. .n $a%t, that test proLe%t is all rea y to go, other than not having any tests o$ signi$i%an%e. .$ you buil an install your main proLe%t &onto an emulator or
%%0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Testing 7our Patience

evi%e', then buil an install the test proLe%t, you >ill be able to run unit tests. An roi a very ru imentary +"nit runner, %alle Instr&mentation<est6&nner. #in%e this %lass resi es in the An roi environment &emulator or evi%e', you nee to invoke the runner to run your tests on the emulator or evi%e itsel$. 5o o this, you %an run the $ollo>ing %omman $rom a %onsole*
adb"s-ell"am"instr&ment"'w" com.commonsware.android.database.tests/android.test.Instr&mentation<est6&nner

ships

>ith

.n this %ase, >e are instru%ting An roi to run all the available test %ases $or the com.commonsware.android.database pa%kage, as this %hapter uses some tests implemente on the 7atabase/Contacts sample proLe%t. .$ you >ere to run this on your o>n proLe%t, substituting in your pa%kage name, >ith Lust the auto3generate test $iles, you shoul see results akin to*
com.commonsware.android.database.Contacts7emo<est,. <est"res&lts"for"Instr&mentation<est6&nner#. <ime,"%.X1 2V"(1"test)

5he $irst line >ill i$$er, base upon your pa%kage an the name o$ your proLe%t7s initial a%tivity, but the rest shoul be the same, sho>ing that a single test >as run, su%%ess$ully. G$ %ourse, this is only the beginning.

<recting 8ore Scaffolding


)ere is the sour%e %o e $or the test %ase that An roi generates $or you*
pac.age"com.commonsware.android.database:

automati%ally

%%2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Testing 7our Patience

import"android.test.3ctivit+Instr&mentation<estCase: /MM "M"<-is"is"a"simple"framewor."for"a"test"of"an"3pplication."See "M"40lin."android.test.3pplication<estCase"3pplication<estCase?"for"more" information"on "M"-ow"to"write"and"extend"3pplication"tests. "M" p/) "M"<o"r&n"t-is"test>"+o&"can"t+pe, "M"adb"s-ell"am"instr&ment"'w"Z "M"'e"class"com.commonsware.android.database.Contacts7emo<est"Z "M"com.commonsware.android.database.tests/android.test.Instr&mentation<est6&nner "M/ p&blic"class"Contacts7emo<est"extends" 3ctivit+Instr&mentation<estCase Contacts7emo)"4 "p&blic"Contacts"emo+est()"4 "s&per($com.commonsware.android.database$>"Contacts7emo.class): "? ?

As you %an see, there are no a%tual test metho s. .nstea , >e have an 3ctivit+Instr&mentation<estCase implementation name Contacts7emo<est. 5he %lass name >as generate by a ing 5est to the en o$ the main a%tivity &Contacts7emo' o$ the proLe%t. .n the ne;t se%tion, >e >ill e;amine 3ctivit+Instr&mentation<estCase more %losely an see ho> you %an use it to, as the name suggests, test your a%tivities. )o>ever, you are >el%ome to %reate or inary +"nit test %ases in An roi M a$ter all, this is Lust +"nit, merely augmente by An roi . #o, you %an %reate %lasses like this*
pac.age"com.commonsware.android.database: import"A&nit.framewor..<estCase: p&blic"class"Sill+<est"extends"<estCase"4 ""protected"void"setUp()"t-rows"8xception"4 """"s&per.setUp(): """" """"//"do"initialiIation"-ere>"r&n"on"ever+"test"met-od ""? "" ""protected"void"tear"own()"t-rows"8xception"4

%%3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Testing 7our Patience

""""//"do"termination"-ere>"r&n"on"ever+"test"met-od """"s&per.tear"own(): ""? "" ""p&blic"void"test-onsense()"4 """"assert+rue(1##1): ""? ?

5here is nothing An roi 3spe%i$i% in this test %ase. .t is simply stan ar +"nit, albeit a bit silly. Dou %an also %reate test suites, to bun le up sets o$ tests $or e;e%ution. )ere, though, i$ you >ant, you %an take a vantage o$ a bit o$ An roi magi%* <estS&ite;&ilder. <estS&ite;&ilder uses re$le%tion to $in test %ases that nee to be run, as sho>n belo>*
pac.age"com.commonsware.android.database: import"android.test.s&iteb&ilder.<estS&ite;&ilder: import"A&nit.framewor..<est: import"A&nit.framewor..<estS&ite: p&blic"class"K&llS&ite"extends"<estS&ite"4 ""p&blic"static"<est"suite()"4 """"ret&rn(new"+estSuiteBuilder(K&llS&ite.class) """""""""""""""".include&ll ac)agesUnder*ere() """""""""""""""".build()): ""? ?

)ere, >e are telling An roi to $in all test %ases lo%ate in K&llS&ite7s pa%kage &com.commonsware.android.database' an all sub3pa%kages, an to buil a <estS&ite out o$ those %ontents. A test suite may or may not be ne%essary $or you. 5he %omman sho>n above to e;e%ute tests >ill e;e%ute any test %ases it %an $in $or the pa%kage spe%i$ie on the %omman line. .$ you >ant to limit the s%ope o$ a test run, though, you %an use the 'e s>it%h to spe%i$y a test %ase or suite to run*
adb"s-ell"am"instr&ment"'e"class" com.commonsware.android.database.Contacts7emo<est"'w" com.commonsware.android.database.tests/android.test.Instr&mentation<est6&nner

%%4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Testing 7our Patience

)ere, >e in i%ate >e only >ant to run Contacts7emo<est, not all test %ases $oun in the pa%kage.

Testing Eeal Stuff


While or inary +"nit tests are %ertainly help$ul, they are still $airly limite , sin%e mu%h o$ your appli%ation logi% may be tie up in a%tivities, servi%es, an the like. 5o that en , An roi has a series o$ <estCase %lasses you %an e;ten esigne spe%i$i%ally to assist in testing these sorts o$ %omponents.

Activity$nstrumentationTestCase
5he test %ase %reate by An roi 7s #@K tools, Contacts7emo<est in our e;ample, is an 3ctivit+Instr&mentation<estCase. 5his %lass >ill run your a%tivity $or you, giving you a%%ess to the 3ctivit+ obLe%t itsel$. Dou %an then*

A%%ess your >i gets .nvoke publi% an pa%kage3private metho s &more on this belo>' #imulate key events

G$ %ourse, the automati%ally3generate 3ctivit+Instr&mentation<estCase" oes none o$ that, sin%e it oes not kno> mu%h about your a%tivity. /elo> you >ill $in an augmente version o$ Contacts7emo<est that oes a little bit more*
pac.age"com.commonsware.android.database: import"android.test.3ctivit+Instr&mentation<estCase: import"android.widget.*istView: import"android.widget.Spinner: p&blic"class"Contacts7emo<est ""extends"3ctivit+Instr&mentation<estCase Contacts7emo)"4 ""private"*istView"list#n&ll: ""private"Spinner"spinner#n&ll: "" ""p&blic"Contacts"emo+est()"4

%%5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Testing 7our Patience

""""s&per($com.commonsware.android.database$> """"""""""Contacts7emo.class): ""? ""02verride ""protected"void"setUp()"t-rows"8xception"4 """"s&per.setUp(): """" """"Contacts7emo"activit+#get&ctivity(): """" """"list#(*istView)activit+.findViewById(android.6.id.list): """"spinner#(Spinner)activit+.findViewById(6.id.spinner): ""? "" ""p&blic"void"testSpinnerCount()"4 """"assert+rue(spinner.get&dapter().getCount()##J): ""? "" ""p&blic"void"testList"efaultCount()"4 """"assert+rue(list.get&dapter().getCount())%): ""? ?

)ere are the steps to making use o$ 3ctivit+Instr&mentation<estCase* -. B;ten the %lass to %reate your o>n implementation. #in%e is a generi%, you nee to supply the name o$ the a%tivity being teste &e.g., 3ctivit+Instr&mentation<estCase Contacts7emo)'.
3ctivit+Instr&mentation<estCase

2. .n the %onstru%tor, >hen you %hain to the super%lass, supply the name o$ the pa%kage o$ the a%tivity plus the a%tivity %lass itsel$. Dou %an optionally supply a thir parameter, a boolean in i%ating i$ the a%tivity shoul be laun%he in tou%h mo e or not. ?. .n setDp(), use get3ctivit+() to get your han s on your 3ctivit+" obLe%t, alrea y type%ast to the proper type &e.g., Contacts7emo' %ourtesy o$ our generi%. Dou %an also at this time a%%ess any >i gets, sin%e the a%tivity is up an running by this point. =. .$ nee e , %lean up stu$$ in tear7own(), no i$$erent than >ith any other +"nit test %aseQ A. .mplement test metho s to e;er%ise your a%tivity. .n this %ase, >e simply %on$irm that the Spinner has three items in its rop3 o>n list an there is at least one %onta%t loa e into the *istView by

%.6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Testing 7our Patience

e$ault. Dou %oul , ho>ever, use sendVe+s() an the like to simulate user input. .$ you are looking at your emulator or evi%e >hile this test is running, you >ill a%tually see the a%tivity laun%he on3s%reen. 3ctivit+Instr&mentation<estCase %reates a true running %opy o$ the a%tivity. 5his means you get a%%ess to everything you nee O on the other han , it oes mean that the test %ase runs slo>ly, sin%e the a%tivity nee s to be %reate an estroye $or ea%h test metho in the test %ase. .$ your a%tivity oes a lot on startup an Qor shut o>n, this may make running your tests a bit sluggish. 0ote that your 3ctivit+Instr&mentation<estCase resi es in the same pa%kage as the A%tivity it is testing M Contacts7emo<est an Contacts7emo are both in com.commonsware.android.database, $or e;ample. 5his allo>s Contacts7emo<est to a%%ess both publi% an pa%kage3private metho s an ata members. Contacts7emo<est still %annot a%%ess private metho s, though. 5his allo>s 3ctivit+Instr&mentation<estCase to behave in a >hite3 bo; &or at least gray3bo;' $ashion, inspe%ting the insi es o$ the teste a%tivities in a ition to testing the publi% A!.. 0o>, that An roi 7s o>n tools %reate an sub%lass $or you, that %lass is o$$i%ially epre%ate . 5hey a vise using 3ctivit+Instr&mentation<estCaseE instea , >hi%h o$$ers the same basi% $un%tionality, >ith a $e> e;tras, su%h as being able to spe%i$y the Intent that is use to laun%h the a%tivity being teste . 5his is goo $or testing sear%h provi ers, $or e;ample.
3ctivit+Instr&mentation<estCase

espite

the

$a%t

AndroidTestCase
(or tests that only nee a%%ess to your appli%ation resour%es, you %an skip some o$ the overhea o$ 3ctivit+Instr&mentation<estCase an use 3ndroid<estCase. .n 3ndroid<estCase, you are given a Context an not mu%h more, so anything you %an rea%h $rom a Context is testable, but in ivi ual a%tivities or servi%es are not.

%.Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Testing 7our Patience

While this may seem some>hat useless, bear in min that a lot o$ the stati% testing o$ your a%tivities >ill %ome in the $orm o$ testing the layout* are the >i gets i enti$ie properly, are they positione properly, oes the $o%us >ork, et%. As it turns out, none o$ that a%tually nee s an 3ctivit+ obLe%t M so long as you %an get the in$late View hierar%hy, you %an per$orm those sorts o$ tests. (or e;ample, here is an
3ndroid<estCase

implementation,

Contacts7emo;ase<est*
pac.age"com.commonsware.android.database: import"android.test.3ndroid<estCase: import"android.view.*a+o&tInflater: import"android.view.View: import"android.view.ViewGro&p: import"android.widget.*istView: import"android.widget.Spinner: p&blic"class"Contacts7emo;ase<est"extends"3ndroid<estCase"4 ""private"*istView"list#n&ll: ""private"Spinner"spinner#n&ll: ""private"ViewGro&p"root#n&ll: "" ""02verride ""protected"void"setUp()"t-rows"8xception"4 """"s&per.setUp(): """" """"*a+o&tInflater"inflater#*a+o&tInflater.from(getConte(t()): """" """"root#(ViewGro&p)inflater.inflate(6.la+o&t.main>"n&ll): """"root.measure(F(%>"JE%): """"root.layout(%>"%>"F(%>"JE%): """"list#(*istView)root.findViewById(android.6.id.list): """"spinner#(Spinner)root.findViewById(6.id.spinner): ""? "" ""p&blic"void"testE(ists()"4 """"assert-ot-ull(list): """"assert-ot-ull(spinner): ""? "" ""p&blic"void"testRelative osition()"4 """"assert+rue(list.get+op())#spinner.getBottom()): """"assert+rue(list.getLeft()##spinner.getLeft()): """"assert+rue(list.getRig!t()##spinner.getRig!t()): ""? ?

%.%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Testing 7our Patience

Most o$ the %ompli%ate >ork is per$orme in setDp()* -. .n$late our layout using a *a+o&tInflater an the Context supplie by getContext()

2. Measure an lay out the >i gets in the in$late View hierar%hy M in this %ase, >e lay them out on a =20;?20 s%reen ?. A%%ess the in ivi ual >i gets to be teste At that point, >e %an test stati% in$ormation on the >i gets, but >e %annot %ause them to %hange very easily &e.g., >e %annot simulate keypresses'. .n the %ase o$ Contacts7emo;ase<est, >e simply %on$irm the >i gets e;ist an are lai out as e;pe%te . We %oul use Koc&sKinder to test >hether $o%us %hanges $rom one >i get to the ne;t shoul >ork as e;pe%te . We %oul ensure our resour%es e;ist un er their esire names, test to see i$ our $onts e;ist in our assets, or anything else >e %an a%%omplish >ith Lust a Context. #in%e >e are not %reating an estroying a%tivities >ith ea%h test %ase, these tests shoul run substantially $aster.

=ther Alternatives
An roi also o$$ers various other test %ase base %lasses esigne to assist in testing An roi %omponents, su%h as*
Service<estCase,

the name

use $or testing servi%es, as you might e;pe%t given

3ctivit+Dnit<estCase, a <estCase 3ctivit+Instr&mentation<estCase',

that %reates the 3ctivit+ &like but oes not $ully %onne%t it to the environment, so you %an supply a mo%k Context, a mo%k 3pplication, an other mo%k obLe%ts to test out various s%enarios
3pplication<estCase, $or testing %ustom 3pplication sub%lasses

8onkeying :round
.n epen ent $rom the +"nit system is the Monkey.
%..
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Testing 7our Patience

5he Monkey is a test program that simulates ran om user input. .t is esigne $or Ibash testingI, %on$irming that no matter >hat the user oes, the appli%ation >ill not %rash. 5he appli%ation may have o results M ran om input entere into a 5>itter %lient may, in ee , post that ran om input to 5>itter. 5he Monkey oes not test to make sure that results o$ ran om input make senseO it only tests to make sure ran om input oes not blo> up the program. Dou %an run the Monkey by setting up your initial starting point &e.g., the main a%tivity in your appli%ation' on your evi%e or emulator, then running a %omman like this*
adb"s-ell"mon.e+"'p"com.commonsware.android.database"'v"''t-rottle"1%%"X%%

Working $rom right to le$t, >e are asking $or 400 simulate events, throttle to run every -00 millise%on s. We >ant to see a list o$ the invoke events &'v' an >e >ant to thro> out any event that might %ause the Monkey to leave our appli%ation, as etermine by the appli%ation7s pa%kage &'p"com.commonsware.android.database'. 5he Monkey >ill simulate keypresses &both FWBR5D an spe%ialiCe har >are keys, like the volume %ontrols', @3pa Qtra%kball moves, an sli ing the keyboar open or %lose . 0ote that the latter may %ause your emulator some %on$usion, as the emulator itsel$ oes not itsel$ a%tually rotate, so you may en up >ith your s%reen appearing in lan s%ape >hile the emulator is still, itsel$, portrait. +ust rotate the emulator a %ouple o$ times &e.g., Ctrl)' K1E)' to %lear up the problem. (or playing >ith a Monkey, the above %omman >orks $ine. )o>ever, i$ you >ant to regularly test your appli%ation this >ay, you may nee some measure o$ repeatability. A$ter all, the parti%ular set o$ input events that trigger your %rash may not %ome up all that o$ten, an >ithout that repeatable s%enario, it >ill be i$$i%ult to repair the bug, let alone test that the repair >orke . 5o eal >ith this, the Monkey o$$ers the 's s>it%h, >here you provi e a see $or the ran om number generator. /y e$ault, the Monkey %reates its o>n
%.$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Testing 7our Patience

see , giving totally ran om results. .$ you supply the see , >hile the se<uen%e o$ events is ran om, it is ran om $or that see M repeate ly using the same see >ill give you the same events. .$ you %an arrange to ete%t a %rash an kno> >hat see >as use to %reate that %rash, you may >ell be able to repro u%e the %rash. 5here are many more Monkey options, to %ontrol the mi; o$ event types, to generate pro$iling reports as tests are run, an so on. 5he Monkey o%umentation in the #@K7s @eveloper7s 8ui e %overs all o$ that an more.

%.0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Subscribe to updates at http://commonsware.com

Special Creative Commons BY-NC-SA 3.0 License Edition

Gey)ord +ndex

Class...............................................
A%%elerate@e%elerate.nterpolator...................9A A%%elerate.nterpolator.....................................9A A%tivity.....-4, A0, -2=, -423-10, -19, 229, 2?0, 2?2, 2?? A%tivity.nstrumentation5estCase...221, 22932?-, 2?? A%tivity.nstrumentation5estCase2.................2?A%tivity"nit5estCase.......................................2?? A apter......................................?03?2, ?A, ?4, -=4 A apter,ie>.Gn.tem#ele%te Listener...........=4 AlarmManager.......44, -42, -19, -20, -22, -2?, -2A Alert@ialog......................................................209 AlphaAnimation..............................21, 9239=, 91 AnalogClo%k......................................................A0 An roi 5estCase......................................2?-, 2?2 Animation........................................21, 22, 9=394 AnimationListener......................................9=, 9A Animation#et........................................21, 94, 91 Animation"tils.................................................9= Appli%ation......................................................2??

Appli%ation5estCase........................................2?? App#ervi%e..................................-223-2A, -21, -22 AppWi get)ost................................................44 AppWi get)ost,ie>.......................................44 AppWi getManager..............................A4, 4-, 4A AppWi get!rovi er........................AA, A9, 4=, 4A Asyn%5ask.........................................................--9 Attribute#et.......................................................-4 Au io#ervi%e....................................................-9? /aseColumns....................................................-A0 /atteryMonitor.........................................-1=, -14 /itmap@ra>able..............................................-20 /oolean#etting.................................................-29 /roa %astRe%eiver.A03A2, AA, 4A, 44, -493-1-, -1?, -2-, -22, -2A /roa %astRe%iever.............................................AA /sh#ervi%e.................................................20?, 2-/sh#ervi%e@emo.............................................20A /utton.............2-, 2?, 2=, =0, A0, A-, A2, 1A, 14, 22 CallLog................................................-A03-A2, -40

%.3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Gey)ord +ndex
CallLog.Calls....................................................-A0 Call!lusA apter........................................-A2, -40 Camera......................................--?3--A, --13--9, 2-Camera.!arameters....................................--A, --1 Camera.!i%tureCallba%k..................................--9 Camera.#hutterCallba%k..................................--2 Char#e<uen%e..................................................-92 Che%k/o;................................................2-, 2A, 21 Chronometer.....................................................A0 Component0ame.......................A4, 200, 22-, 222 Constants.nstaller............................................-=Conta%ts.............................................-=2, -=?, -A0 Conta%ts.Conta%tMetho sColumns...............-=9 Conta%ts.!eopleColumns.........................-=2, -=9 Conta%ts.!hones..............................................-=2 Conta%ts.!honesColumns...............................-=2 Conta%ts@emo....................-=?, -=1, 221, 2?0, 2?Conta%ts@emo/ase5est...........................2?2, 2?? Conta%ts@emo5est...........................221, 229, 2?Content!rovi er........................................-A-, -42 Content,alues..................................................-A1 Conte;t..............-4, 9=, -2=, -?0, -10, -19, 2?-, 2?? Cursor..............................?-, -A03-A?, -A4, -A1, -40 CursorA apter.................................................-A2 Cursor+oiner......................................................-ACursorWrapper..........................................-A-, -A2 Cy%le.nterpolator........................................9=, 94 @atabase.nstaller......................................-=03-=2 @ea GbLe%tB;%eption.....................................20@e%elerate.nterpolator.....................................9A @ra>able...............................2?324, =2, 1-, 12, -9? @ra>ableQ8ra ient@emo.................................12 B it5e;t..............................................................AB;%eption..........................................................2-B;e%ute#%ript+ob...............................................2-(o%us(in er.....................................................2?? (rameLayout.....................................................A0 (ull#uite...........................................................222 8eoWebGne........................................................2 )ea er(ooter@emo..........................................?2 .R+oin)an ler............................................-A4, -A1 ./in er.............................................................200 .mage/utton...............-?, -=, -9, A0, A-, AA, A2, 9A .mage,ie>..................................................A0, -1? .nput#tream......................................................-=.nstrumentation5estRunner..........................224 .ntent ;ii, AA, 40, 4-, 44, -413-1-, -1?3-1A, -19, -20, -22, -2A, -9-, 200, 204, 2203222, 2?.ntent#ervi%e........................................A4, 44, -2A .nterpolator.................................................9A, 94 .#%ript..............................................20?, 204, 202 .#%riptResult.....................................202, 209, 2-? +oinCa%he..........................................................-A1 +oinCursor.....................................-A-3-A?, -A43-A2 +oin@emo....................................-A0, -A1, -A2, -40 Layout.n$later............................................A2, 2?? Linear.nterpolator............................................9A LinearLayout..............................-A, ?2, A0, 29, 90 Linke /lo%kingFueue.....................................2-Linke )ashMap...............................................-A1 List.......................................................?A, -92, 222

%.4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Gey)ord +ndex
ListA%tivity..............................?2, ?4, =?, -=?, -40 List,ie>. 293?2, ?4, ?2, =2, =?, =4, A1, 12, 1=, -=?, -==, -40, 2?0 Lo%ater.................................................................= Lo%ationListener.............................................=, 2 Lo%ationManager................................................= Map...................................................................-92 Me iaQAu io.....................................................-0Me ia!layer................................-00, -0-, -0=, -0A Menu..........................................................9=, 220 Menu..tem........................................................22Meter................................-?3-4, -2, -9, 2-, -9?, -9A Meter@emo........................................................2MyA%tivity........................................................220ine!at%h@emo................................................22 0oteA%tivity.....................................................-4= 0oteB itor.......................................................-4= GnAlarmRe%eiver.....................................-223-2= Gn/ootComplete ..........................................-49 Gn/ootRe%eiver........................................-49, -2GnCli%kListener.................................................AGnWi(iChangeRe%eiver...................................-1!a%kageManager.............................................222 !ar%elable.........................................................-92 !en ing.ntent................................A-, A2, -19, -22 !hotoCallba%k..................................................-20 !i%ture@emo.............................................--2, -20 !o>erManager..........................................-20, -2? !re$eren%eA%tivity......................................A2, 40 !revie>@emo.............................................--2, --? !rogress/ar...............................-?, -=, A0, -1?, -14 RelativeLayout..................................................A0 RemoteB;%eption.............................................20Remote#ervi%e.................................................20? Remote,ie>s...............................A0, A-, AA3A9, 4RotateAnimation........................................21, 9= #ave!hoto5ask..........................................--9, -20 #%aleAnimation.................................................21 #%roll,ie>........................................................-22 #e%tion...............................................................?A #e%tione A apter..................................?2, ?A, ?4 #e%tione @emo...........................................?2, ?4 #eek/ar.........................................................-?, 22 #ele%torA apter................................................=4 #ele%tor@emo..............................................=?, =4 #ele%torWrapper...............................................=4 #ensor...............................................................-2A #ensorBvent......................................................-2A #ensorBventListener.................................-2A, -21 #ensorManager..................................-2=, -2A, -?0 #ervi%e........................A03A2, A4, 44, -42, -19, -99 #ervi%eConne%tion...................................200, 20#ervi%e5estCase...............................................2?? #ettings......................................................-22, -9#ettings.#e%ure.........................................-22, -92 #ettings.#ystem.................................-22, -29, -92 #ettings#etter....................................-22, -90, -92 #haker.........................................................-293-?#haker.Callba%k................................................-?#haker@emo..............................................-29, -?#hare !re$eren%es............................................A2

%.5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Gey)ord +ndex
#impleCursorA apter....................?-, ?2, -=4, -=9 #li ing!anel....................................90, 92, 9=394 #li ing!anel@emo.............................................9#pinner.......................................-=?, -==, -=4, 2?0 #FLite@atabase................................................-=#FLiteGpen)elper............................-?1, -=0, -=#tring................................................................-92 #ur$a%e)ol er.............................................--?, --= #ur$a%e)ol er.Callba%k.............................--=, --A #ur$a%e,ie>.................................................--?3--A 5estCase....................................................229, 2?? 5est#uite..........................................................222 5est#uite/uil er..............................................222 5e;t#>it%her......................................................22 5e;t,ie>. .21, =0, =?, =4, A0, AA, A2, -24, -22, -29, -1?, -14 5hrea ..............................................................-2= 5oast.........................................................201, 209 5ranslateAnimation.............21390, 92, 9?, 9A, 91 5ranslationAnimation......................................9= 5>itterWi get..................................A=3A4, 4=344 5W!re$s.......................................................A2, A9 5ype Array....................................................-4, -1 "p ate#ervi%e..............................................A4, A1 "ri..........................................99, -00, 2-A32-1, 22,i eo@emo......................................................-01 ,i eo,ie>.................................................-0A, -04 ,ie>. .?03?2, ?A, ?4, ?2, =0, =2, =?, =4, =9, A0, A1, A2, 44, 22, 9=, 2?2, 2?? ,ie>.GnCli%kListener.......................................-2 ,ie>Animator...................................................22 ,ie>(lipper.......................................................22 ,ie>Wrapper...................................................-A2 ,olumeManager...............................................-9A ,olumiCer..................................................-9?, -9A Wake$ul.ntent#ervi%e........................-2?, -2A, -21 WakeLo%k...........................................-20, -2?3-2A Web#ettings.........................................................Web,ie>.........................................-, 2, =, 1, 9, -0 Web,ie>Client....................................................Wi get!rovi er.................................................4-

Command......................................
a b push...........................................................-01 ra>9pat%h............................................12, 19, 2? mks %ar ..........................................................-01 s<lite?..................................................-?1, -?9, -=-

Constant.........................................
AC5.G0R!.CK..........................................2-4, 2-1 AC5.G0R5A8..................................................220 AC5.G0R,.BW................................................2-1 AL5BR0A5.,B.................................................22/.0@RA"5GRCRBA5B....................................20CA5B8GRDRAL5BR0A5.,B...................220, 22@B(A"L5RCA5B8GRD....................................22MA5C)R@B(A"L5RG0LD..............................22RB#"L5RGK..............................................2-4, 2-1

*ethod...........................................
a%<uire&'...........................................................-2= a%<uire#tati%Lo%k&'..................................-2?, -2A

%$6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Gey)ord +ndex
a a a a a (ooter,ie>&'...............................................?2 )ea er,ie>&'..............................................?2 .ntentGptions&'.................................2203222 +avas%ript.nter$a%e&'.............................2, =, 4 #e%tion&'......................................................?A get!a%kageManager&'.....................................222 get#ystem#ervi%e&'............................-2=, -19, -22 get,ie>&'......................................................?2, ?A get,ie>5ypeCount&'...................................?A, ?4 han le.nstallBrror&'.........................................-=initMeter&'........................................................-9A insert&'..............................................................-?A isBnable &'........................................................?0 is0ull&'..............................................................-A4 loa Animation&'...............................................9= loa "rl&'..........................................................1, 9 obtain#tyle Attributes&'...................................-4 onA%%ura%yChange &'.....................................-2A onA%tivityResult&'...........................................2-4 onAnimationBn &'...........................................9= on/in &'...........................................................-99 onCli%k&'............................................................-9 onCreate&'.....................-0=, --=, -=-, -2=, -2A, -9A on@elete &'.................................................4A, 44 on@estroy&'................................................40, -2A on@isable &'......................................................4A onBnable &'.......................................................4A on(inish.n$late&'...........................................-4, -1 on)an le.ntent&'...............................A4, -2A, -21 on.tem#ele%te &'..............................................=4 onKey@o>n&'........................................40, 4-, --1 onLo%ationChange &'........................................2 on0othing#ele%te &'........................................=4 on!ause&'.........................................................-1= on!i%ture5aken&'.............................................--9

areAll.tems#ele%table&'....................................?0 bin #ervi%e&'....................................2003202, 204 buil (ooter&'.....................................................=0 buil )ea er&'...................................................=0 buil "p ate&'..............................................A4, A1 %reate&'.............................................................-0= elete&'..............................................................-?A o.n/a%kgroun &'...........................................-20 enable&'............................................................-99 eval&'..........................................................201, 2-e;e%#FL&'..................................................-=-, -=2 e;e%ute#%ript&'.................................201, 202, 2-0 $ailure&'............................................................209 $in ,ie>/y. &'..................................................A1 getA%tivity&'.....................................................2?0 getColumnCount&'..........................................-A4 getColumn.n e;&'...........................................-A4 getConte;t&'.....................................................2?? getCount&'.........................................................?A get)ol er&'.......................................................--= get.nt&'........................................................-4, -A4 get.tem&'............................................................?A get.tem,ie>5ype&'......................................?A, ?4 get+oin&'.....................................................-A1, -A2 getLo%k&'..........................................................-2?

%$Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Gey)ord +ndex
onRe%eive&'............................4A, 44, -10, -22, -2A onResume&'......................................................-1= on#ensorChange &'.........................................-2A on#ervi%eConne%te &'.............................200, 20on#ervi%e@is%onne%te &'........................200, 20on#tart&'....................................................-2=, -2A on"p ate&'............................................AA, 4=, 4A on"pgra e&'.....................................................-=open&'................................................................--? pause&'.......................................................-0-, -0= play&'................................................................-0= prepare&'....................................................-0-, -0= prepareAsyn%&'.................................................-0<uery&'..............................................................-?A <uery.ntentA%tivityGptions&'........................222 re%y%le&'..............................................................-1 registerListener&'.............................................-2A registerRe%eiver&'........................-42, -49, -1-, -1? release&'...............................................-0A, --A, -2? re<uery&'....................................................-A1, -A2 runGn"i5hrea &'...........................................209 sen Keys&'........................................................2?setAnimationListener&'....................................9= set@ata#our%e&'...............................................-00 set@uration&'....................................................92 set.nterpolator&'...............................................94 setMa;&'...........................................................-9A setGnCli%k!en ing.ntent&'..............................A2 setGn.tem#ele%te Listener&'...........................=? set!i%ture(ormat&'...........................................--1 set!revie>@isplay&'.........................................--= set!rogress&'....................................................-9A setRepeating&'..................................................-22 setResult&'..........................................................4set5e;t,ie>5e;t&'.............................................A2 set5ype&'...........................................................--= setup&'.......................................................-0=, -0A set"p&'......................................................2?0, 2?? set,isibility&'..............................................29, 9= shaking#tarte &'...............................................-?shaking#toppe &'.............................................-?start&'................................................................-0startA%tivity(orResult&'.............................A9, 2-4 startAnimation&'.........................................22, 92 start!revie>&'...................................................--A start#ervi%e&'.......................................A4, -10, -2A steerLe$t&'.........................................................-22 steerRight&'......................................................-22 stop&'..................................................-0-, -0=, -0A stop!revie>&'....................................................--A su%%ess&'..........................................................209 sur$a%eChange &'.............................................--A sur$a%eCreate &'...............................................--= sur$a%e@estroye &'...........................................--A take!i%ture&'.....................................................--2 tear@o>n&'......................................................2?0 toggle&'..............................................................90 to#tring&'.........................................................201 unbin #ervi%e&'...............................................20unregisterListener&'.........................................-2A

%$%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Gey)ord +ndex
up ate&'............................................................-?A up ateAppWi get&'..............................A4, 4-, 4A

%$.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-NC-SA 3.0 License Edition

Das könnte Ihnen auch gefallen