You are on page 1of 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 direct@commonsware.com.
!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 android.database.s@lite.S[*ite2penBelper:
import android.database.s@lite.S[*ite7atabase:
import android.database.s@lite.S[*ite[&er+;&ilder:
import Aava.io.M:
abstract class 7atabaseInstaller extends S[*ite2penBelper 4
abstract void !andleInstallError(<-rowable t):

private Context ctxt#n&ll:

p&blic "atabaseInstaller(Context context> String name>
S[*ite7atabase.C&rsorKactor+ factor+>
int version) 4
s&per(context> name> factor+> version):

t-is.ctxt#context:
?

02verride
p&blic void onCreate(S[*ite7atabase db) 4
tr+ 4
Inp&tStream stream#ctxt
.getResources()
.openRawResource(6.raw.pac.aged/db):
Inp&tStream6eader is#new InputStreamReader(stream):
;&ffered6eader in#new BufferedReader(is):
String str:

w-ile ((str # in.readLine()) N# n&ll) 4
if (Nstr.equals($;8GI= <63=S3C<I2=:$) UU Nstr.equals($C299I<:$)) 4
db.e(ecS0L(str):
?
?

in.close():
?
catc- (I28xception e) 4
!andleInstallError(e):
?
?
?
-$6
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 android.database.s@lite.S[*ite7atabase:
import android.&til.*og:
class ConstantsInstaller extends 7atabaseInstaller 4
p&blic ConstantsInstaller(Context context> String name>
S[*ite7atabase.C&rsorKactor+ factor+>
int version) 4
s&per(context> name> factor+> version):
?

void !andleInstallError(<-rowable t) 4
*og.e($Constants$> $8xception installing database$> t):
?
02verride
p&blic void onUpgrade(S[*ite7atabase db> int oldVersion>
-$-
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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 android.database.s@lite.S[*ite7atabase:
import android.os.;&ndle:
import android.provider.Call*og:
import android.view.View:
import android.view.ViewGro&p:
import android.view.*a+o&tInflater:
import android.widget.C&rsor3dapter:
import android.widget.ImageView:
import android.widget.*istView:
import android.widget.<extView:
import Aava.text.Simple7ateKormat:
p&blic class Join7emo extends *ist3ctivit+ 4
p&blic static String =2<8#$/=2<8$:
private static String =2<8/I7#$=2<8/I7$:
private static StringPQ 562J8C<I2=#new StringPQ 4 Call*og.Calls./I7>
Call*og.Calls.=D9;86>
Call*og.Calls.73<8>
Call*og.Calls.7D63<I2=
?:
private static Simple7ateKormat K2693<#new Simple"ate'ormat($99/d -,mm a$):
private C&rsor c&rsor#n&ll:
private int noteCol&mn#'1:
private int idCol&mn#'1:
private int noteIdCol&mn#'1:
private S[*ite7atabase db#n&ll:

02verride
p&blic void onCreate(;&ndle savedInstanceState) 4
s&per.onCreate(savedInstanceState):

C&rsor c#managed0uery(android.provider.Call*og.Calls.C2=<8=</D6I>
562J8C<I2=> n&ll> n&ll>
Call*og.Calls.73<81$ 78SC$):

c&rsor#new JoinCursor(c> Aoin):
noteCol&mn#c&rsor.getColumnInde((=2<8):
idCol&mn#c&rsor.getColumnInde((Call*og.Calls./I7):
noteIdCol&mn#c&rsor.getColumnInde((=2<8/I7):
-26
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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%e@emo.............................................20A
/utton.............2-, 2?, 2=, =0, A0, A-, A2, 1A, 14, 22
CallLog................................................-A03-A2, -40
%.3
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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%ts@emo....................-=?, -=1, 221, 2?0, 2?-
Conta%ts@emo/ase5est...........................2?2, 2??
Conta%ts@emo5est...........................221, 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>ableQ8raient@emo.................................12
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
+oin@emo....................................-A0, -A1, -A2, -40
Layout.n$later............................................A2, 2??
Linear.nterpolator............................................9A
LinearLayout..............................-A, ?2, A0, 29, 90
Linke/lo%kingFueue.....................................2--
Linke)ashMap...............................................-A1
List.......................................................?A, -92, 222
%.4
Subscribe to updates at http://commonsware.com Special Creative Commons BY-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%h@emo................................................22
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%ture@emo.............................................--2, -20
!o>erManager..........................................-20, -2?
!re$eren%eA%tivity......................................A2, 40
!revie>@emo.............................................--2, --?
!rogress/ar...............................-?, -=, A0, -1?, -14
RelativeLayout..................................................A0
RemoteB;%eption.............................................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................................................-?-
#haker@emo..............................................-29, -?-
#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
#liing!anel@emo.............................................9-
#pinner.......................................-=?, -==, -=4, 2?0
#FLite@atabase................................................-=-
#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-
,ieo@emo......................................................-01
,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