100% found this document useful (1 vote)
821 views262 pages

Android Avanzado PDF

Android

Uploaded by

avionica
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
821 views262 pages

Android Avanzado PDF

Android

Uploaded by

avionica
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 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-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 eu%ational or
business use. (or more in$ormation, %onta%t [email protected].
!rinting )istory*
+ul 2009* ,ersion -.0 .#/0* 91230392-41203-34
5he CommonsWare name an logo, 6/usy Coer7s 8uie9, an relate trae ress are
traemarks o$ CommonsWare, LLC.
All other traemarks re$eren%e in this book are traemarks 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-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 Coe 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........................................................................&
(riens >ith /ene$its....................................................................................-
5urnabout is (air !lay..................................................................................4
8earing "p....................................................................................................9
/a%k 5o 5he (uture......................................................................................--
Craftin' (our %"n !ie"s.......................................................................&)
8etting Meta................................................................................................-?
5he Wiget Layout...............................................................................-=
5he Attribute @e%larations..................................................................-=
5he Wiget .mplementation...............................................................-A
iii
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
"sing the Wiget..................................................................................-9
Change o$ #tate............................................................................................2-
Changing /utton /a%kgrouns............................................................2-
Changing Che%k/o; #tates..................................................................2A
*ore +un With ,ist!ie"s......................................................................-.
8iant B%onomy3#iCe @iviers....................................................................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 Wiget...................................................A0
Cra$ting App Wigets.................................................................................A-
5he Mani$est.........................................................................................A2
5he Metaata........................................................................................A?
5he Layout............................................................................................A=
5he /roa%astRe%eiver.........................................................................AA
5he #ervi%e............................................................................................A4
5he Con$iguration A%tivity..................................................................A2
5he Result..............................................................................................4-
Another an Another.................................................................................4=
App Wigets* 5heir Li$e an 5imes..........................................................4A
Controlling Dour &App Wiget7s' @estiny................................................44
iv
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
/eing a 8oo )ost.....................................................................................44
Creatin' Dra"ales................................................................................3&
5raversing Along a 8raient......................................................................1-
A #tit%h .n 5ime #aves 0ine......................................................................1A
5he 0ame an the /orer...................................................................14
!aing 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 #liing !anel...................................................................29
5he A$termath......................................................................................29
.ntrou%ing #liing!anel....................................................................90
"sing the Animation............................................................................92
(aing 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 Meia Gn....................................................................................99
Making 0oise.............................................................................................-00
v
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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
Dataases and Content Providers.......................................................&)5
@istribute @ata........................................................................................-?4
#FLite* Gn3@evi%e, Gn3@esktop.......................................................-?1
B;porting a @atabase..........................................................................-?1
Loaing 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-SA 3.0 License Edition
A%%essing Bmail Aresses................................................................-=2
Rummaging 5hrough Dour !hone Re%ors............................................-A0
Come 5ogether, Right 0o>.......................................................................-A-
CursorWrapper....................................................................................-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
#%heuling Alarms...............................................................................-2-
Arranging $or Work (rom Alarms.....................................................-22
#taying A>ake At Work.....................................................................-2=
#etting B;pe%tations.................................................................................-22
/asi% #ettings......................................................................................-22
#e%ure #ettings.....................................................................................-9-
Can 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-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' Availale 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$$oling.......................................................................224
5esting Real #tu$$......................................................................................229
A%tivity.nstrumentation5estCase.....................................................229
Anroi5estCase.................................................................................2?-
Gther Alternatives..............................................................................2??
Monkeying Aroun...................................................................................2??
viii
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Welcome to the Warescription!
We hope you enLoy this igital book an its upates M keep tabs on the
Wares%ription $ee o$$ the CommonsWare site to learn >hen ne> eitions
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 eition o$ this title >ill be release
uner 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 %oe' $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 Kinle users*
Dou may >ish to rop your $ont siCe to level 2 $or easier reaing
#our%e %oe listings are in%orporate as graphi%s so as to retain the
monospa%e $ont, though this means the sour%e %oe listings o not
honor %hanges in Kinle $ont siCe
ix
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Preface
Welcome to the Book!
.$ you %ome to this book a$ter having rea its %ompanion volume, 5he /usy
Coer7s 8uie to Anroi @evelopment, thanks $or sti%king >ith the series:
CommonsWare aims to have the most %omprehensive set o$ Anroi
evelopment resour%es &outsie o$ the Gpen )anset Allian%e itsel$', an
>e appre%iate your interest.
.$ you %ome to this book having learne about Anroi $rom other sour%es,
thanks $or Loining the CommonsWare %ommunity: Anroi, >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 nees to kno>. 5his book >ill hope$ully augment your kno>lege o$
the ins an outs o$ Anroi3om an make it easier $or you to %reate Ikiller
appsI that use the Anroi 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 Anroi evelopment, >hether
$rom a CommonsWare resour%e or somepla%e else. .n other >ors, you
shoul have*
xi
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
A >orking Anroi evelopment environment, >hether it is base
on B%lipse, another .@B, or Lust the %omman3line tools that
a%%ompany the Anroi #@K
A strong unerstaning o$ ho> to %reate a%tivities an the various
sto%k >igets available in Anroi
A >orking kno>lege 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 proviers 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 Coer7s 8uie to Anroi @evelopment, there are plenty
o$ other books available %overing the Anroi basi%s, blog posts, >ikis, an,
o$ %ourse, the main Anroi site itsel$. A list o$ %urrently3available Anroi
books %an be $oun on the Anroi !rogramming knol.
#ome %hapters may re$eren%e material in previous %hapters, though usually
>ith a link ba%k to the pre%eing se%tion o$ relevan%e. Many %hapters >ill
re$eren%e material in 5he /usy Coer7s 8uie to Anroi @evelopment,
sometimes via the shorthan BCG to Android moniker.
.n orer to make e$$e%tive use o$ this book, you >ill >ant to o>nloa the
sour%e %oe $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 reaing.
!resently, CommonsWare o$$ers !@( an KinleO other igital $ormats >ill
be ae base on interest an the openness o$ the $ormat.
xii
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Ba%h subs%riber gets personaliCe eitions o$ all eitions o$ ea%h title* both
those mirroring printe eitions an in3bet>een upates that are only
available in igital $orm. 5hat >ay, your igital books are never out o$ ate
$or long, an you %an take avantage o$ ne> material as it is mae available
instea o$ having to >ait $or a >hole ne> print eition. (or e;ample, >hen
ne> releases o$ the Anroi #@K are mae available, this book >ill be
<ui%kly upate 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%luing not3yet3publishe ne> titles.
Also, i$ you o>n a print %opy o$ a CommonsWare book, an it is in goo
%lean %onition >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
eition, an >e7ll give you a %oupon $or a si;3month Wares%ription as a
bounty $or helping us eliver a better prou%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 ranom 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 avertise, 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-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 a sample appli%ations, or
e;pan upon the e;isting material
#amples that o not >ork ue to Ishi$ting sansI o$ the unerlying
environment &e.g., %hange A!.s >ith ne> releases o$ an #@K'
)o>ever, those Iso$terI issues o not <uali$y $or the $ormal bounty
program.
Fuestions about the bug bounty, or problems you >ish to report $or bounty
%onsieration, shoul be sent to bountyN%ommons>are.%om.
Source Code icense
5he sour%e %oe samples sho>n in this book are available $or o>nloa
$rom the CommonsWare Web site. All o$ the Anroi proLe%ts are li%ense
uner 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 eition >ill be available $or use uner 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 eition 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-SA 3.0 License Edition
%ommer%ial purposes. 5hat is our (our3to3(ree 8uarantee to our reaers
an the broaer %ommunity. (or the purposes o$ this guarantee, ne>
Wares%riptions an rene>als >ill be %ounte as sales o$ this eition,
starting $rom the time the eition is publishe.
5his eition o$ this book >ill be available uner the a$orementione
Creative Commons li%ense on +une -# -;&). G$ %ourse, >at%h the
CommonsWare Web site, as this eition 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 eitions o$ this book >ill be%ome $ree on later ates, ea%h
$our years $rom the publi%ation o$ that eition or base on sales o$ that
spe%i$i% eition. Releasing one eition uner the Creative Commons li%ense
oes not automati%ally release all eitions uner that li%ense.
ifecycle of a CommonsWare Book
CommonsWare books generally go through a series o$ stages.
(irst are the pre3release eitions. 5hese >ill have version numbers belo>
0.9 &e.g., 0.2'. 5hese eitions 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 %aniates are eitions >ith version numbers ening in I.9I &0.9,
-.9, et%.'. 5hese eitions shoul be %omplete. Gn%e again, they are mae
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 eitions are those >ith version numbers ening 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>ie.
xv
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
,ersions bet>een a maLor eition an the ne;t release %aniate &e.g., -.-,
-.2' >ill %ontain bug $i;es plus ne> material. Ba%h o$ these eitions shoul
also be %omplete, in that you >ill not see any I5/@I &to be one' markers
or the like. )o>ever, these eitions may have bugs, an so bug reports are
eligible $or the bounty program, as >ith release %aniates an maLor
releases.
A book usually >ill progress $airly rapily through the pre3release eitions
to the $irst release %aniate an ,ersion -.0 M o$ten times, only a $e>
months. @epening 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 moeI, only getting upates to $i; bugs an eal
>ith maLor e%osystem events M $or e;ample, a ne> release o$ the Anroi
#@K >ill ne%essitate an upate to all Anroi books.
xvi
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
PART I Advanced Widgets
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER 1
Web(ie)* +nside and ,ut
Anroi uses the WebKit bro>ser engine as the $ounation $or both its
/ro>ser appli%ation an the WebView embeable bro>sing >iget. 5he
/ro>ser appli%ation, o$ %ourse, is something Anroi users %an intera%t
>ith ire%tlyO the WebView >iget 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 Anroi
a%tivity, >ith the a%tivity i%tating >hat the bro>sing >iget isplaye an
ho> it respone to links.
)ere, >e >ill e;pan on this theme, an sho> ho> to more tightly
integrate the +ava environment o$ an Anroi 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 provier 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 embee 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 Anroi
appli%ation.
-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 methos, so they %an be %alle by
+avas%ript loae by the Web %ontent in the WebView itsel$.
0o> you have the po>er to provie a%%ess to a >ie range o$ Anroi
$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
loae 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 avertising.
We %an o mu%h o$ the same thing >ith Anroi an
addJavascriptInterface().
.n the WebView/GeoWeb1 proLe%t, you >ill $in a $airly simple layout
&main.xml'*
!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 >iget.
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-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 onause() 4
s&per.onause():
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 onrovider"isabled(String provider) 4
// re@&ired for interface> not &sed
?

p&blic void onroviderEnabled(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-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 as three key bits o$ %oe*
-. .t sets up the *ocation9anager to provie upates >hen the evi%e
position %hanges, routing those upates to a o3nothing
*ocation*istener %allba%k obLe%t
2. .t has a *ocater inner %lass that provies a %onvenient A!. $or
a%%essing the %urrent lo%ation, in the $orm o$ latitue an longitue
values
?. .t uses addJavascriptInterface() to e;pose a *ocater instan%e uner
the name locater to the Web %ontent loae in the WebView
5he Web page itsel$ is re$eren%e in the sour%e %oe as
file,///android/asset/geoweb1.-tml, so the GeoWeb1 proLe%t has a
%orresponing 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)
$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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"pate Lo%ationI link, the page %alls a w-ereami()
+avas%ript $un%tion, >hi%h in turn uses the locater obLe%t to upate the
latitue an longitue, 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"pate 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-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 upates to the Web page, so
it %oul proa%tively upate the position as the user moves, rather than >ait
$or a %li%k on the I"pate Lo%ationI link.
Well, as lu%k >oul have it, >e %an o that too. 5his is a goo thing,
other>ise, this >oul be a really >eak se%tion o$ the book.
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 %urrently3loae Web page.
Gly enough, that is not ho> this is a%%omplishe.
2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 %oe an use that as the IaressI 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 Anroi analogue M the
Aavascript, pre$i; tells the bro>ser to treat the rest o$ the aress as
+avas%ript sour%e, inLe%te into the %urrently3vie>e Web page.
#o, arme >ith this %apability, let us moi$y the previous e;ample to
%ontinuously upate 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 onause() 4
s&per.onause():
m+*ocation9anager.removeUpdates(on*ocationC-ange):
?
3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 onrovider"isabled(String provider) 4
// re@&ired for interface> not &sed
?

p&blic void onroviderEnabled(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 buils up a %all to a w-ereami() +avas%ript $un%tion,
proviing the latitue an longitue as parameters to that %all. #o, $or
4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Web(ie)* +nside and ,ut
e;ample, i$ our lo%ation >ere =0 egrees latitue an 31A egrees longitue,
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 neee a slight revision, to a%%ommoate
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"pate Lo%ationI link,
albeit >ith a slightly i$$erent onClic. attribute.
.$ you buil, install, an run this revise sample on a 8!#3e<uippe
Anroi evi%e, the page >ill initially isplay >ith I&unkno>n'I $or the
%urrent position. A$ter a $i; is reay, though, the page >ill automati%ally
upate to re$le%t your a%tual position. An, as be$ore, you %an al>ays %li%k
I"pate Lo%ationI i$ you >ish.
'earing 1p
.n these e;amples, >e emonstrate ho> Web,ie> %an intera%t >ith +ava
%oe, %oe that provies a servi%e a little like one o$ those $rom 8ears.
5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 Anroi is %lose on that $ront. 8ears is a%tually
bake into Anroi. )o>ever, it is only e;pose by the /ro>ser
appli%ation, not via WebView. #o, an en user o$ an Anroi evi%e %an
leverage 8ears3enable Web pages.
(or e;ample, you %oul loa the 8eolo%ation sample appli%ation in your
Anroi evi%e7s /ro>ser appli%ation. .nitially, you >ill get the stanar
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-SA 3.0 License Edition
Web(ie)* +nside and ,ut
!igure $/ The 'ears 'eolocation sample application
Back To The !uture
5he %ore Anroi team has ini%ate that these sorts o$ %apabilities >ill
in%rease in $uture eitions o$ the Anroi operating system. 5his %oul
in%lue support $or more types o$ plugins, a ri%her +ava3+avas%ript brige,
an so on.
Dou %an also e;pe%t some improvements %oming $rom the overall Anroi
e%osystem. (or e;ample, the !hone8ap proLe%t is attempting to buil a
$rame>ork that supports %reating Anroi 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-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER 2
Crafting 7our ,)n (ie)s
Gne o$ the %lassi% $orms o$ %oe reuse is the 8". >iget. #in%e the avent
o$ Mi%roso$t Wino>s M an, to some e;tent, even earlier M evelopers have
been %reating their o>n >igets to e;ten an e;isting >iget set. 5hese
range $rom -43bit Wino>s I%ustom %ontrolsI to ?23bit Wino>s GCH
%omponents to the innumerable >igets available $or +ava #>ing an #W5,
an beyon. Anroi lets you %ra$t your o>n >igets as >ell, su%h as
e;tening an e;isting >iget >ith a ne> ". or ne> behaviors.
'etting 8eta
Gne %ommon >ay o$ %reating your o>n >igets is to aggregate other
>igets together into a reusable ImetaI >iget. Rather than >orry about all
the etails o$ measuring the >iget siCes an ra>ing its %ontents, you
simply >orry about %reating the publi% inter$a%e $or ho> one intera%ts >ith
the >iget.
.n this se%tion, >e >ill look at the Views/9eter sample proLe%t. )ere, >e
bunle a 5rogress;ar an t>o Image;&tton >igets into a reusable 9eter
>iget, allo>ing one to %hange a value by %li%king Iin%rementI an
Ie%rementI buttons. .n most %ases, one >oul probably be better serve
using the built3in See.;ar >iget. )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 ieally suite. .n $a%t, >e >ill reuse the 9eter in a later %hapter
>hen >e sho> ho> to manipulate the various volume levels in Anroi.
-.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Crafting 7our ,)n (ie)s
The id!et "ayout
5he $irst step to>ars %reating a reusable >iget is to lay it out. .n some
%ases, you may pre$er to %reate your >iget %ontents purely in +ava,
parti%ularly i$ many %opies o$ the >iget >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
Wigets 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 >igets in the layout
-$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 >iget, 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 >iget %lass spe%i$ie in the name attribute M in our %ase, >e >ill %all
the >iget 9eter. .nsie declare'st+leable you %an have one or more attr
elements, ea%h ini%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 valiation an in getting any supplie values $or this attribute
parse into the appropriate type at runtime.
)ere, >e ini%ate there are three attributes* max &ini%ating the highest
value the 9eter >ill go to', incr &ini%ating ho> mu%h the value shoul
in%rease >hen the in%rement button is %li%ke', an decr &ini%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 >iget. 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 >iget layout into the
%ontainer.
The Constructor
5o be usable insie 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-SA 3.0 License Edition
Crafting 7our ,)n (ie)s
-. A Context obLe%t, typi%ally representing the 3ctivit+ that is in$lating
your >iget
2. An 3ttrib&teSet, representing the bunle o$ attributes in%lue in
the element in the layout being in$late that re$eren%es your >iget
.n this %onstru%tor, a$ter %haining to your super%lass, you %an o some basi%
%on$iguration o$ your >iget. /ear in min, though, that you are not in
position to %on$igure the >igets that make up your aggregate >iget 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 hanles any styles that might be e%lare via the style attribute in
the layout element that re$eren%es your >iget
.t $ins the resour%es you e%lare via attrs.;ml an makes them
available to you
.n the %oe sho>n above, >e get our <+ped3rra+ via
obtainSt+led3ttrib&tes(), then %all getInt() three times to get our values
-2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Crafting 7our ,)n (ie)s
out o$ the <+ped3rra+. 5he <+ped3rra+ is keye by 6.st+leable ienti$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 immeiate reuse, rather than $or%ing it
to be garbage3%olle%te.
Finishing Inflation
Dour >iget >ill also typi%ally overrie onKinis-Inflate(). At this point, you
%an turn aroun an a your o>n %ontents, via +ava %oe 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.incrementrogressBy(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.incrementrogressBy(decr3mo&nt):
if (on7ecrN#n&ll) 4
on7ecr.onClic)(9eter.t-is):
?
?
?):
?
-3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 outsie >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 >iget
%lass
G$$er setters &an, optionally, getters' to e$ine those listener
obLe%ts
Call those listeners >hen appropriate
(or e;ample, 9eter hols 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-SA 3.0 License Edition
Crafting 7our ,)n (ie)s
p&blic void onClic)(View v) 4
bar.incrementrogressBy(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.incrementrogressBy(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 >iget on the
outboun onClic.() %all. 5his is so >e o not leak internal implementation
o$ our >iget. 5he users o$ 9eter shoul neither kno> nor %are that >e have
Image;&tton >igets as part o$ the 9eter internals.
Dour >iget may >ell re<uire other methos as >ell, $or >iget3spe%i$i%
%on$iguration or $un%tionality, though 9eter oes not.
%sin! the id!et
8iven all o$ that, using the 9eter >iget is not signi$i%antly i$$erent than
using any other >iget provie in the system...>ith a $e> minor
e;%eptions.
.n the layout, sin%e your %ustom >iget is not in the android.widget +ava
pa%kage, you nee to $ully3<uali$y the %lass name $or the >iget, 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-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 Anroi
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
nees 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-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
>iget in another proLe%t.
Change of State
#ometimes, >e o not nee to %hange the $un%tionality o$ an e;isting
>iget, but >e simply >ant to %hange ho> it looks. Maybe you >ant an
oly3shape ;&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 >iget as you
see $it, rather than have to roll a separate >iget 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-SA 3.0 License Edition
Crafting 7our ,)n (ie)s
!igure 2/ The !ancyButton application* sho)ing a normal oval"shaped button
Moreover, it nees 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-SA 3.0 License Edition
Crafting 7our ,)n (ie)s
...an it nees 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, proviing 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 graients. )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 uner >hi%h they shoul be applie, as es%ribe via
a series o$ states $or the >iget 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-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 regarless o$ $o%us'.
.$ >e spe%i$y this sele%tor 7rawable resour%e as the android,bac.gro&nd o$ a
;&tton, Anroi >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-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 to %hange the images use by a
C-ec.;ox.
.n this %ase, the $a%t that Anroi is open sour%e helps, as >e %an e;tra%t
$iles an resour%es $rom Anroi an aLust them to %reate our o>n
eitions, >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-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 Anroi #@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 our layout, >e %an spe%i$y that >e >ant to use our
res/drawable/fanc+c-ec..xml sele%tor 7rawable as our ba%kgroun*
!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-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; >ie. #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-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER )
8ore !un With ist(ie)s
Gne o$ the most important >igets 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 alreay sa> in The Busy Coder's
Guide to Android Deelopment 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 aitional te%hni<ues you %an use to make your *istView
>igets 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-SA 3.0 License Edition
8ore !un With ist(ie)s
!igure --/ : PreferenceScreen 1+
Dou may have thought that this re<uire some %ustom >iget, or some
$an%y on3the3$ly View hanling, 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 methos in the 3dapter hierar%hy that let you %ontrol >hat is
an is not sele%table in a *istView*
are3llItemsSelectable() shoul return tr&e $or orinary *istView
>igets an false $or *istView >igets >here some items in the
Aapter are sele%table an others are not
is8nabled(), 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-SA 3.0 License Edition
8ore !un With ist(ie)s
8iven these t>o, it is ImerelyI a matter o$ overriing your %hosen 3dapter
%lass an implementing these t>o methos 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 orer >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 heaings, 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
SimpleC&rsor3dapter, the t>o methos %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.
5o get the heaings in pla%e, your 3dapter nees to mi; the heaings in
>ith the books &so they all appear in the proper se<uen%e', return a %ustom
View $or ea%h &so heaings look i$$erent than the books', an implement
the t>o methos that %ontrol >hether the heaings or books are sele%table.
5here is no easy >ay to o this $rom a simple <uery.
.nstea, you nee to be a bit more %reative, an >rap your
SimpleC&rsor3dapter in something that %an intelligently inLe%t the se%tion
heaings.
Composition *or (ections
+e$$ #harkey, author o$ CompareBvery>here an all3aroun Anroi guru,
emonstrate a >ay o$ using %omposition to %reate a *istView >ith se%tion
heaings. 5he %oe presente here is base on his implementation, >ith a
$e> alterations. As his original %oe >as release uner the 8!Lv?, bear in
min that the %oe presente here is also release uner the 8!Lv?, as
.-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 %oe 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 heaing name.
.mplement, on your %ontainer 3dapter sub%lass, a metho to return
the View $or a heaing, 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 >orsI 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$
/)
Most o$ the smarts %an be $oun in Sectioned3dapter. 5his %lass e;tens
3dapter an elegates all o$ the 3dapter methos 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-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 *istSection) sections#new 3rra+*istSection)():
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 (positionsiIe) 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-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 (positionsiIe) 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 (positionsiIe) 4
ret&rn(section.adapter.getView(position'1>
convertView>
parent)):
?
.$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 hols a *ist o$ Section obLe%ts, >here a Section is simply a
name an an 3dapter holing 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 orer in >hi%h they >ere ae.
Sectioned3dapter synthesiCes the overall list o$ obLe%ts $rom ea%h o$ the
aapters, plus the se%tion heaings. #o, $or e;ample, the implementation o$
getView() >alks ea%h se%tion an returns either a View $or the se%tion
heaer &i$ the re<ueste item is the $irst one $or that se%tion' or the View
$rom the se%tion7s aapter &i$ the re<ueste item is any other one in this
se%tion'. 5he same hols true $or getCo&nt() an getItem().
Gne thing that Sectioned3dapter nees to o, though, is ensure that the
pool o$ se%tion heaer 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
avantage 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 heaer
View pool. #imilarly, getItemView<+pe() %onsiers the %th View type to be the
heaer 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-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, as in three
se%tions &>ith three sets o$ the lorem ipsum >ors', 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+3dapterString)(t-is>
android.6.la+o&t.simple/list/item/1>
items)):

*istString) list#3rra+s.asList(items):

Collections.s!uffle(list):
adapter.addSection($S-&ffled$>
new 3rra+3dapterString)(t-is>
.2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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+3dapterString)(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-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 heaers are simple bits o$ te;t >ith an appropriate style applie.
Dour se%tion heaers, o$ %ourse, %an be as %omple; as you like.
!rom =ead To Toe
!erhaps you o not nee se%tion heaers 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 heaer an $ooter vie>s.
*istView supports addBeaderView() an addKooterView() methos 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 heaers or $ooters, rather than put them in the *istView
itsel$, put them outsie the *istView, perhaps using a *inear*a+o&t.
5o emonstrate heaer an $ooter vie>s, take a peek at
*istView/BeaderKooter, parti%ularly the BeaderKooter7emo %lass*
.4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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+3dapterString)(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-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
*istString) list#3rra+s.asList(items):

Collections.s!uffle(list):

setList&dapter(new 3rra+3dapterString)(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 heaer 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, upate every se%on. 5he list itsel$ is the ever3
popular list o$ lorem ipsum >ors.
When initially isplaye, the heaer 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-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 heaer >ill slie 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-SA 3.0 License Edition
8ore !un With ist(ie)s
Control 7our Selection
5he sto%k Anroi ". $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%onary 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 ini%ation o$ the sele%te item than having
the >hole ro> sho> up in some neon %olor. 5he sto%k Anroi ". $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
>igets you >ant $or the sele%te3ro> 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 >igets 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 a ro>.;ml
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$
$%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 >ith 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, proviing 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-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-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-SA 3.0 License Edition
8ore !un With ist(ie)s
Selector7emo sets up a Selector3dapter, >hi%h $ollo> the vie>3>rapper
pattern establishe in The Busy Coder's Guide to Android Deelopment.
Ba%h ro> is %reate $rom the layout sho>n earlier, >ith a SelectorWrapper
proviing a%%ess to both the <extView &$or setting the te;t in a ro>' an the
bar View.
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 neee to ini%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-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 nees 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-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER .
Sho) 1p :t =ome
Gne o$ the o$t3re<ueste $eatures ae in Anroi -.A is the ability to a
live elements to the home s%reen. Calle Iapp >igetsI, these %an be ae
by users via a long3tap on the home s%reen an %hoosing an appropriate
>iget $rom the available roster. Anroi ships >ith a $e> app >igets,
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 >igetsI >ill re$er to these items that go
on the home s%reen. Gther uses o$ the term I>igetI >ill be reserve $or
the ". >igets, 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 i $or app >igets to be%ome
available is se%urity.
Anroi7s se%urity moel 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 moi$ying the $iles o$ another or
other>ise inLe%ting their o>n %oe into another running pro%ess.
$5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Sho) 1p :t =ome
.n parti%ular, the %ore Anroi team >ante to $in a >ay that >oul allo>
app >igets 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 %oe itsel$ or someho> allo> its ". to be
ire%tly manipulate by another pro%ess.
5he app >iget ar%hite%ture, there$ore, is set up to keep the home s%reen
appli%ation inepenent $rom any %oe that puts app >igets on that home
s%reen, so bugs in one %annot harm the other.
The Big Picture for a Small :pp Widget
5he >ay Anroi pulls o$$ this bit o$ se%urity is through the use o$
6emoteViews.
5he appli%ation %omponent that supplies the ". $or an app >iget is not an
3ctivit+, but rather a ;roadcast6eceiver &o$ten in tanem >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.
6emoteViews en%apsulates a limite eition o$ normal >igets, in su%h a
$ashion that the 6emoteViews %an be IeasilyI transporte a%ross pro%ess
bounaries. Dou %on$igure the 6emoteViews via your ;roadcast6eceiver an
make those 6emoteViews available to Anroi. Anroi in turn elivers the
6emoteViews to the app >iget host &usually the home s%reen', >hi%h
reners them to the s%reen itsel$.
5his ar%hite%tural %hoi%e has many impa%ts*
-. Dou o not have a%%ess to the $ull range o$ >igets 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 >igets.
06
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 >igets. .n parti%ular, there is no 8dit<ext $or te;t
input.
?. /e%ause the app >igets are renere 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
bran3ne> 6emoteViews >henever you >ant to %hange the %ontents
o$ the app >iget. 5his, %ouple >ith having to transport the
6emoteViews a%ross pro%ess bounaries, means that upating the app
>iget is rather e;pensive in terms o$ C!" time, memory, an
battery li$e.
A. /e%ause the %omponent hanling the upates is a
;roadcast6eceiver, you have to be <ui%k &lest you take too long an
Anroi %onsier you to have time out', you %annot use
ba%kgroun threas, an your %omponent itsel$ is lost on%e the
re<uest has been %omplete. )en%e, i$ your upate 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 >iget upate.
Crafting :pp Widgets
5his >ill be%ome some>hat easier to unerstan in the %onte;t o$ some
sample %oe. .n the 3ppWidget/<witterWidget proLe%t, you >ill $in an app
>iget 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.
0-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 neee on ;roadcast6eceiver e%larations.
)o>ever, in this %ase, those are use $or the entry that goes in the
menu o$ available >igets 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-SA 3.0 License Edition
Sho) 1p :t =ome
Gur receiver) has an intent'filter) $or the
android.appwidget.action.355WI7G8</D573<8 a%tion. 5his means >e
>ill get %ontrol >henever Anroi >ants us to upate the %ontent o$
our app >iget. 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, ini%ating that its
android.appwidget.provider etails %an be $oun in the
res/xml/widget/provider.xml $ile. 5his metaata 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 >iget provier metaata. 5his has to
resie at the lo%ation ini%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 provie $our pie%es o$ in$ormation*
5he minimum >ith an height o$ the app >iget &android,minWidt-
an android,minBeig-t'. 5hese are appro;imate M the app >iget
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 >igets >ill
resie. )o>ever, they shoul be no smaller than the minimums
%ite here.
5he $re<uen%y in >hi%h Anroi shoul re<uest an upate o$ the
>iget7s %ontents &android,&pdate5eriod9illis'. 5his is e;presse in
terms o$ millise%ons, so a value o$ T%%%%% is a -A3minute upate
%y%le.
0.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Sho) 1p :t =ome
An a%tivity %lass that >ill be use to %on$igure the >iget >hen it is
$irst ae 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 Anroi the initial layout to use
$or the app >iget, via an android,initial*a+o&t attribute.
The "ayout
Bventually, you are going to nee a layout that es%ribes >hat the app
>iget looks like. #o long as you sti%k to the >iget 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-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 >igets 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 Anroi >ants
us to upate our 6emoteViews $or our app >iget. 5o simpli$y this, Anroi
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 nees to be implemente on the provier
is onDpdate(). Gther li$e%y%le methos may be o$ interest an are is%usse
later in this %hapter.
(or e;ample, here is the onDpdate() implementation o$ the
3ppWidget5rovider $or <witterWidget*
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-SA 3.0 License Edition
Sho) 1p :t =ome
.$ our 6emoteViews %oul be rapily %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 upates.
The (ervice
5he real >ork $or <witterWidget is mostly one in an DpdateService inner
%lass o$ <witterWidget.
DpdateService oes not e;ten Service, but rather e;tens IntentService.
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, upating an app >iget $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
Anroi hanles 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 upate the 6emoteViews $or our app >iget, >e nee to buil those
6emoteViews &elegate to a b&ildDpdate() helper metho' an tell an
3ppWidget9anager to upate the >iget via &pdate3ppWidget(). .n this %ase,
>e use a version o$ &pdate3ppWidget() that takes a Component=ame as the
ienti$ier o$ the >iget to be upate. 0ote that this means that >e >ill
upate all instan%es o$ this app >iget presently in use M the %on%ept o$
multiple app >iget instan%es is %overe in greater etail later in this
%hapter.
02
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 methos like findView;+Id() an then %alling methos on iniviual
>igets, >e nee to %all methos on 6emoteViews itsel$, proviing the
ienti$ier o$ the >iget >e >ish to moi$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>3upating %oe 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
buils 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.getac)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-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 ienti$ier o$ our layout. 5his gives us a 6emoteViews that
%ontains all o$ the >igets >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 methos like*
set<extView<ext() to set the te;t on a <extView in the 6emoteViews,
given the ienti$ier o$ the <extView >ithin the layout >e >ish to
manipulate
set2nClic.5endingIntent() to provie a 5endingIntent that shoul
get $ire o$$ >hen a ;&tton or Image;&tton is %li%ke
0ote, o$ %ourse, that Anroi 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%lue an activit+) element $or a <W5refs
a%tivity. An, in our >iget metaata HML $ile, >e sai that <W5refs >as the
android,config&re attribute value. .n our 6emoteViews $or the >iget 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 this >iget to our home
s%reen
.t >ill be re3laun%he >henever >e %li%k the %on$igure button in the
>iget itsel$
(or the latter s%enario, the a%tivity nee be nothing spe%ial. .n $a%t, <W5refs
is mostly Lust a 5reference3ctivit+, upating 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-SA 3.0 License Edition
Sho) 1p :t =ome
5he $ormer s%enario M e$ining a %on$iguration a%tivity in the metaata M
re<uires a bit more >ork, though.
.$ >e >ere to leave this out, an not have an android,config&re attribute in
the metaata, on%e the user %hose to a our >iget to their home s%reen,
the >iget >oul immeiately appear. /ehin the s%enes, Anroi >oul
ask our 3ppWidget5rovider to supply the 6emoteViews $or the >iget boy
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, Anroi 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 >iget.
5his approa%h is prone to %oe upli%ation, an it is not %ompletely %lear
>hy Anroi ele%te to buil the >iget $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):

addreferences'romResource(6.xml.preferences):
?

02verride
05
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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(getac)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 on3eman re%on$iguration via the %on$igure button in the
>iget. 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 methos &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 >iget %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-SA 3.0 License Edition
Sho) 1p :t =ome
8et our >iget instan%e ienti$ier &es%ribe in greater etail later
in this %hapter'
8et our 3ppWidget9anager an %reate a ne> 6emoteViews in$late $rom
our >iget layout
!ass the empty 6emoteViews to the 3ppWidget9anager via
&pdate3ppWidget()
Call set6es&lt() >ith an Intent >rapping our >iget instan%e
ienti$ier, so Anroi kno>s >e have properly %on$igure our
>iget
Raise a broa%ast Intent to ask our Widget5rovider to o the real
initial version o$ the >iget
5his minimiCes %oe upli%ation, but it oes mean there is a slight hi%%up,
>here the >iget initially appears blank, be$ore the $irst timeline entry
appears. 5his is largely unavoiable 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.
"noubtely, there are other patterns $or hanling this situation.
The Result
.$ you %ompile an install all o$ this, you >ill have a ne> >iget entry
available >hen you long3tap on the home s%reen ba%kgroun*
2-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Sho) 1p :t =ome
!igure -2/ The roster of available )idgets
When you %hoose 5>itter Wiget, 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-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 >iget >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
$riens timeline*
2.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Sho) 1p :t =ome
!igure -5/ T)itterWidget* )ith a timeline entry
5o %hange your 5>itter %reentials, you %an either tap the %on$igure i%on in
the >iget or run the 5>itter Wiget appli%ation in your laun%her. An,
%li%king the re$resh button, or >aiting -A minutes, >ill %ause the >iget to
upate its %ontents.
:nother and :nother
As ini%ate above, you %an have multiple instan%es o$ the same app >iget
outstaning at any one time. (or e;ample, one might have multiple pi%ture
$rames, or multiple Isho>3me3the3latest3R##3entryI app >igets, one per
$ee. Dou >ill istinguish bet>een these in your %oe via the ienti$ier
supplie in the relevant 3ppWidget5rovider %allba%ks &e.g., onDpdate()'.
.$ you >ant to support separate app >iget instan%es, you >ill nee to store
your state on a per3app3>iget3ienti$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 >iget
ienti$ier %olumn, or something to istinguish one app >iget 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-SA 3.0 License Edition
Sho) 1p :t =ome
&pdate3ppWidget() on 3ppWidget9anager >hen you upate the app >igets,
one that takes app >iget ienti$iers as the $irst parameter, so you upate
the proper app >iget instan%es.
Conversely, there is nothing re<uiring you to support multiple instan%es as
inepenent 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 upate on inepenent %y%les, so one >ill get ne>er
t>eets be$ore another.
:pp Widgets> Their ife and Times
5>itterWiget overroe t>o 3ppWidget5rovider methos*
onDpdate(), invoke >hen the android,&pdate5eriod9illis time has
elapse
on6eceive(), the stanar ;roadcast6eceiver %allba%k, use to ete%t
>hen >e are invoke >ith no a%tion, meaning >e >ant to $or%e an
upate ue to the re$resh button being %li%ke
5here are three other li$e%y%le methos that 3ppWidget5rovider o$$ers that
you may be intereste in*
on8nabled() >ill be %alle >hen the $irst >iget instan%e is %reate
$or this parti%ular >iget provier, so i$ there is anything you nee
to o on%e $or all supporte >igets, you %an implement that logi%
here
on7eleted() >ill be %alle >hen a >iget 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
on7isabled() >ill be %alle >hen the last >iget instan%e $or this
provier is remove $rom the home s%reen, so you %an %lean up
anything relate to all su%h >igets
20
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Sho) 1p :t =ome
0ote, ho>ever, that there is a bug in Anroi -.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 eition o$ Anroi.
Controlling 7our #:pp Widget?s& 9estiny
As <witterWidget illustrates, you are not limite to upating your app
>iget only base on the timetable spe%i$ie in your metaata. 5hat
timetable is use$ul i$ you %an get by >ith a $i;e s%heule. )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
metaata is bake into your A!K an there$ore %annot be moi$ie
at runtime'
.$ you >ant the app >iget to be upate 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 upates. 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 >iget provier
)ave the provier 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 aition to %reating your o>n app >igets, it is possible to host app
>igets. 5his is mostly aime $or those %reating alternative home s%reen
appli%ations, so they %an take avantage o$ the same app >iget $rame>ork
an all the app >igets 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-SA 3.0 License Edition
Sho) 1p :t =ome
shoul be able to resie in an app >iget host7s ". like any other orinary
>iget.
23
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
PART II Advanced Media
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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
8raients have long been use to a Isomething a little e;traI to a user
inter$a%e, >hether it is Mi%roso$t aing them to G$$i%e7s title bars in the
late -9907s or the seemingly enless number o$ graient buttons aorning
IWeb 2.0I sites.
An no>, you %an have graients in your Anroi appli%ations as >ell.
5he easiest >ay to %reate a graient is to use an HML $ile to es%ribe the
graient. /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 graient 7rawable resour%e, active/row.xml, $rom the
7rawable/Gradient sample proLe%t*
3-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 graient is applie to the more general3purpose s-ape) element, in this
%ase, a re%tangle. 5he graient is e$ine as having a start an en %olor M in
this %ase, the graient is an in%reasing amount o$ re, >ith only the alpha
%hannel varying to %ontrol ho> mu%h the ba%kgroun blens 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 Io>nI &start %olor at the
top, en %olor at the bottom'.
As >ith any other HML3e$ine shape, you %an %ontrol various aspe%ts o$
the >ay the shape is ra>n. .n this %ase, >e put some paing aroun the
ra>able an roun o$$ the %orners o$ the re%tangle.
5o use this 7rawable in +ava %oe, you %an re$eren%e it as
6.drawable.active/row. Gne possible use o$ a graient is in %ustom *istView
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$>
3%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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-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 graient
roune 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 graient*
3$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 graient. .$ the list ba%kgroun >ere >hite, the top
en o$ the graient >oul be re mi;e >ith >hite, as etermine by the
alpha %hannel spe%i$ie on the graient7s top %olor.
: Stitch +n Time Saves @ine
As you rea through the Anroi o%umentation, you no oubt ran into
re$eren%es to Inine3pat%hI or I93pat%hI an >onere >hat Anroi ha to
o >ith <uilting. Rest assure, you >ill not nee to take up neele>ork to
be an e$$e%tive Anroi eveloper.
.$, ho>ever, you are looking to %reate ba%kgrouns $or resiCable >igets,
like a ;&tton, you >ill probably nee to >ork >ith nine3pat%h images.
As the Anroi o%umentation states, a nine3pat%h is Ia !08 image in
>hi%h you e$ine stret%hable se%tions that Anroi >ill resiCe to $it the
obLe%t at isplay time to a%%ommoate variable siCe se%tions, su%h as te;t
stringsI. /y using a spe%ially3%reate !08 $ile, Anroi %an avoi trying to
30
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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, Anroi
%an still resiCe the ba%kgroun to hanle >hatever you >ant to put insie 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%luing ho> to %ustomiCe an apply them to your o>n Anroi layouts.
The 1ame and the Border
0ine3pat%h graphi%s are !08 $iles >hose names en in .T.png. 5his means
they %an be eite using normal graphi%s tools, but Anroi kno>s to apply
nine3pat%h rules to their use.
What makes a nine3pat%h graphi% i$$erent than an orinary !08 is a one3
pi;el3>ie borer surrouning the image. When ra>n, Anroi >ill
remove that borer, sho>ing only the stret%he renition o$ >hat lies
insie the borer. 5he borer is use as a %ontrol %hannel, proviing
instru%tions to Anroi $or ho> to eal >ith stret%hing the image to $it its
%ontents.
Paddin! and the Bo'
Along the right an bottom sies, you %an ra> one3pi;el3>ie bla%k lines
to ini%ate the Ipaing bo;I. Anroi >ill stret%h the image su%h that the
%ontents o$ the >iget >ill $it insie that paing 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',
Anroi >ill %ompute the siCe o$ that te;t, in terms o$ >ith an height in
pi;els. 5hen, it >ill stret%h the nine3pat%h image su%h that the te;t >ill
resie insie the paing bo;. What lies outsie the paing bo; $orms the
borer o$ the button, typi%ally a roune re%tangle o$ some $orm.
32
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 Anroi >here on the image to a%tually o the stret%hing, ra> one3
pi;el3>ie bla%k lines on the top an le$t sies o$ the image. Anroi >ill
s%ale the graphi% only in those areas M areas outsie the stret%h Cones are
not stret%he.
!erhaps the most %ommon pattern is the %enter3stret%h, >here the mile
portions o$ the image on both a;es are %onsiere stret%hable, but the
eges are not*
33
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 paing bo;. 5he eges o$ the graphi% are le$t unstret%he.
#ome aitional 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', Anroi >ill stret%h both o$ them
but keep them in their %urrent proportions. #o, i$ the $irst Cone is
t>i%e as >ie as the se%on Cone in the original graphi%, the $irst
Cone >ill be t>i%e as >ie as the se%on Cone in the stret%he
graphi%.
.$ you leave out the %ontrol lines $or the paing bo;, it is assume
that the paing 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-SA 3.0 License Edition
Creating 9ra)ables
!igure %./ The dra)5patch tool
While a regular graphi%s eitor >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> insie the main image area itsel$, you >ill be
blo%ke*
35
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 paing
bo;.
While this is %onvenient $or >orking >ith the nine3pat%h nature o$ the
image, you >ill still nee some other graphi%s eitor to %reate or moi$y the
boy o$ the image itsel$. (or e;ample, the image sho>n above, $rom the
7rawable/=ine5atc- proLe%t, is a moi$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%kgrouns, 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-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)
4-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Creating 9ra)ables
)ere, >e have t>o See.;ar >igets, 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 >igets 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 onrogressC!anged(See.;ar see.;ar>
int progress>
boolean from<o&c-) 4
ViewGro&p.*a+o&t5arams old#t-ing<o6esiIe.getLayoutarams():
ViewGro&p.*a+o&t5arams c&rrent#new *inear*a+o&t.Layoutarams(F(1progress>
old.-eig-t):

t-ing<o6esiIe.setLayoutarams(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-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 onrogressC!anged(See.;ar see.;ar>
int progress>
boolean from<o&c-) 4
ViewGro&p.*a+o&t5arams old#t-ing<o6esiIe.getLayoutarams():
ViewGro&p.*a+o&t5arams c&rrent#new *inear*a+o&t.Layoutarams(old.widt->
F(1progress):

t-ing<o6esiIe.setLayoutarams(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-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-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-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER 4
:nimating Widgets
Anroi 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$lege rag3an3rop,
>e >ill %over some o$ the basi% animations an ho> to apply them to your
e;isting >igets.
+t?s @ot Bust !or Toons :nymore
Anroi has a pa%kage o$ %lasses &android.view.animation' ei%ate to
animating the movement an behavior o$ >igets.
5hey %enter aroun an 3nimation base %lass that es%ribes >hat is to be
one. /uilt3in animations e;ist to move a >iget &<ranslate3nimation',
%hange the transparen%y o$ a >iget &3lp-a3nimation', revolving a >iget
&6otate3nimation', an resiCing a >iget &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-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 Deelopment.
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$ Anroi books.
/echanics o* Translation
5he simple %onstru%tor $or <ranslate3nimation takes $our parameters
es%ribing ho> the >iget 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 Anroi o%umentation re$ers to these as fromW7elta,
toW7elta, fromC7elta, an toC7elta.
.n Anroi7s pi;el3spa%e, an (W>C) %oorinate o$ (%>%) represents the upper3
le$t %orner o$ the s%reen. )en%e, i$ toW7elta is greater than fromW7elta, the
>iget >ill move to the right, i$ toC7elta is greater than fromC7elta, the
>iget >ill move o>n, an so on.
44
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
:nimating Widgets
$ma!inin! a (lidin! Panel
#ome Anroi appli%ations employ a sliing 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 Anroi menu system, >ith a %ontainer that slies up $rom the bottom
an slies o>n an out >hen being remove. )o>ever, >hile menus are
limite to menu %hoi%es, Anroi7s animation $rame>ork lets one %reate a
sliing panel %ontaining >hatever >igets 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 immeiately, >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 >iget, but i$ you >ant the >iget to stay
>here it is >hen the animation is over, you have to hanle that yoursel$.
Gther>ise, the >iget >ill snap ba%k to its original position >hen the
animation %ompletes.
.n the %ase o$ the panel opening, >e hanle 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 boy 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-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
hie 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>
getLayoutarams().-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%%oring 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>
getLayoutarams().-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-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*
5-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 ini%ate ho> long the
animation shoul take. 5his is one by %alling set7&ration() on the
animation, proviing the esire length o$ time in millise%ons.
When >e are reay >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/
3lp-a3nimation allo>s you to $ae a >iget in or out by making it less or
more transparent. 5he greater the transparen%y, the more the >iget
appears to be I$aingI.
5%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 >iget, $rom $ully3soli to $ully3transparent.
.n Anroi, a $loat value o$ 1.% ini%ates a $ully3soli >iget, >hile a value
o$ %.% ini%ates a $ully3transparent >iget. ,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 $ae' or vi%e versa.
Animations in 5/"
With <ranslate3nimation, >e sho>e ho> to %onstru%t the animation in
+ava sour%e %oe. 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 $aes out as it is %lose. .n there, you >ill
$in a res/anim/ ire%tory, >hi%h is >here animation resour%es shoul
resie. .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 ini%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 $ae $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-SA 3.0 License Edition
:nimating Widgets
%sin! 5/" Animations
5o make use o$ HML3e$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 loaing our $ae 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 loaing 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.
(or e;ample, >hen >e %lose the panel, >e >ant to use a
<ranslation3nimation to slie 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 ens.
5o o that, you use a animation listener.
An animation listener is simply an instan%e o$ the 3nimation*istener
inter$a%e, provie to an animation via set3nimation*istener(). 5he listener
>ill be invoke >hen the starts, ens, 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.
5$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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>ar3pointing arro>
an setting our %ontent7s visibility to be G2=8, thereby %losing the panel.
=it The :ccelerator
.n aition to the 3nimation %lasses themselves, Anroi also provies a set
o$ Interpolator %lasses. 5hese provie instru%tions $or ho> an animation is
suppose to behave uring its operating perio.
(or e;ample, the 3ccelerateInterpolator ini%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 sliing 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 besies
3ccelerateInterpolator, in%luing*
3ccelerate7ecelerateInterpolator, >hi%h starts slo>ly, pi%ks up
spee in the mile, an slo>s o>n again at the en
7ecelerateInterpolator, >hi%h starts <ui%kly an slo>s o>n
to>ars the en
*inearInterpolator, the e$ault, >hi%h ini%ates the animation
shoul pro%ee smoothly $rom start to $inish
50
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 %an also spe%i$y one o$ the sto%k interpolators via the
android,interpolator attribute in your animation HML $ile.
:nimate/ Set/ 8atch/
(or the 3nimation/Sliding5anel8x proLe%t, though, >e >ant the panel to
slie open, but also $ae >hen it slies %lose. 5his implies t>o animations
>orking at the same time &a $ae an a slie'. Anroi supports this via the
3nimationSet %lass.
An 3nimationSet is itsel$ an 3nimation implementation. (ollo>ing the
%omposite esign pattern, it simply %as%aes 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>
getLayoutarams().-eig-t>
%.%f):
?
52
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
:nimating Widgets
else 4
anim#new +ranslate&nimation(%.%f> %.%f> %.%f>
getLayoutarams().-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>ars', 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 pre3e$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-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 vieo. Bven many more orinary phones are
$ull3$lege M!? players, in aition to o$$ering ringtones an >hatnot.
0ot surprisingly, Anroi has multimeia support $or you, as a eveloper,
to buil your o>n games, meia players, an so on.
5his %hapter is $o%use on auio an vieo playba%kO other %hapters >ill
ta%kle meia input, in%luing the %amera an auio re%oring.
'et 7our 8edia ,n
.n Anroi, you have $ive i$$erent pla%es you %an pull meia %lips $rom M
one o$ these >ill hope$ully $it your nees*
-. Dou %an pa%kage meia %lips as ra> resour%es &res/raw in your
proLe%t', so they are bunle >ith your appli%ation. 5he bene$it is
that you7re guarantee the %lips >ill be thereO the o>nsie is that
they %annot be repla%e >ithout upgraing the appli%ation.
2. Dou %an pa%kage meia %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>nsie M
55
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Playing 8edia
assets are only repla%eable >hen the appli%ation is upgrae M
remains.
?. Dou %an store meia in an appli%ation3lo%al ire%tory, su%h as
%ontent you o>nloa o$$ the .nternet. Dour meia may or may not
be there, an your storage spa%e isn7t in$inite, but you %an repla%e
the meia as neee.
=. Dou %an store meia M or re$eren%e meia 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 meia
as neee, but other appli%ations have a%%ess to the #@ %ar as >ell.
A. Dou %an, in some %ases, stream meia o$$ the .nternet, bypassing
any lo%al storage, as >ith the #tream(urious appli%ation
.nternet streaming is tri%ky, parti%ularly $or vieo, an is >ell beyon the
s%ope o$ this book. (or the 53Mobile 8-, the re%ommene 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 auio %omes in the $orm o$ the 9edia5la+er %lass.
With it, you %an $ee it an auio %lip, startQstopQpause playba%k, an get
noti$ie on key events, su%h as >hen the %lip is reay to be playe or is
one playing.
Dou have three >ays to set up a 9edia5la+er an tell it >hat auio %lip to
play*
-. .$ the %lip is a ra> resour%e, use 9edia5la+er.create() an provie
the resour%e .@ o$ the %lip
2. .$ you have a Dri to the %lip, use the Dri3$lavore version o$
9edia5la+er.create()
?. .$ 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-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 reay to play, su%h as $et%hing the $irst $e> se%ons o$$ the $ile or
stream. 5he prepare() metho is syn%hronousO as soon as it returns, the %lip
is reay 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() ens
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$
-6-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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-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-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())
.setositiveButton($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
alreay 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 Meia!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-SA 3.0 License Edition
Playing 8edia
9edia5la+er to play again. 5he stop() %allba%k is also use $or >hen the
auio %lip %ompletes o$ its o>n a%%or.
5o reset the Meia!layer, the stop() %allba%k %alls release() on the e;isting
9edia5la+er &to release its resour%es', then %alls set&p() again, is%aring
the use 9edia5la+er an starting a $resh one.
5he ". is nothing spe%ial, but >e are more intereste in the auio in this
sample, any>ay*
!igure .6/ The :udio9emo sample application
8oving Pictures
,ieo %lips get their o>n >iget, the VideoView. !ut it in a layout, $ee it an
M!= vieo %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-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 vieo player. Whether it >ill use the $ull
s%reen >ill be epenent on the vieo %lip, its aspe%t ratio, an >hether you
have the evi%e &or emulator' in portrait or lans%ape moe.
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.setVideoat!(clip.get&bsoluteat!()):

ctlr#new %ediaController(t-is):
ctlr.set%edialayer(video):
video.set%ediaController(ctlr):
video.request'ocus():
?
?
?
5he biggest tri%k >ith VideoView is getting a vieo %lip onto the evi%e.
While VideoView oes support some streaming vieo, the re<uirements on
the M!= $ile are $airly stringent. .$ you >ant to be able to play a >ier array
o$ vieo %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-SA 3.0 License Edition
Playing 8edia
5he %rue 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 #tuy o$ the !ubli% @omain7s
Moving .mage Contest, >hi%h >as use in the %reation o$ this book
2. "se m.sdcard &in the Anroi #@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, proviing the
path to your #@ %ar image, so the #@ %ar is ImounteI >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 %oe sho>n above >ill give you a >orking vieo player*
!igure .-/ The (ideo9emo sample application* sho)ing a Creative Commons"
licensed video clip
5apping on the vieo >ill pop up the playba%k %ontrols*
-63
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Playing 8edia
!igure .%/ The (ideo9emo sample application* )ith the media controls
displayed
5he vieo >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, epening 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-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-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER 7
1sing the Camera
Most Anroi evi%es >ill have a %amera, sin%e they are $airly
%ommonpla%e on mobile evi%es these ays. Dou, as an Anroi eveloper,
%an take avantage o$ the %amera, $or everything $rom snapping tourist
photos to s%anning bar%oes. (or simple operations, the A!.s neee to use
the %amera are $airly straight3$or>ar, re<uiring a bit o$ boilerplate %oe
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 Anroi3po>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> moe, 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 %oe 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-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 hien or
e;pose, rather than have Anroi rotate the s%reen $or us
We use android,screen2rientation # $landscape$ to tell Anroi >e
are al>ays in lans%ape moe. 5his is ne%essary be%ause o$ a bit o$ a
bug in the %amera previe> logi%, su%h that it >orks best in
lans%ape moe.
--%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 outsie o$ the realm o$ your
orinary >igets. .n this %ase, Anroi 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 by the
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)
The Camera
5he biggest step, o$ %ourse, is telling Anroi 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-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 reay or %hanges
5ell the S&rfaceView &via the S&rfaceBolder' that it has the
SD6K3C8/<C58/5DSB/;DKK86S type &set<+pe()' M this ini%ates
something in the system >ill be upating the S&rfaceView an
proviing 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 reay
immeiately a$ter being %hange into SD6K3C8/<C58/5DSB/;DKK86S moe. #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.setreview"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-SA 3.0 License Edition
1sing the Camera
?
?
0e;t, on%e the S&rfaceView is set up an siCe by Anroi, >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 pre3etermine 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, upate 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.getarameters():
parameters.setreviewSi.e(widt-> -eig-t):
camera.setarameters(parameters):
camera.startreview():
?
Bventually, the previe> nees 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.stopreview():
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-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.setreview"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.getarameters():
parameters.setreviewSi.e(widt-> -eig-t):
camera.setarameters(parameters):
camera.startreview():
?
p&blic void surface"estroyed(S&rfaceBolder -older) 4
camera.stopreview():
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-SA 3.0 License Edition
1sing the Camera
5he %oe snippets sho>n in this se%tion are pulle $rom the Camera/5ict&re
sample proLe%t, >hi%h buils 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%ie 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 ini%ate that >e, inee, >ant +!B8*
p&blic void surfaceC!anged(S&rfaceBolder -older>
int format> int widt->
int -eig-t) 4
Camera.5arameters parameters#camera.getarameters():
parameters.setreviewSi.e(widt-> -eig-t):
parameters.seticture'ormat(5ixelKormat.J58G):
camera.setarameters(parameters):
camera.startreview():
?
Connectin! the Camera Button
#omeho>, your appli%ation >ill nee to ini%ate >hen a pi%ture shoul be
taken. 5hat %oul be via >igets 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-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)eicture():
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 ei%ate sear%h key, >hi%h is in the
upper3right portion o$ the Magi%7s $a%e >hen the evi%e is hel in lans%ape
moe.
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)eicture() 4
camera.stopreview():
camera.ta)eicture(n&ll> n&ll> p-otoCallbac.):
?
--4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
1sing the Camera
5he Camera.5ict&reCallbac. &p-otoCallbac.' nees to implement
on5ict&re<a.en(), >hi%h provies 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
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 sening 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 threas, parti%ularly i$ >e are sening the image over the
.nternet an o not have a $ast %onne%tion to our estination server.
Anroi -.A o$$ers a >ork <ueue moel, 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 Save5-oto<as., as
$ollo>s*
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-SA 3.0 License Edition
1sing the Camera
tr+ 4
Kile2&tp&tStream fos#new 'ile$utputStream(p-oto.getat!()):
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
Anroi. 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 onicture+a)en(b+tePQ data> Camera camera) 4
new Save!oto+as)().e(ecute(data):
camera.startreview():
?
?:
-%6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
PART III Advanced System
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER 9
Sensors
I#ensorsI is Anroi7s overall term $or >ays that Anroi %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 ae 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 Anroi evi%es like the 53Mobile 8-.
5he samples in this %hapter assume that you have a%%ess to a pie%e o$
sensor3e<uippe Anroi 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 %oe samples that helpe
%lear up %on$usion surrouning the use o$ sensors.
The Sixth Sense/ ,r Possibly the Seventh/
.n theory, Anroi 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 ark the
surrounings are
-%.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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
surrouning environment
A tri%orer sensor, to turn the evi%e into Ia $ully $un%tional
5ri%orerI
Clearly, not all o$ these possible sensors are available toay, su%h as the last
one. What e$initely are available toay 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$ Anroi, 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, Anroi i all that as part o$ the orientation sensor...so
long as the evi%e is hel $lat in the horiContal plane &e.g., on a level
tabletop'.
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-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 upates >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 upates ine$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 methos. 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
provie 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-SA 3.0 License Edition
Sensors
.n Sensor/Compass, >e upate a <extView >ith the ea%h reaing*
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-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.
Anroi %an o this too. Dou %an see it in the Sensor/Steering sample
appli%ation.
.n the pre%eing 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 IsteereI.
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 (prev2rientationorientation) 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-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 provie the ne> %urrent position o$ the >heel an the
amount the >heel turne, measure in egrees.
5he steer*eft() an steer6ig-t() methos, in turn, simply ump their
results to a Itrans%riptI* a <extView insie 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-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.
Anroi %an o this as >ell, as you %an see in the Sensor/S-a.er sample
appli%ation, >ith our ata provie by the a%%elerometer sensor
&<C58/3CC8*86298<86'.
What the a%%elerometer sensor provies 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
epenent on ho> har the evi%e is being shaken. While the iniviual
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> steay 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 shake3ete%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-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 ini%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-SA 3.0 License Edition
Sensors
means the shake has to be 2AP stronger than gravity to be
%onsiere a shake
An amount o$ time >ith belo>3threshol a%%eleration, a$ter >hi%h
the shake is %onsiere IoneI
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 methos &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 ens.
5he S-a.er simply %onverts the three iniviual 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 %onsier 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 ens, an time elapses, >e %all
s-a.ingStopped() on the %allba%k obLe%t an assume that the shake has
ene. A more robust implementation o$ S-a.er >oul take into a%%ount
the possibility that the sensor >ill not be upate $or a >hile a$ter the
shake ens, though in reality, normal human movement >ill ensure that
there are some sensor upates, so >e %an $in out >hen the shaking ens.
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-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-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-oldnetKorce) 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-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER 1:
9atabases and Content
Providers
.n the abstra%t, >orking >ith #FLite atabases an Anroi3style %ontent
proviers 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 proviers %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
upateJ
Where is the o%umentation $or the built3in Anroi %ontent
proviersJ
)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 proviers in the real >orl.
-.0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
9atabases and Content Providers
9istributed 9ata
#ome atabases use by Anroi appli%ations naturally start empty. (or
e;ample, a Ipass>or sa$eI probably has no pass>ors >hen initially
laun%he by the user, an an e;pense3tra%king appli%ation probably oes
not have any e;penses re%ore 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 upate as neee 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%ors.
"n$ortunately, there is no >ay to ship a atabase >ith ata in it via the
Anroi A!K pa%kaging me%hanism. An A!K is an e;e%utable blob, $rom
the stanpoint o$ Anroi an @alvik. More importantly, it is store rea3
only in a E.! $ile, >hi%h makes upates 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$ neee.
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 avantage o$ e;isting atabase manipulation tools &versus,
say, han3>riting hunres 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-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 Anroi. 5his %an >ork, but is likely to be more prone to versioning
issues M $or e;ample, i$ your evelopment environment is upgrae 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 Anroi 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 insie an Anroi
emulator or evi%e.
5he plan, there$ore, is to allo> evelopers to %reate the atabase to be
IshippeI as a #FLite atabase, then buil tools that pa%kage the #FLite
%ontents into the Anroi A!K an turn it ba%k into a atabase >hen the
appli%ation nees 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$ %oe*
-. We nee something that e;tra%ts the ata out o$ the #FLite
atabase the eveloper has prepare an puts it somepla%e insie
the Anroi A!K
2. We nee something that ties in >ith S[*ite2penBelper that takes the
A!K3pa%kage ata an turns it into an on3evi%e atabase >hen
the atabase is $irst a%%esse.
E'portin! a Data#ase
(ortunately, the s@liteJ %omman3line e;e%utable that %omes stanar
>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-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 %oe that hanles 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 Deelopment
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 %oe 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 eition 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-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 neeing 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 tables as a set o$ #FL
statements*
;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 Anroi itsel$ M an ship those along
>ith the table s%hema.
"oadin! the E'ported Data#ase
5he other en o$ his pro%ess is to take the ra> #FL stores in
res/raw/pac.aged/db.txt an Iin$lateI it at runtime into a atabase. #in%e
-.5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
9atabases and Content Providers
S[*ite2penBelper is esigne to hanle 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*
import android.content.Context:
import android.database.S[*8xception:
import [email protected][*ite2penBelper:
import [email protected][*ite7atabase:
import [email protected][*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-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 reaing 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 hanle 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
on3evi%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 [email protected][*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-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 ienti%al to the Content5rovider/Constants
sample $rom The Busy Coder's Guide to Android Deelopment.
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 reaer as an e;er%ise.
<xamining 7our Eelationships
Anroi has a built3in %onta%t manager, integrate >ith the phone ialer.
Dou %an >ork >ith the %onta%ts via the Contacts %ontent provier.
)o>ever, %ompare to %ontent proviers $oun in, say, simpli$ie book
e;amples, the Contacts %ontent provier is rather intimiating. A$ter all,
there are -4 %lasses an 9 inter$a%es all involve in a%%essing this %ontent
provier. 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, moi$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-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 unerlying the Contacts %ontent provier is private, one
%an imagine that it has several tables* one $or people, one $or their phone
numbers, one $or their email aresses, et%. 5hese are tie together by
typi%al atabase relations, most likely -*0, so the phone number an email
aress 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 provier inter$a%e,
Anroi 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-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+3dapterString) aa#new 3rra+3dapterString)(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-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-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
provier, retrieve all o$ the %onta%ts in the e$ault sort orer, 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-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 one by
<uerying the C2=<8=</D6I %ontent provier*
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):
-$3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 o%umentation $or Contacts.5-ones sho>s that it in%orporates
Contacts.5eopleCol&mns an 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%lue 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 aresses, >e %an use the
C2=<8=</893I*/D6I %ontent provier, >hi%h in%orporates the
-$4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
9atabases and Content Providers
Contacts.Contact9et-odsCol&mns an Contacts.5eopleCol&mns, so >e %an get
a%%ess to the %onta%t name as >ell as the email aress itsel$ &73<3'*
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-SA 3.0 License Edition
9atabases and Content Providers
Eummaging Through 7our Phone Eecords
5he Call*og %ontent provier in Anroi 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 provier 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%lue*
=D9;86* the phone number asso%iate >ith the %all
73<8* >hen the %all >as pla%e, in millise%ons3sin%e3the3epo%h
$ormat
7D63<I2=* ho> long the %all laste, in se%ons
<C58* ini%ating i$ the %all >as in%oming, outgoing, or misse
5hese, o$ %ourse, are augmente by the sto%k ;aseCol&mns, >hi%h
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 unmoi$iable by Anroi 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-SA 3.0 License Edition
9atabases and Content Providers
Also note that, to a%%ess the %all log, you nee the 6837/C2=<3C<S
permission.
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 thir3party
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 &toay' 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$. Anroi7s C&rsors o$$er a
$airly vanilla inter$a%e, an Anroi even supplies a C&rsorWrapper %lass that
%an hanle 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, blening 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 aresse in a serious prou%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.
-0-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
9atabases and Content Providers
Cursorrapper
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 unerlying C&rsor ire%tlyJ
5he key is not C&rsorWrapper itsel$, but rather %ustom sub%lasses o$
C&rsorWrapper. Dou %an then overrie %ertain C&rsor methos, to per$orm
>ork in aition 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 aitional %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 as I%all notesI M a blo%k o$
te;t about a spe%i$i% %all one mae. 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 moi$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 %oe, an some is ue to the problem being solve.
-0%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
9atabases and Content Providers
What >e nee the JoinC&rsor to o is*
Gverrie C&rsor3relate methos that involve the %olumns
Che%k to see i$ there is a note $or the %urrent ro>
ALust the results o$ the metho to a%%omoate 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#%:iAoin.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#%:iAoin.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-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-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-9apString> 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-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, gets both the C&rsor to >rap an an
I/JoinBandler instan%e. 5he Loin hanler is responsible $or getting the e;tra
%olumns $or a given ro>*
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 aLust the
results o$ various C&rsor methos. (or e;ample*
getCol&mnCo&nt() returns the sum o$ the C&rsor7s %olumn %ount an
the number o$ e;tra %olumns returne by the Loin hanler
getCol&mnIndex() an kin nee to sear%h through the Loin hanler7s
%olumns as >ell as the C&rsor7s to $in the mat%h, i$ any
getInt(), is=&ll(), an kin nee to support retrieving values $rom
both the C&rsor an the Loin hanler
-02
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 overrie re@&er+() to $lush the
%a%he i$ the C&rsor itsel$ is being proa%tively upate.
%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-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 ini%ate that >e are, inee, 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
Calllus&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-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-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>, ini%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 [email protected][*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-SA 3.0 License Edition
9atabases and Content Providers
setList&dapter(new Calllus&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+oosition(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):

-2-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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-SA 3.0 License Edition
9atabases and Content Providers
?
?:

class Call5l&s3dapter extends C&rsor3dapter 4
Calllus&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-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>, epening 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 eit 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 smuge $or priva%y'*
-2$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 Anroi, 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 evi%e is
po>ere on.
-23
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 perioi%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 resient in memory all the time.
The Permission
.n orer 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 Anroi o%umentation es%ribes it*
Thou"h holdin" this permission does not hae any security
implications$ it can hae a ne"atie impact on the user e%pe&
rience by increasin" the amount o' time it takes the system
to start and allowin" applications to hae themseles 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
register6eceiver() $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*
-24
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 Anroi 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-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 moi$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 threas, ire%tly or inire%tly,
sin%e the ;roadcast6eceiver gets is%are 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 neee.
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, Anroi 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-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>ith3intensive 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>ith, >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 Anroi 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*
-3-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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-SA 3.0 License Edition
=andling System <vents
0ote that, to test this, you >ill nee an a%tual Anroi 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 reu%ing your impa%ts on the evi%e >hile the evi%e is not in a
great state. .n the pre%eing se%tion, >e sa> ho> you %oul $in out >hen
Wi(i >as isable, so you might not use as mu%h ban>ith >hen on
?8Q8!R#. )o>ever, not every appli%ation uses so mu%h ban>ith 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$est3e%lare re%eiver as sho>n in the
pre%eing 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-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-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 onause() 4
s&per.onause():

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.setrogress(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-SA 3.0 License Edition
=andling System <vents
-ealt-, >hi%h shoul generally be ;3<<86C/B83*<B/G227
level, >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 ini%ate i$ the evi%e is plugge into AC po>er
&;3<<86C/5*DGG87/3C' or "#/ po>er &;3<<86C/5*DGG87/DS;'
scale, >hi%h ini%ates the ma;imum possible value o$ level &e.g.,
1%%, ini%ating that level is a per%entage o$ %harge remaining'
stat&s, >hi%h >ill tell you i$ the battery is %harging
&;3<<86C/S<3<DS/CB36GI=G', $ull &;3<<86C/S<3<DS/KD**', or is%harging
&;3<<86C/S<3<DS/7ISCB36GI=G'
tec-nolog+, >hi%h ini%ates >hat sort o$ battery is installe &e.g.,
$*i'Ion$'
temperat&re, >hi%h tells you ho> >arm the battery is, in tenths o$ a
egree Celsius &e.g., E1J is 2-.? egrees Celsius'
voltage, ini%ating the %urrent voltage being elivere by the
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 iviing
the level by the s%ale
2. We upate 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 epening 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-SA 3.0 License Edition
=andling System <vents
!igure $-/ The Battery8onitor application
-33
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER 12
1sing System Services
Anroi o$$ers a number o$ system servi%es, usually obtaine by
getS+stemService() $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 builing %ompelling Anroi appli%ations.
'et :larmed
A %ommon <uestion >hen oing Anroi evelopment is I>here o . set
up cron LobsJI
5he cron utility M popular in Linu; M is a >ay o$ s%heuling >ork to be one
perioi%ally. Dou tea%h cron >hat to run an >hen to run it &e.g., >eekays
at noon', an cron takes %are o$ the rest. #in%e Anroi has a Linu; kernel
at its heart, one might think that cron might literally be available.
While cron itsel$ is not, Anroi 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
neee. /y this me%hanism, you %an get a similar e$$e%t to cron.
5here is one small %at%h, though* Anroi 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-SA 3.0 License Edition
1sing System Services
your perioi% 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 Anroi, you are eveloping %oe 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%heule ba%kgroun tasks, though, you nee to bear in
min that the evi%e >ill eventually Igo to sleepI. .n $ull sleep moe, 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 %oe 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 responing 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-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%heule 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

-4-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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
ini%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 nees 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 $rom
S+stemServices/3larm*
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-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 %oe 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 %orresponing
number o$ release() %alls to truly release the lo%k'. .$ >e have alreay
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 the 3ppService instan%e &remember*
ac@&ireStatic*oc.() >as a static metho' an e;its. 0otably,
-4.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
1sing System Services
2n3larm6eceiver 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
neee, use overlapping Wa.e*oc. instan%es to ensure %onstant %overage as
you pass $rom %omponent to %omponent.
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, uner 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 neee to be one sometimes takes longer than the
alarm perio, >e %oul >in up >ith many ba%kgroun threas,
>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 threas.
-4$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
1sing System Services
Anroi has a %lass that helps >ith parts o$ this, IntentService. .t arranges
$or a >ork <ueue o$ inboun Intents M rather than overriing onStart(), you
overrie onBandleIntent(), >hi%h is %alle $rom a ba%kgroun threa.
Anroi hanles all the etails o$ shutting o>n your servi%e >hen there is
no more outstaning >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 hanles most o$ the Wa.e*oc. logi%,
so 3ppService &inheriting $rom Wa.ef&lIntentService' %an Lust $o%us on the
>ork it nees to o.
Wa.ef&lIntentService hanles the Wa.e*oc. logi% in $our %omponents*
-. .t o$$ers the publi% stati% metho ac@&ireStatic*oc.(), >hi%h nees
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 hanle by
onBandleIntent().
)ere is the $ull implementation o$ Wa.ef&lIntentService*
-40
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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-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&bsoluteat!()> 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-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 neee 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 Anroi 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 methos on Settings.S+stem, ea%h taking a key as a parameter.
5he keys are %lass %onstants, su%h as*
I=S<3**/=2=/936V8</355S to %ontrol >hether you %an install
appli%ations on a evi%e $rom outsie o$ the Anroi Market
*2CV/53<<86=/8=3;*87 to %ontrol >hether the user nees to enter a
lo%k pattern to enable use o$ the evi%e
*2CV/53<<86=/VISI;*8 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
5he S+stemServices/Settings proLe%t has a SettingsSetter sample
appli%ation that isplays a %he%klist*
!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-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-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#%:isettings.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-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 to $our a%tivity Intent values ienti$ie by the
Settings %lass*
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 %orresponing 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 Anroi3supplie a%tivity
$or manipulating those settings.
(ecure (ettin!s
Dou >ill noti%e that i$ you use the above %oe 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.
-5-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 Anroi -.- an earlier M it i.
0o>, though, that setting is one that Anroi 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 Anroi 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 heaphones.
.n Anroi, though, there are several sour%es o$ souns*
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 souns &error beeps, "#/ %onne%tion signal, et%.'
Musi%, as might %ome $rom the M!? player
Anroi 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-SA 3.0 License Edition
1sing System Services
volume buttons %hange the voi%e %all volume'. Also, there is a s%reen in the
Anroi #ettings appli%ation that allo>s you to %on$igure various volume
levels.
5he 3&dioService in Anroi 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 moi$ies all $ive volume levels, reusing the 9eter >iget >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 >iget reuse
moels be%ome apparent, e;pe%t upates to this book to %over them.
Attachin! /eters to ,olume (treams
8iven that >e have our 9eter >iget to >ork >ith, setting up 9eter >igets
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-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-SA 3.0 License Edition
1sing System Services
app,decr#$1$
/)
/<able6ow)
/<able*a+o&t)
5hen, >e nee to >ire up ea%h o$ those meters in the onCreate() $or
Vol&miIer*
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 ienti$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 methos on Vol&me9anager*
-50
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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.setrogress(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 aLusts
the stream to mat%h*
!igure $./ The (olumi;er application
-52
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER 1)
7our ,)n #:dvanced& Services
.n The Busy Coder's Guide to Android Deelopment, >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 outsie 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 Anroi %omponents. Ba%h servi%e
e%lares >hat methos it is making available over .!CO those methos are
then available $or other %omponents to %all, >ith Anroi hanling all the
messy etails involve >ith making metho %alls a%ross %omponent or
pro%ess bounaries.
5he guts o$ this, $rom the stanpoint o$ the eveloper, is e;presse in A.@L*
the Anroi .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 Anroi supplies tools to
buil the %lient an server sie 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-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 methos are >rappe in an inter$a%e e%laration &interface
IScript 4 ... ?'. An, as >ith a +ava inter$a%e, you list the methos 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.@L3e$ine inter$a%es
Any +ava %lasses that implement the 5arcelable inter$a%e, >hi%h is
Anroi7s $lavor o$ serialiCation
.n the %ase o$ the latter t>o %ategories, you nee to in%lue 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-SA 3.0 License Edition
7our ,)n #:dvanced& Services
ba%k to the %lient. !rimitives &e.g., int' %an only be inO >e in%lue 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 %oe, eal >ith them, an return $ailure ini%ations
some other >ay &e.g., error %oe return values'.
0ame your A.@L $iles >ith the .aidl e;tension an pla%e them in the
proper ire%tory base on the pa%kage name.
When you buil your proLe%t, either via an .@B or via Ant, the aidl utility
$rom the Anroi #@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 methos you have alreay >ritten.
5he me%hani%s o$ this are $airly straight$or>ar*
Create a private instan%e o$ the A.@L3generate .St&b %lass &e.g.,
IScript.St&b'
.mplement methos mat%hing up >ith ea%h o$ the methos you
pla%e in the A.@L
Return this private instan%e $rom your on;ind() metho in the
Service sub%lass
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-SA 3.0 License Edition
7our ,)n #:dvanced& Services
: Consumer <conomy
G$ %ourse, >e nee to have a %lient $or A.@L3e$ine servi%es, lest these
servi%es $eel lonely.
Bound *or (uccess
5o use an A.@L3e$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 nees to implement t>o methos*
-. onServiceConnected(), >hi%h is %alle on%e your a%tivity is boun to
the servi%e
2. onService7isconnected(), >hi%h is %alle i$ your %onne%tion ens
normally, su%h as you unbining your a%tivity $rom the servi%e
Ba%h o$ those methos re%eives a Component=ame, >hi%h simply ienti$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 methos 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-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 alreay
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 reay $or use.
Re?uest *or (ervice
Gn%e your servi%e inter$a%e obLe%t is reay
&IScript.St&b.asInterface(binder)', you %an start %alling methos on it as
you nee to. .n $a%t, i$ you isable some >igets 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%tely. .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 ini%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 >igets, or other>ise $lag
yoursel$ as no longer being able to use the servi%e.
(or e;ample, in the Weather!lus implementation o$
onService7isconnected() sho>n above, >e null out the IWeat-er servi%e
obLe%t.
%6-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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%eing 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
Deelopment spe%i$i%ally in the %onte;t o$ lo%al servi%es. )o>ever, A.@L
as 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 bounaries, >hi%h is >hy there are so many <uirky rules about
>hat you %an an %annot pass as parameters to your A.@L3e$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 Deelopment into a remote servi%e.
.$ you a%tually >ante to use s%ripting in an Anroi appli%ation, >ith
s%ripts loae o$$ o$ the .nternet, isolating their e;e%ution into a servi%e
might not be a ba iea. .n the servi%e, those s%ripts are sanbo;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.@L3e$ine A!., you nee to %ra$t an .ntent that %an
ienti$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-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, ini%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 ienti$ie by the name
com.commonsware.android.advservice.IScript. #o long as the %lient uses this
name to ienti$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-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 hanles 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-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-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())
.setositiveButton($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 nees 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 %oe
>ith the servi%e. .n a prou%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 uner, 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-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 %oe 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%eing se%tion outline t>o $la>s in the implementation o$ the
/eanshell remote servi%e*
-. 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-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%eing 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.@L3e$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-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 sie 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-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)
.setositiveButton($2V$> n&ll)
.s!ow():
?
An, o$ %ourse, >e nee to upate 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-SA 3.0 License Edition
7our ,)n #:dvanced& Services
Revisin! the (ervice
5he servi%e also nees %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 emonstrate 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&eJob) @#new *in.ed;loc.ing[&e&eJob)():

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):
%--
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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-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 nees 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 mae 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 get its results
>ithout tying up the %lient7s ". threa.
%-.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 iea 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
Anroi, >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-SA 3.0 License Edition
!inding :vailable :ctions via +ntrospection
5he problem is, you have absolutely no iea >hat is all possible >ith any
given %ontent Dri. Dou probably %an vie> any o$ them, but %an you eit
themJ Can you ial themJ #in%e ne> appli%ations >ith ne> types o$
%ontent %oul be ae 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 Anroi evi%es.
(ortunately, the Anroi evelopers thought o$ this.
Anroi 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
iea >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 Anroi %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 %oe, 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-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-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-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-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. Anroi appli%ations are per$e%tly %apable o$ aing 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 introu%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 ini%ate they >ant to tag it, >hi%h leas 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 aing a%tions to another
appli%ation7s %ontent.
.$ you >ant to >rite a%tivities that are a>are o$ possible a3ons like
tagging, you shoul use addIntent2ptions() to a those a3ons7 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-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 moi$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 orer ae 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 hanle 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-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$ $ining 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-SA 3.0 License Edition
PART IV Advanced Development
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
CHAPTER 10
Testing 7our Patience
!resumably, you >ill >ant to test your %oe, beyon Lust playing aroun
>ith it yoursel$ by han.
5o that en, Anroi in%lues 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
Anroi %omponents, like a%tivities an servi%es. Bven better, Anroi -.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 Anroi -.A using anroi %reate proLe%t,
Anroi automati%ally %reates a ne> tests/ ire%tory insie the proLe%t
ire%tory. .$ you look in there, you >ill see a %omplete set o$ Anroi
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 reay 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-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.
Anroi ships >ith a very ruimentary +"nit runner, %alle
Instr&mentation<est6&nner. #in%e this %lass resies in the Anroi
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
.n this %ase, >e are instru%ting Anroi 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 %oe $or the test %ase that Anroi automati%ally
generates $or you*
pac.age com.commonsware.android.database:
%%2
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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<estCaseContacts7emo) 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 methos. .nstea, >e have an
3ctivit+Instr&mentation<estCase implementation name Contacts7emo<est.
5he %lass name >as generate by aing 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 orinary +"nit test %ases in Anroi M
a$ter all, this is Lust +"nit, merely augmente by Anroi. #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-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 Anroi3spe%i$i% in this test %ase. .t is simply stanar
+"nit, albeit a bit silly.
Dou %an also %reate test suites, to bunle up sets o$ tests $or e;e%ution.
)ere, though, i$ you >ant, you %an take avantage o$ a bit o$ Anroi
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&llac)agesUnder*ere()
.build()):
?
?
)ere, >e are telling Anroi 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-SA 3.0 License Edition
Testing 7our Patience
)ere, >e ini%ate >e only >ant to run Contacts7emo<est, not all test %ases
$oun in the pa%kage.
Testing Eeal Stuff
While orinary +"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, Anroi 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 Anroi7s #@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 >igets
.nvoke publi% an pa%kage3private methos &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<estCaseContacts7emo) 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-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
3ctivit+Instr&mentation<estCase is a generi%, you nee to supply the
name o$ the a%tivity being teste &e.g.,
3ctivit+Instr&mentation<estCaseContacts7emo)'.
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 ini%ating i$ the
a%tivity shoul be laun%he in tou%h moe or not.
?. .n setDp(), use get3ctivit+() to get your hans on your 3ctivit+
obLe%t, alreay type%ast to the proper type &e.g., Contacts7emo'
%ourtesy o$ our generi%. Dou %an also at this time a%%ess any >igets,
sin%e the a%tivity is up an running by this point.
=. .$ neee, %lean up stu$$ in tear7own(), no i$$erent than >ith any
other +"nit test %aseQ
A. .mplement test methos to e;er%ise your a%tivity. .n this %ase, >e
simply %on$irm that the Spinner has three items in its rop3o>n
list an there is at least one %onta%t loae into the *istView by
%.6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 neeO on the other han, it
oes mean that the test %ase runs slo>ly, sin%e the a%tivity nees to be
%reate an estroye $or ea%h test metho in the test %ase. .$ your a%tivity
oes a lot on startup anQor shuto>n, this may make running your tests a
bit sluggish.
0ote that your 3ctivit+Instr&mentation<estCase resies 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 methos an
ata members. Contacts7emo<est still %annot a%%ess private methos,
though. 5his allo>s 3ctivit+Instr&mentation<estCase to behave in a >hite3
bo; &or at least gray3bo;' $ashion, inspe%ting the insies o$ the teste
a%tivities in aition to testing the publi% A!..
0o>, espite the $a%t that Anroi7s o>n tools %reate an
3ctivit+Instr&mentation<estCase sub%lass $or you, that %lass is o$$i%ially
epre%ate. 5hey avise 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 proviers, $or e;ample.
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 iniviual
a%tivities or servi%es are not.
%.-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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
>igets ienti$ie properly, are they positione properly, oes the $o%us
>ork, et%. As it turns out, none o$ that a%tually nees 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 testRelativeosition() 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-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 >igets in the in$late View hierar%hy M in
this %ase, >e lay them out on a =20;?20 s%reen
?. A%%ess the iniviual >igets to be teste
At that point, >e %an test stati% in$ormation on the >igets, 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 >igets e;ist an
are lai out as e;pe%te. We %oul use Koc&sKinder to test >hether $o%us
%hanges $rom one >iget to the ne;t shoul >ork as e;pe%te. We %oul
ensure our resour%es e;ist uner 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
Anroi also o$$ers various other test %ase base %lasses esigne to assist in
testing Anroi %omponents, su%h as*
Service<estCase, use $or testing servi%es, as you might e;pe%t given
the name
3ctivit+Dnit<estCase, a <estCase that %reates the 3ctivit+ &like
3ctivit+Instr&mentation<estCase', 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
.nepenent $rom the +"nit system is the Monkey.
%..
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Testing 7our Patience
5he Monkey is a test program that simulates ranom 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
ranom input entere into a 5>itter %lient may, inee, post that ranom
input to 5>itter. 5he Monkey oes not test to make sure that results o$
ranom input make senseO it only tests to make sure ranom 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%ons. 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', @3paQtra%kball moves, an
sliing 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 lans%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 provie a see
$or the ranom number generator. /y e$ault, the Monkey %reates its o>n
%.$
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Testing 7our Patience
see, giving totally ranom results. .$ you supply the see, >hile the
se<uen%e o$ events is ranom, it is ranom $or that see M repeately 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 reprou%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 8uie %overs all o$ that an more.
%.0
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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??
Aapter......................................?03?2, ?A, ?4, -=4
Aapter,ie>.Gn.tem#ele%teListener...........=4
AlarmManager.......44, -42, -19, -20, -22, -2?, -2A
Alert@ialog......................................................209
AlphaAnimation..............................21, 9239=, 91
AnalogClo%k......................................................A0
Anroi5estCase......................................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
AppWiget)ost................................................44
AppWiget)ost,ie>.......................................44
AppWigetManager..............................A4, 4-, 4A
AppWiget!rovier........................AA, A9, 4=, 4A
Asyn%5ask.........................................................--9
Attribute#et.......................................................-4
Auio#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%[email protected]
/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-SA 3.0 License Edition
Gey)ord +ndex
CallLog.Calls....................................................-A0
Call!lusAapter........................................-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%tMethosColumns...............-=9
Conta%ts.!eopleColumns.........................-=2, -=9
Conta%ts.!hones..............................................-=2
Conta%ts.!honesColumns...............................-=2
Conta%[email protected]=?, -=1, 221, 2?0, 2?-
Conta%ts@emo/ase5est...........................2?2, 2??
Conta%[email protected], 229, 2?-
Content!rovier........................................-A-, -42
Content,alues..................................................-A1
Conte;t..............-4, 9=, -2=, -?0, -10, -19, 2?-, 2??
Cursor..............................?-, -A03-A?, -A4, -A1, -40
CursorAapter.................................................-A2
Cursor+oiner......................................................-A-
CursorWrapper..........................................-A-, -A2
Cy%le.nterpolator........................................9=, 94
@atabase.nstaller......................................-=03-=2
@eaGbLe%tB;%eption.....................................20-
@e%elerate.nterpolator.....................................9A
@ra>able...............................2?324, =2, 1-, 12, -9?
@ra>[email protected]
Bit5e;t..............................................................A-
B;%eption..........................................................2--
B;e%ute#%ript+ob...............................................2--
(o%us(iner.....................................................2??
(rameLayout.....................................................A0
(ull#uite...........................................................222
8eoWebGne........................................................2
)eaer(ooter@emo..........................................?2
.R+oin)anler............................................-A4, -A1
./iner.............................................................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
[email protected], -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-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
MeiaQAuio.....................................................-0-
Meia!layer................................-00, -0-, -0=, -0A
Menu..........................................................9=, 220
Menu..tem........................................................22-
Meter................................-?3-4, -2, -9, 2-, -9?, -9A
Meter@emo........................................................2-
MyA%tivity........................................................22-
0ine!at%[email protected]
0oteA%tivity.....................................................-4=
0oteBitor.......................................................-4=
GnAlarmRe%eiver.....................................-223-2=
Gn/ootComplete..........................................-49
Gn/ootRe%eiver........................................-49, -2-
GnCli%kListener.................................................A-
GnWi(iChangeRe%eiver...................................-1-
!a%kageManager.............................................222
!ar%elable.........................................................-92
!ening.ntent................................A-, A2, -19, -22
!hotoCallba%k..................................................-20
!i%[email protected], -20
!o>erManager..........................................-20, -2?
!re$eren%eA%tivity......................................A2, 40
!revie>@emo.............................................--2, --?
!rogress/ar...............................-?, -=, A0, -1?, -14
RelativeLayout..................................................A0
RemoteB;%eption.............................................20-
Remote#ervi%e.................................................20?
Remote,ie>s...............................A0, A-, AA3A9, 4-
RotateAnimation........................................21, 9=
#ave!hoto5ask..........................................--9, -20
#%aleAnimation.................................................21
#%roll,ie>........................................................-22
#e%tion...............................................................?A
#e%tioneAapter..................................?2, ?A, ?4
#e%tione@emo...........................................?2, ?4
#eek/ar.........................................................-?, 22
#ele%torAapter................................................=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................................................-?-
#[email protected], -?-
#hare!re$eren%es............................................A2
%.5
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Gey)ord +ndex
#impleCursorAapter....................?-, ?2, -=4, -=9
#liing!anel....................................90, 92, 9=394
#[email protected]
#pinner.......................................-=?, -==, -=4, 2?0
#[email protected]=-
#FLiteGpen)elper............................-?1, -=0, -=-
#tring................................................................-92
#ur$a%e)oler.............................................--?, --=
#ur$a%e)oler.Callba%k.............................--=, --A
#ur$a%e,ie>.................................................--?3--A
5estCase....................................................229, 2??
5est#uite..........................................................222
5est#uite/uiler..............................................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>itterWiget..................................A=3A4, 4=344
5W!re$s.......................................................A2, A9
5ypeArray....................................................-4, -1
"pate#ervi%e..............................................A4, A1
"ri..........................................99, -00, 2-A32-1, 22-
,[email protected]
,ieo,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....................................................-
Wiget!rovier.................................................4-
Command......................................
ab 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....................................20-
CA5B8GRDRAL5BR0A5.,B...................220, 22-
@B(A"L5RCA5B8GRD....................................22-
MA5C)R@B(A"L5RG0LD..............................22-
RB#"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-SA 3.0 License Edition
Gey)ord +ndex
a(ooter,ie>&'...............................................?2
a)eaer,ie>&'..............................................?2
a.ntentGptions&'.................................2203222
a+avas%ript.nter$a%e&'.............................2, =, 4
a#e%tion&'......................................................?A
areAll.tems#ele%table&'....................................?0
bin#ervi%e&'....................................2003202, 204
buil(ooter&'.....................................................=0
buil)eaer&'...................................................=0
buil"pate&'..............................................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.ne;&'...........................................-A4
getConte;t&'.....................................................2??
getCount&'.........................................................?A
get)oler&'.......................................................--=
get.nt&'........................................................-4, -A4
get.tem&'............................................................?A
get.tem,ie>5ype&'......................................?A, ?4
get+oin&'.....................................................-A1, -A2
getLo%k&'..........................................................-2?
get!a%kageManager&'.....................................222
get#ystem#ervi%e&'............................-2=, -19, -22
get,ie>&'......................................................?2, ?A
get,ie>5ypeCount&'...................................?A, ?4
hanle.nstallBrror&'.........................................-=-
initMeter&'........................................................-9A
insert&'..............................................................-?A
isBnable&'........................................................?0
is0ull&'..............................................................-A4
loaAnimation&'...............................................9=
loa"rl&'..........................................................1, 9
obtain#tyleAttributes&'...................................-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)anle.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
%$-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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, 20-
on#ervi%e@is%onne%te&'........................200, 20-
on#tart&'....................................................-2=, -2A
on"pate&'............................................AA, 4=, 4A
on"pgrae&'.....................................................-=-
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
senKeys&'........................................................2?-
setAnimationListener&'....................................9=
set@ata#our%e&'...............................................-00
set@uration&'....................................................92
set.nterpolator&'...............................................94
setMa;&'...........................................................-9A
setGnCli%k!ening.ntent&'..............................A2
setGn.tem#ele%teListener&'...........................=?
set!i%ture(ormat&'...........................................--1
set!revie>@isplay&'.........................................--=
set!rogress&'....................................................-9A
setRepeating&'..................................................-22
setResult&'..........................................................4-
set5e;t,ie>5e;t&'.............................................A2
set5ype&'...........................................................--=
setup&'.......................................................-0=, -0A
set"p&'......................................................2?0, 2??
set,isibility&'..............................................29, 9=
shaking#tarte&'...............................................-?-
shaking#toppe&'.............................................-?-
start&'................................................................-0-
startA%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&'...............................................20-
unregisterListener&'.........................................-2A
%$%
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition
Gey)ord +ndex
upate&'............................................................-?A upateAppWiget&'..............................A4, 4-, 4A
%$.
Subscribe to updates at http://commonsware.com Special Creative Commons BY-SA 3.0 License Edition

You might also like