The Busy Coder's Guide To Android Development Version 8.9 Mark L. Murphy 2017

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 4495

DownloadThe Busy Coder's Guide To Android Development Version 8.9 Mark L. Murphy - 2017
Open PDF In BrowserView PDF
The Busy Coder's Guide to Android Development

by Mark L. Murphy

The Busy Coder's Guide to Android Development
by Mark L. Murphy
Copyright © 2008-2017 CommonsWare, LLC. All Rights Reserved.
Printed in the United States of America.
Printing History:
December 2017:

Version 8.9

ISBN: 978-0-9816780-0-9

The CommonsWare name and logo, “Busy Coder's Guide”, and related trade dress are trademarks of CommonsWare,
LLC.
All other trademarks referenced in this book are trademarks of their respective firms.
The publisher and author(s) assume no responsibility for errors or omissions or for damages resulting from the use of the
information contained herein.

Table of Contents
Headings formatted in bold-italic have changed since the last version.
• Preface
◦ Welcome to the Book! ...................................................................... xliii
◦ The Book’s Structure ........................................................................ xliii
◦ The Trails ................................................................................ xliv
◦ About the Updates ................................................................................. l
◦ What’s New in Version 8.9? ......................................................... l
◦ Warescription ........................................................................................ l
◦ About the APK Edition ......................................................................... li
◦ Book Bug Bounty ................................................................................. lii
◦ Source Code and Its License .............................................................. liii
◦ Creative Commons and the Four-to-Free (42F) Guarantee ...... liv
◦ Acknowledgments ............................................................................... liv
• Key Android Concepts
◦ Android Applications ............................................................................ 1
◦ Android Devices .......................................................................... 6
◦ Don’t Be Scared .................................................................................... 10
• Choosing Your Development Toolchain
◦ Android Studio ..................................................................................... 11
◦ Eclipse .................................................................................................... 11
◦ IntelliJ IDEA ............................................................................... 12
◦ Command-Line Builds via Gradle ...................................................... 12
◦ Yet Other Alternatives ......................................................................... 12
◦ IDEs… And This Book ........................................................................... 13
◦ What We Are Not Covering ................................................................. 13
• Tutorial #1 - Installing the Tools
◦ But First, Some Notes About Android’s Emulator ............................. 15
◦ Step #1: Checking Your Hardware ...................................................... 16
◦ Step #2: Setting Up Java and 32-Bit Linux Support ............................ 17
◦ Step #3: Install Android Studio .................................................. 17
◦ Step #4: Install the SDKs and Add-Ons ............................................. 19
◦ In Our Next Episode… ......................................................................... 27
• Android and Projects
◦ Projects and Android Studio ............................................................... 29
◦ Starter Project Generators ................................................................... 35
• Tutorial #2 - Creating a Stub Project
i

•

•

•

•

•

◦ About Our Tutorial Project ................................................................. 37
◦ About the Rest of the Tutorials ........................................................... 38
◦ About Our Tools .................................................................................. 38
◦ Step #1: Importing the Project ............................................................ 38
◦ Step #2: Get Ready for the x86 Emulator ........................................... 42
◦ Step #3: Set Up the AVD ...................................................................... 43
◦ Step #4: Set Up the Device .................................................................. 50
◦ Step #5: Running the Project .............................................................. 55
◦ In Our Next Episode… ......................................................................... 56
Getting Around Android Studio
◦ Navigating The Project Explorer ......................................................... 57
◦ Running Projects ................................................................................ 60
◦ Viewing Output ................................................................................... 61
◦ Accessing Android Tools ..................................................................... 62
◦ Android Studio and Release Channels .............................................. 64
◦ Visit the Trails! ..................................................................................... 65
Contents of Android Projects
◦ What You Get, In General ................................................................... 67
◦ More About the Directory Structure .................................................. 70
◦ What You Get Out Of It ...................................................................... 72
Introducing Gradle and the Manifest
◦ Gradle: The Big Questions .................................................................. 73
◦ Obtaining Gradle ................................................................................. 75
◦ Versions of Gradle and the Android Gradle Plugin .................. 77
◦ Gradle Environment Variables ............................................................ 78
◦ Examining the Gradle Files ...................................................... 78
◦ Introducing the Manifest .................................................................... 81
◦ Things In Common Between the Manifest and Gradle .................... 82
◦ Other Gradle Items of Note ............................................................... 84
◦ Where’s the GUI? ................................................................................. 85
◦ The Rest of the Manifest ..................................................................... 85
◦ Learning More About Gradle ............................................................. 88
◦ Visit the Trails! .................................................................................... 88
Tutorial #3 - Manifest Changes
◦ Some Notes About Relative Paths ..................................................... 89
◦ Step #1: Supporting Screens ............................................................... 89
◦ Step #2: Blocking Backups ................................................................. 90
◦ Step #3: Ignoring Lint ......................................................................... 90
◦ In Our Next Episode… ......................................................................... 92
Some Words About Resources
◦ String Theory ....................................................................................... 93
ii

◦ Got the Picture? .................................................................................. 99
◦ Dimensions ........................................................................................ 103
◦ The Resource That Shall Not Be Named… Yet ................................. 105
• Icons

•

•

•

•

•

•

◦ App Icons… And Everything Else .............................................. 107
◦ Creating an App Icon with the Asset Studio ........................... 108
◦ Creating Other Icons with the Asset Studio ..................................... 113
Tutorial #4 - Adjusting Our Resources
◦ Step #1: Changing the Name .............................................................. 115
◦ Step #2: Changing the Icon ................................................................ 116
◦ Step #3: Running the Result .............................................................. 120
◦ In Our Next Episode… ........................................................................ 121
The Theory of Widgets
◦ What Are Widgets? ............................................................................ 123
◦ Size, Margins, and Padding ................................................................ 125
◦ What Are Containers? ........................................................................ 125
◦ The Absolute Positioning Anti-Pattern ............................................ 126
◦ The Theme of This Section: Themes ................................................. 127
The Android User Interface
◦ The Activity ......................................................................................... 131
◦ Dissecting the Activity ....................................................................... 132
◦ Using XML-Based Layouts ....................................................... 133
Basic Widgets
◦ Common Concepts ................................................................... 137
◦ Introducing the Graphical Layout Editor ........................................ 140
◦ And Now, Some Notes About the Book’s Sample Projects ....... 149
◦ Assigning Labels ................................................................................ 150
◦ A Commanding Button ...................................................................... 155
◦ Fleeting Images .................................................................................. 158
◦ Fields of Green. Or Other Colors. ............................................ 164
◦ More Common Concepts ......................................................... 167
◦ Visit the Trails! ................................................................................... 170
Debugging Your App
◦ Get Thee To a Stack Trace .................................................................. 172
◦ The Case of the Confounding Class Cast .......................................... 173
◦ Point Break .......................................................................................... 174
The Classic Container Classes
◦ Introducing the Sampler App ............................................................ 175
◦ RTL and Your Layouts ....................................................................... 176
◦ LinearLayout and the Box Model ............................................ 177
◦ All Things Are Relative ............................................................ 201
iii

•

•

•

•

•

•

◦ Tabula Rasa ......................................................................................... 212
◦ Hey, What About ConstraintLayout? ............................................... 218
◦ Turning Back to RTL .......................................................................... 219
Other Common Widgets and Containers
◦ Just a Box to Check .................................................................. 221
◦ Don’t Like Checkboxes? How About Toggles or Switches? ............ 224
◦ Turn the Radio Up ............................................................................. 228
◦ Scrollwork ............................................................................................ 231
◦ Making Progress with ProgressBars ....................................... 234
◦ Framing the Scene ............................................................................. 235
◦ Visit the Trails! ................................................................................... 236
Tutorial #5 - Creating a Layout
◦ Step #1: Creating a New Layout Resource ........................................ 237
◦ Step #2: Defining the UI .................................................................... 238
◦ In Our Next Episode… ....................................................................... 243
GUI Building, Continued
◦ Making Your Selection ...................................................................... 245
◦ Including Includes .................................................................. 246
◦ Preview of Coming Attractions ......................................................... 248
AdapterViews and Adapters
◦ Adapting to the Circumstances ........................................................ 249
◦ Lists of Naughty and Nice ........................................................ 251
◦ Clicks versus Selections ........................................................... 253
◦ Spin Control ............................................................................. 257
◦ Grid Your Lions (Or Something Like That…) .......................... 260
◦ Fields: Now With 35% Less Typing! ......................................... 264
◦ Customizing the Adapter ................................................................. 268
◦ Visit the Trails! ................................................................................... 277
The WebView Widget
◦ Role of WebView ............................................................................... 279
◦ Daddy, Where Do WebViews Come From? .................................... 280
◦ Adding the Widget ........................................................................... 280
◦ Loading Content Via a URL ..................................................... 281
◦ Links and Redirects ........................................................................... 283
◦ Supporting JavaScript ........................................................................ 283
◦ Alternatives for Loading Content ..................................................... 284
◦ Listening for Events ........................................................................... 285
◦ Addressing the Link/Redirect Behavior ................................. 288
◦ Visit the Trails! .................................................................................. 290
Defining and Using Styles
◦ Styles: DIY DRY .................................................................................. 291
iv

•

•

•

•

•

◦ Elements of Style ............................................................................... 293
◦ Themes: Would a Style By Any Other Name… ............................... 296
◦ What Happens If You Have No Theme ............................................ 297
◦ Android Studio’s Theme Editor ........................................................ 297
Dependencies
◦ What’s a Dependency? ...................................................................... 303
◦ Dependency Scopes ........................................................................... 304
◦ Depending on a Local JAR ................................................................ 305
◦ What’s an Artifact? ............................................................................ 306
◦ Artifacts and Repositories ................................................................. 306
◦ Major Library Families from Google ................................................ 306
◦ Requesting Dependencies ...................................................... 307
◦ The Android Support Library .................................................. 310
Tutorial #6 - Adding a Library
◦ Step #1: Getting Rid of Existing Cruft ................................................ 315
◦ Step #2: Requesting New Dependencies .......................................... 316
◦ In Our Next Episode… ....................................................................... 318
Introducing ConstraintLayout
◦ Why Another Container? ......................................................... 319
◦ Comparing with the Classics ............................................................. 321
◦ Getting ConstraintLayout .................................................................. 321
◦ Using Widgets and Containers from Libraries ................................ 323
◦ Using a ConstraintLayout ................................................................. 323
◦ Converting Existing Layouts ............................................................. 339
◦ Visit the Trails! ................................................................................... 341
The Action Bar
◦ Bar Hopping ............................................................................. 343
◦ Yet Another History Lesson .............................................................. 349
◦ Your Action Bar Options ................................................................... 350
◦ Setting the Target .............................................................................. 352
◦ Defining the Resource ....................................................................... 353
◦ Applying the Resource ...................................................................... 356
◦ Responding to Events ........................................................................ 356
◦ The Rest of the Sample Activity ....................................................... 357
◦ MENU Key, We Hardly Knew Ye ...................................................... 363
◦ Action Bars, Live in Living Color! ........................................... 364
◦ Visit the Trails! ................................................................................... 374
Vector Drawables
◦ Getting the Artwork .......................................................................... 375
◦ VectorDrawableCompat .................................................................... 380
◦ Other VectorDrawable Backports ..................................................... 388
v

• Tutorial #7 - Setting Up the Action Bar
◦ Step #1: Adding Some Icons .............................................................. 389
◦ Step #2: Defining Some Options ...................................................... 391
◦ Step #3: Loading and Responding to Our Options ......................... 394
◦ Step #4: Supporting Older Devices .................................................. 395
◦ Step #5: Trying It Out ........................................................................ 396
◦ In Our Next Episode… ....................................................................... 398
• Android’s Process Model
◦ When Processes Are Created ............................................................ 399
◦ BACK, HOME, and Your Process ..................................................... 400
◦ Termination ........................................................................................ 401
◦ Foreground Means “I Love You” ....................................................... 402
◦ You and Your Heap ............................................................................ 402
• Activities and Their Lifecycles
◦ Creating Your Second (and Third and…) Activity .......................... 404
◦ Warning! Contains Explicit Intents! ................................................ 408
◦ Using Implicit Intents ............................................................ 410
◦ Extra! Extra! ........................................................................................ 416
◦ Pondering Parcelable ......................................................................... 417
◦ Asynchronicity and Results .............................................................. 419
◦ Schroedinger’s Activity ...................................................................... 419
◦ Life, Death, and Your Activity ................................................ 420
◦ When Activities Die .......................................................................... 422
◦ Walking Through the Lifecycle ........................................................ 423
◦ Recycling Activities ........................................................................... 426
◦ Application: Transcending the Activity ........................................... 427
◦ The Case of the Invisible Activity ..................................................... 428
• Tutorial #8 - Setting Up An Activity
◦ Step #1: Creating the Stub Activity Class and Manifest Entry ........ 431
◦ Step #2: Launching Our Activity ...................................................... 433
◦ In Our Next Episode… ....................................................................... 434
• The Tactics of Fragments
◦ The Six Questions .............................................................................. 435
◦ Where You Get Your Fragments From ............................................. 438
◦ Your First Fragment ........................................................................... 438
◦ The Fragment Lifecycle Methods ..................................................... 442
◦ Your First Dynamic Fragment ........................................................... 443
◦ Fragments and the Action Bar ......................................................... 446
◦ Fragments Within Fragments: Just Say “Maybe” ............................ 448
◦ Fragments and Multiple Activities .................................................. 448
• Tutorial #9 - Starting Our Fragments
vi

•

•

•

•
•

•

◦ Step #1: Create a SimpleContentFragment ...................................... 451
◦ Step #2: Examining SimpleContentFragment ................................. 453
◦ In Our Next Episode… ....................................................................... 454
Swiping with ViewPager
◦ Pieces of a Pager ................................................................................. 455
◦ Paging Fragments .............................................................................. 456
◦ Paging Other Stuff ............................................................................. 461
◦ Indicators ........................................................................................... 462
◦ Revisiting the Containers Sampler ................................................... 465
Tutorial #10 - Rigging Up a ViewPager
◦ Step #1: Add a ViewPager to the Layout ........................................... 473
◦ Step #2: Creating a ContentsAdapter ............................................... 474
◦ Step #3: Setting Up the ViewPager ................................................... 475
◦ In Our Next Episode… ....................................................................... 478
Resource Sets and Configurations
◦ What’s a Configuration? And How Do They Change? .................... 479
◦ Configurations and Resource Sets ................................................... 480
◦ Screen Size and Orientation ............................................................. 481
◦ Coping with Complexity .................................................................. 484
◦ Choosing The Right Resource ........................................................... 485
◦ API-Versioned Resources ................................................................. 489
◦ Default Change Behavior .................................................................. 491
◦ State Saving Scenarios ....................................................................... 493
◦ Your Options for Configuration Changes ....................................... 494
◦ Blocking Rotations ............................................................................ 508
◦ And Now, a Word From the Android Project View ........................ 509
◦ Configuration Challenges .................................................................. 510
Material Design Basics
◦ Your App, in Technicolor! .................................................................. 515
Dealing with Threads
◦ The Main Application Thread ........................................................... 521
◦ Getting to the Background ................................................................ 523
◦ Asyncing Feeling ................................................................................ 523
◦ Alternatives to AsyncTask ................................................................. 532
◦ And Now, The Caveats ....................................................................... 534
◦ Event Buses ........................................................................................ 535
◦ Visit the Trails! ................................................................................... 543
Requesting Permissions
◦ Frequently-Asked Questions About Permissions ........................... 546
◦ Characteristics of Permissions ........................................................... 551
◦ New Permissions in Old Applications .............................................. 554
vii

•

•

•

•

◦ Android 6.0+ Runtime Permission System ...................................... 555
◦ A Simple Runtime Permission Abstraction ..................................... 567
Assets, Files, and Data Parsing
◦ Packaging Files with Your App .......................................................... 571
◦ Files and Android .............................................................................. 573
◦ Working with Internal Storage ......................................................... 574
◦ Working with External Storage ......................................................... 583
◦ Removable Storage ........................................................................... 590
◦ Multiple User Accounts ..................................................................... 591
◦ Linux Filesystems: You Sync, You Win ............................................. 591
◦ StrictMode: Avoiding Janky Code ..................................................... 593
◦ Files, and Your Development Machine ............................................ 595
◦ XML Parsing Options ........................................................................ 603
◦ JSON Parsing Options ...................................................................... 604
◦ Using Files with Implicit Intents ..................................................... 604
◦ Visit the Trails! ................................................................................... 605
Tutorial #11 - Adding Simple Content
◦ Step #1: Adding Some Content ........................................................ 607
◦ Step #2: Using SimpleContentFragment ......................................... 608
◦ Step #3: Launching Our Activities, For Real This Time ................. 609
◦ Step #4: Getting a Bit More Material ................................................ 610
◦ Step #5: Seeing the Results ............................................................... 612
◦ In Our Next Episode… ....................................................................... 614
Tutorial #12 - Displaying the Book
◦ Step #1: Adding a Book ...................................................................... 615
◦ Step #2: Creating a ModelFragment ................................................. 616
◦ Step #3: Defining Our Model ............................................................ 617
◦ Step #4: Examining Our Model ........................................................ 619
◦ Step #5: Defining Our Event ............................................................. 619
◦ Step #6: Loading Our Model ............................................................ 620
◦ Step #7: Registering for Events ......................................................... 623
◦ Step #8: Adapting the Content ......................................................... 624
◦ Step #9: Showing the Content When Loaded ................................. 625
◦ Step #10: Attaching our ModelFragment ......................................... 626
◦ Step #11: Showing the Content After a Configuration Change ....... 627
◦ Step #12: Setting Up StrictMode ....................................................... 628
◦ In Our Next Episode… ....................................................................... 629
Using Preferences
◦ Getting What You Want .................................................................... 631
◦ Stating Your Preference ..................................................................... 632
◦ Collecting Preferences with PreferenceFragment ........................... 633
viii

•

•

•

•

◦ Android Studio’s Preferences Editor ............................................... 640
◦ Types of Preferences .......................................................................... 641
Tutorial #13 - Using Some Preferences
◦ Step #1: Defining the Preference XML Files ..................................... 647
◦ Step #2: Creating Our Preference Activity ....................................... 651
◦ Step #3: Adding To Our Action Bar .................................................. 652
◦ Step #4: Launching the Preference Activity .................................... 652
◦ Step #5: Loading the Preferences ..................................................... 655
◦ Step #6: Saving the Last-Read Position ........................................... 659
◦ Step #7: Restoring the Last-Read Position ...................................... 660
◦ Step #8: Keeping the Screen On ....................................................... 661
◦ In Our Next Episode… ....................................................................... 663
SQLite Databases
◦ Introducing SQLite ........................................................................... 665
◦ Thinking About Schemas ................................................................. 666
◦ Start with a Helper ........................................................................... 666
◦ Getting Data Out ............................................................................... 671
◦ The Rest of the CRUD ....................................................................... 678
◦ Hey, What About Hibernate? .......................................................... 684
◦ But, What About Room? .................................................................. 684
◦ Visit the Trails! .................................................................................. 684
Tutorial #14 - Saving Notes
◦ Step #1: Adding a DatabaseHelper .................................................. 687
◦ Step #2: Examining DatabaseHelper ............................................... 688
◦ Step #3: Creating a NoteFragment .................................................. 689
◦ Step #4: Examining NoteFragment ................................................. 690
◦ Step #5: Creating the NoteActivity .................................................. 690
◦ Step #6: Examining NoteActivity ..................................................... 691
◦ Step #7: Add Notes to the Action Bar ............................................. 692
◦ Step #8: Defining a NoteLoadedEvent ............................................ 694
◦ Step #9: Loading a Note from the Database ................................... 695
◦ Step #10: Loading the Note Into the Fragment .............................. 696
◦ Step #11: Updating the Database ...................................................... 697
◦ Step #12: Saving the Note ................................................................. 698
◦ Step #13: Adding a Delete Action Bar Item ...................................... 700
◦ Step #14: Closing the NoteFragment When Deleted ....................... 703
◦ In Our Next Episode… ....................................................................... 708
Internet Access
◦ DIY HTTP .......................................................................................... 709
◦ What About HttpClient? ................................................................... 719
◦ HTTP via DownloadManager ........................................................... 722
ix

•

•

•

•

•

◦ Using Third-Party JARs ..................................................................... 722
◦ SSL ...................................................................................................... 723
◦ Using HTTP Client Libraries .................................................... 723
◦ Visit the Trails .................................................................................... 749
Intents, Intent Filters
◦ What’s Your Intent? ............................................................................ 751
◦ Stating Your Intent(ions) .................................................................. 753
◦ Responding to Implicit Intents ......................................................... 753
◦ Requesting Implicit Intents .............................................................. 756
◦ ShareActionProvider .............................................................. 760
◦ Practice Safe Content Resolution ..................................................... 763
Broadcasts and Broadcast Receivers
◦ The Stopped State .............................................................................. 767
◦ Example System Broadcasts ............................................................. 768
◦ The Order of Things .......................................................................... 777
◦ Keeping It Local ................................................................................. 778
◦ Visit the Trails! ................................................................................... 778
Tutorial #15 - Sharing Your Notes
◦ Step #1: Adding a ShareActionProvider ........................................... 779
◦ Step #2: Sharing the Note ................................................................. 780
◦ Step #3: Testing the Result ................................................................ 782
◦ In Our Next Episode… ....................................................................... 785
Services and the Command Pattern
◦ Why Services? .................................................................................... 787
◦ Setting Up a Service ........................................................................... 788
◦ Communicating To Services ............................................................ 790
◦ Scenario: The Music Player ............................................................... 792
◦ Communicating From Services ........................................................ 796
◦ Scenario: The Downloader ................................................................ 798
◦ Services and Configuration Changes ............................................... 804
Tutorial #16 - Updating the Book
◦ Step #1: Adding a Stub DownloadCheckService ............................. 807
◦ Step #2: Tying the Service Into the Action Bar ............................... 808
◦ Step #3: Defining Our Event ............................................................. 810
◦ Step #4: Defining Our JSON ............................................................. 810
◦ Step #5: Defining Our Retrofit Interface ........................................... 811
◦ Step #6: Retrieving Our JSON Via Retrofit ...................................... 812
◦ Step #7: Downloading the Update .................................................... 814
◦ Step #8: Unpacking the Update ........................................................ 815
◦ Step #9: Using the Update ................................................................ 819
◦ In Our Next Episode… ....................................................................... 824
x

• Large-Screen Strategies and Tactics
◦ Objective: Maximum Gain, Minimum Pain ..................................... 825
◦ The Fragment Strategy ...................................................................... 825
◦ Fragment Example: The List-and-Detail Pattern ............................ 834
◦ Other Master-Detail Strategies ........................................................ 848
◦ Showing More Pages .......................................................................... 861
◦ Fragment FAQs ................................................................................. 867
◦ Screen Size and Density Tactics ...................................................... 868
◦ Other Considerations ........................................................................ 871
• Tutorial #17 - Supporting Large Screens
◦ Step #1: Creating Our Layouts .......................................................... 875
◦ Step #2: Loading Our Sidebar Widgets ............................................ 879
◦ Step #3: Opening the Sidebar .......................................................... 880
◦ Step #4: Loading Content Into the Sidebar ..................................... 881
◦ Step #5: Removing Content From the Sidebar ............................... 884
• Backwards Compatibility Strategies and Tactics
◦ Think Forwards, Not Backwards ...................................................... 891
◦ Aim Where You Are Going ............................................................... 893
◦ A Target-Rich Environment .............................................................. 893
◦ Lint: It’s Not Just For Belly Buttons ................................................. 894
◦ A Little Help From Your Friends ..................................................... 895
◦ Avoid the New on the Old ............................................................... 895
◦ Testing ............................................................................................... 899
◦ Keeping Track of Changes ................................................................ 899
• System Services
◦ What is a System Service? ................................................................. 901
◦ What System Services Are There? ................................................... 902
• Google Play Services
◦ What Is Google Play Services? ......................................................... 905
◦ What Is In the Play Services SDK? .................................................. 906
◦ Adding Play Services to Your Project ............................................... 913
• Getting Help
◦ Questions. Sometimes, With Answers. ................................... 923
◦ Heading to the Source ....................................................................... 924
• Working with Library Modules
◦ Prerequisites ....................................................................................... 927
◦ Creating a Library Module ................................................................ 927
◦ Using a Library Module ..................................................................... 930
◦ Library Modules and the Manifest ................................................... 930
◦ Library Modules and Transitive Dependencies ....................... 931
◦ Limitations of Library Modules ........................................................ 932
xi

• Gradle and Tasks
◦ Key Build-Related Tasks .................................................................... 933
◦ Results ................................................................................................ 936
• Gradle Build Variants
◦ Prerequisites ....................................................................................... 937
◦ Objectives of the Project Structure .................................................. 937
◦ Terminology ....................................................................................... 938
◦ Configuring the Stock Build Types ................................................... 941
◦ Adding Build Types ........................................................................... 945
◦ Adding Product Flavors and Getting Build Variants ....................... 945
◦ Doing the Splits ................................................................................. 947
◦ Gradle and Android Studio ..................................................... 949
• Manifest Merger Rules
◦ Prerequisites ....................................................................................... 951
◦ Manifest Scenarios ............................................................................. 951
◦ Pieces of Manifest Generation .......................................................... 953
◦ Examining the Merger Results .......................................................... 955
◦ Viewing Merged Manifests in Android Studio ................................ 955
◦ Merging Elements and Attributes ................................................... 956
◦ Employing Placeholders ................................................................... 966
• Signing Your App
◦ Prerequisites ....................................................................................... 971
◦ Role of Code Signing ......................................................................... 971
◦ What Happens In Debug Mode ........................................................ 972
◦ Production Signing Keys ................................................................... 973
• Distribution
◦ Prerequisites ....................................................................................... 981
◦ Get Ready To Go To Market .............................................................. 981
• Writing a Gradle Plugin
◦ Prerequisites ...................................................................................... 987
◦ Customizing a Gradle Build ............................................................. 987
◦ Some Use Cases for a Custom Plugin .............................................. 988
◦ Writing a Plugin ............................................................................... 989
◦ Distributing the Plugin .................................................................... 996
◦ Using the Plugin ............................................................................... 998
◦ Creating a Real Plugin ..................................................................... 1002
• Code Generation
◦ Prerequisites ..................................................................................... 1007
◦ What Drives the Custom Code? ..................................................... 1007
◦ Java as Poetry ................................................................................... 1009
◦ Writing a Code Generation Plugin .................................................. 1010
xii

•

•

•

•

•

•

◦ Using the Generated Code ............................................................... 1021
Advanced Gradle for Android Tips
◦ Prerequisites ...................................................................................... 1023
◦ Gradle, DRY ....................................................................................... 1023
◦ Automating APK Version Information ........................................... 1026
◦ Adding to BuildConfig ..................................................................... 1028
Testing with JUnit4
◦ Prerequisites ...................................................................................... 1033
◦ Instrumentation Tests and Unit Tests ............................................. 1033
◦ Writing JUnit4 Test Cases ................................................................ 1035
◦ Configuring Gradle ........................................................................... 1041
◦ Running Your Instrumentation Tests ............................................. 1042
◦ Testing Android Library Projects .................................................... 1047
◦ Testing and Runtime Permissions .................................................. 1047
◦ The Android Test Orchestrator ............................................. 1048
Testing with Espresso
◦ Prerequisites ...................................................................................... 1053
◦ Adding a Shot of Espresso ............................................................... 1054
◦ Writing Tests in Espresso ................................................................ 1056
◦ The Espresso Test Recorder ............................................................ 1062
◦ Stronger Espresso ............................................................................ 1067
◦ Opting Out of Analytics ................................................................... 1081
◦ Waiting for the World to Change ................................................... 1082
Testing with UI Automator
◦ Prerequisites ..................................................................................... 1089
◦ What Is UI Automator? ................................................................... 1089
◦ Why Choose UI Automator Over Alternatives? ............................ 1090
◦ Gradle and Android Studio Settings .............................................. 1090
◦ Creating a Test Case ......................................................................... 1091
◦ Running Your Tests .......................................................................... 1099
◦ Finding Your Widgets ...................................................................... 1099
◦ Using the UI Automator Viewer ...................................................... 1100
Measuring Test Coverage
◦ Prerequisites ...................................................................................... 1103
◦ Who Tests the Testers? ..................................................................... 1103
◦ Some Types of Test Coverage ........................................................... 1104
◦ Coverage and Your Instrumentation Tests ...................................... 1106
Unit Testing
◦ Prerequisites ........................................................................................ 1111
◦ I Thought We Were Already Unit Testing? ...................................... 1112
◦ Scenario: Clean Architecture ............................................................ 1112
xiii

•

•

•

•

•

◦ Setting Up Unit Testing ..................................................................... 1113
◦ Writing POJO Unit Tests .................................................................. 1116
◦ Running Unit Tests ........................................................................... 1120
◦ Mocking Android .............................................................................. 1125
MonkeyRunner and the Test Monkey
◦ Prerequisites ...................................................................................... 1147
◦ MonkeyRunner ................................................................................. 1147
◦ Monkeying Around ........................................................................... 1149
Java 8 Lambda Expressions
◦ Prerequisites ...................................................................................... 1155
◦ The Basic Idea ................................................................................... 1156
◦ Using Lambda Expressions .............................................................. 1157
◦ Alternative: Method References ....................................................... 1161
Rx Basics
◦ Prerequisites ...................................................................................... 1163
◦ Life is But a Stream ........................................................................... 1163
◦ Action and Reaction ......................................................................... 1165
◦ A Rx For What Ails You .................................................................... 1166
◦ Rx and Lambdas ............................................................................... 1167
◦ A Simple Stream .................................................................... 1167
◦ Be Your Own Stream ........................................................................ 1169
◦ Removing the AsyncTask .................................................................. 1171
◦ Lambdas and Lifetimes .................................................................... 1177
◦ Streaming from a Resource .............................................................. 1178
◦ Error Handling .................................................................................. 1179
◦ Transmogrification ........................................................................... 1180
◦ Rx-Enabled Libraries ......................................................................... 1181
◦ Further Reading ................................................................................ 1183
◦ What About LiveData? ..................................................................... 1183
Notifications
◦ Prerequisites ...................................................................................... 1187
◦ What’s a Notification? ............................................................ 1187
◦ Notifications and Channels ................................................... 1190
◦ Showing a Simple Notification .............................................. 1190
◦ The Activity-Or-Notification Scenario ............................................ 1196
◦ Big (and Rich) Notifications ................................................... 1197
◦ Foreground Services .............................................................. 1204
◦ Disabled Notifications ........................................................... 1207
Advanced Notifications
◦ Prerequisites ....................................................................................... 1211
◦ Being a Good Citizen ......................................................................... 1211
xiv

◦ More About Channels ............................................................. 1212
◦ Wear? There! ..................................................................................... 1219
◦ Stacking Notifications ........................................................... 1224
◦ Avoiding Wear ........................................................................ 1230
◦ Other Wear-Specific Notification Options ............................. 1231
◦ Remote Input, On-Device ................................................................ 1245
◦ Notification Groups .......................................................................... 1250
◦ Lockscreen Notifications .................................................................. 1252
◦ Priority, Importance, and Heads-Up Notifications ............... 1261
◦ Full-Screen Notifications ....................................................... 1264
◦ Progress Notifications ..................................................................... 1266
◦ Custom Views ........................................................................ 1275
◦ Life After Delete ................................................................................ 1278
◦ The Mysterious Case of the Missing Number ........................ 1279
◦ Notifications and MessagingStyle ......................................... 1279
◦ Changes in API Level 23 .................................................................. 1284
◦ Sounds and Android 7.0 ................................................................... 1285
◦ Auto-Timeout ........................................................................ 1286
◦ Colorized Notifications ......................................................... 1287
• Multi-Window Support
◦ Prerequisites ...................................................................................... 1291
◦ A History of Windows ...................................................................... 1291
◦ What The User Sees ........................................................................ 1292
◦ What Your Code Sees ...................................................................... 1294
◦ Opting Out ....................................................................................... 1296
◦ Opting In .......................................................................................... 1296
◦ Configuring the Layout ................................................................... 1297
◦ Avoiding Stutter ............................................................................... 1299
◦ Managing the Background .............................................................. 1300
◦ How Low Can You Go? .................................................................... 1300
◦ Parallel Processing ............................................................................ 1301
◦ Split-Screen, HOME, and Your Activity .......................................... 1303
◦ Split-Screen and Orientations ........................................................ 1304
◦ Forcing Your App Into Multi-Window/Multi-Instance ................ 1304
◦ Supporting Legacy Proprietary Multi-Window .............................. 1312
◦ Freeform Multi-Window Mode ........................................................ 1315
◦ Picture-in-Picture .................................................................. 1322
◦ Multi-Display Support ........................................................... 1326
• Advanced ConstraintLayout
◦ Prerequisites ...................................................................................... 1335
◦ Disclosing Your Bias ......................................................................... 1335
xv

•

•

•

•

•

•

◦ Centering Yourself ............................................................................ 1341
◦ Keeping Things Proportional ........................................................... 1345
◦ Constraining the ConstraintLayout Size ........................................ 1346
◦ Chains, Without the Whips ............................................................. 1347
◦ What If We’re GONE? ....................................................................... 1351
GridLayout
◦ Prerequisites ...................................................................................... 1353
◦ Issues with the Classic Containers .................................................. 1353
◦ The New Contender: GridLayout .................................................... 1355
◦ GridLayout and the Android Support Package .............................. 1355
◦ Our Test App ..................................................................................... 1356
◦ Replacing the Classics ...................................................................... 1359
◦ Implicit Rows and Columns ............................................................. 1365
◦ Row and Column Spans .................................................................. 1366
Dialogs and DialogFragments
◦ Prerequisites ...................................................................................... 1373
◦ DatePickerDialog and TimePickerDialog ....................................... 1373
◦ AlertDialog ........................................................................................ 1379
◦ DialogFragments .............................................................................. 1380
◦ DialogFragment: The Other Flavor ................................................. 1385
◦ Dialogs: Modal, Not Blocking .......................................................... 1385
Advanced ListViews
◦ Prerequisites ...................................................................................... 1387
◦ Multiple Row Types, and Self Inflation ........................................... 1387
◦ Choice Modes and the Activated Style ........................................... 1394
◦ Custom Mutable Row Contents ............................................. 1395
◦ From Head To Toe ................................................................. 1400
◦ Enter RecyclerView .......................................................................... 1404
Action Modes
◦ Prerequisites ..................................................................................... 1406
◦ A Matter of Context ......................................................................... 1406
◦ Manual Action Modes ..................................................................... 1407
◦ Multiple-Choice-Modal Action Modes .................................... 1412
◦ Long-Click To Initiate an Action Mode .......................................... 1416
Other Advanced Action Bar Techniques
◦ Prerequisites ...................................................................................... 1423
◦ Action Layouts .................................................................................. 1423
◦ Action Views and Action Providers ................................................ 1424
◦ Searching with SearchView .............................................................. 1425
◦ Floating Action Bars ............................................................... 1431
Toolbar
xvi

•

•

•

•

◦ Prerequisites ...................................................................................... 1435
◦ Basic Toolbar Mechanics .................................................................. 1435
◦ Use Case #1: Split Action Bar ................................................. 1436
◦ Use Case #2: Contextual Actions .................................................... 1442
◦ Use Case #3: Replacement Action Bar ................................... 1452
AppCompat: The Official Action Bar Backport
◦ Prerequisites ...................................................................................... 1455
◦ Ummmm… Why? .............................................................................. 1455
◦ The Basics of Using AppCompat ............................................ 1458
◦ Other AppCompat Effects ...................................................... 1465
◦ Toolbar and AppCompat ......................................................... 1471
◦ To Material, or Not to Material ........................................................ 1475
The Android Design Support Library
◦ Prerequisites ..................................................................................... 1478
◦ GUIs and the Support Package ....................................................... 1478
◦ Adding the Library… and What Comes With It ............................ 1479
◦ Introducing CWAC-CrossPort ........................................................ 1479
◦ Snackbars: Sweeter than Toasts ...................................................... 1480
◦ Absolutely FABulous ....................................................................... 1488
◦ Material Tabs with TabLayout ........................................................ 1506
◦ Floating Labels ....................................................................... 1518
Implementing a Navigation Drawer
◦ Prerequisites ...................................................................................... 1529
◦ What is a Navigation Drawer? ......................................................... 1529
◦ A Simple Navigation Drawer ............................................................ 1531
◦ Alternative Row Layouts .................................................................. 1537
◦ Additional Considerations ............................................................... 1539
◦ What Should Not Be in the Drawer ............................................... 1548
◦ Independent Implementations ....................................................... 1549
RecyclerView
◦ Prerequisites ...................................................................................... 1552
◦ AdapterView and its Discontents .................................................... 1552
◦ Enter RecyclerView ........................................................................... 1552
◦ A Trivial List ............................................................................ 1553
◦ Divider Options ................................................................................ 1561
◦ Handling Click Events ..................................................................... 1569
◦ What About Cursors? ............................................................. 1576
◦ Grids ....................................................................................... 1583
◦ Varying the Items .............................................................................. 1587
◦ Mutable Row Contents ......................................................... 1600
◦ Changing the Contents ................................................................... 1628
xvii

•

•

•

•

•

◦ The Order of Things ........................................................................ 1634
◦ Other Bits of Goodness ................................................................... 1642
◦ Animating the Deltas Using DiffUtil .............................................. 1643
◦ The March of the Libraries .................................................... 1651
Advanced RecyclerView
◦ Prerequisites ..................................................................................... 1659
◦ RecyclerView as Pager ..................................................................... 1659
◦ Declaring a LayoutManager in the Layout .................................... 1682
◦ Transcript Mode ............................................................................... 1682
Advanced Uses of WebView
◦ Prerequisites ..................................................................................... 1687
◦ Friends with Benefits ....................................................................... 1687
◦ Navigating the Waters ...................................................................... 1702
◦ Settings, Preferences, and Options (Oh, My!) ................................ 1702
◦ Security and Your WebView ............................................................ 1703
◦ Android 8.0 WebView Changes .............................................. 1706
◦ Chrome Custom Tabs ............................................................. 1709
◦ Prerequisites ....................................................................................... 1711
◦ Keyboards, Hard and Soft ................................................................. 1711
◦ Tailored To Your Needs .................................................................... 1712
◦ Tell Android Where It Can Go ......................................................... 1717
◦ Fitting In ............................................................................................ 1719
◦ Jane, Stop This Crazy Thing! ............................................................ 1722
Fonts and Text
◦ Prerequisites ...................................................................................... 1723
◦ Love The One You’re With ............................................................... 1723
◦ Yeah, But Do We Really Have To Do This in Java? ......................... 1727
◦ Here a Glyph, There a Glyph ........................................................... 1728
◦ Auto-Sizing TextView ............................................................. 1729
◦ Justified Text .......................................................................... 1734
Rich Text
◦ Prerequisites ...................................................................................... 1735
◦ The Span Concept ............................................................................. 1735
◦ Loading Rich Text ............................................................................. 1737
◦ Editing Rich Text .............................................................................. 1740
◦ Saving Rich Text ................................................................................ 1745
◦ Manipulating Rich Text .................................................................... 1745
Animators
◦ Prerequisites ...................................................................................... 1747
◦ ViewPropertyAnimator .................................................................... 1747
◦ The Foundation: Value and Object Animators .............................. 1752
xviii

◦ Animating Custom Types ................................................................. 1755
◦ Hardware Acceleration ..................................................................... 1756
◦ The Three-Fragment Problem ......................................................... 1757
• Legacy Animations
◦ Prerequisites ..................................................................................... 1769
◦ It’s Not Just For Toons Anymore ..................................................... 1769
◦ A Quirky Translation ........................................................................ 1770
◦ Fading To Black. Or Some Other Color. .......................................... 1774
◦ When It’s All Said And Done .......................................................... 1776
◦ Loose Fill ........................................................................................... 1777
◦ Hit The Accelerator .......................................................................... 1778
◦ Animate. Set. Match. ........................................................................ 1778
◦ Active Animations ........................................................................... 1780
• Custom Drawables
◦ Prerequisites ...................................................................................... 1781
◦ Where Do These Things Go? ........................................................... 1782
◦ ColorDrawable .................................................................................. 1783
◦ AnimationDrawable ......................................................................... 1783
◦ StateListDrawable ............................................................................. 1787
◦ ColorStateList .................................................................................. 1788
◦ LayerDrawable ................................................................................. 1790
◦ TransitionDrawable .......................................................................... 1791
◦ LevelListDrawable ............................................................................ 1792
◦ ScaleDrawable and ClipDrawable ................................................... 1794
◦ InsetDrawable .................................................................................. 1803
◦ ShapeDrawable ................................................................................ 1804
◦ BitmapDrawable ............................................................................... 1815
◦ Composite Drawables ....................................................................... 1822
◦ A Stitch In Time Saves Nine ........................................................... 1826
• Mapping with Maps V2
◦ Prerequisites ...................................................................................... 1837
◦ A Brief History of Mapping on Android ........................................ 1838
◦ Where You Can Use Maps V2 .................................................. 1838
◦ Licensing Terms for Maps V2 .......................................................... 1839
◦ What You Need to Start ......................................................... 1839
◦ The Book Samples… And You! ................................................ 1842
◦ Setting Up a Basic Map .......................................................... 1842
◦ Playing with the Map ...................................................................... 1847
◦ Map Tiles .......................................................................................... 1850
◦ Placing Simple Markers ................................................................... 1850
◦ Seeing All the Markers .................................................................... 1854
xix

◦ Flattening and Rotating Markers .................................................... 1856
◦ Sprucing Up Your “Info Windows” ................................................. 1860
◦ Images and Your Info Window ....................................................... 1865
◦ Setting the Marker Icon .................................................................. 1872
◦ Responding to Taps .......................................................................... 1874
◦ Dragging Markers ............................................................................. 1875
◦ The “Final” Limitations ................................................................... 1878
◦ A Bit More About IPC ............................................................. 1881
◦ Finding the User ............................................................................... 1881
◦ Dealing with Runtime Permissions ................................................ 1886
◦ Drawing Lines and Areas ................................................................ 1889
◦ Gestures and Controls ..................................................................... 1892
◦ Tracking Camera Changes .............................................................. 1893
◦ Maps in Fragments and Pagers ....................................................... 1896
◦ Animating Marker Movement ........................................................ 1902
◦ Maps, of the Indoor Variety ............................................................ 1908
◦ Taking a Snapshot of a Map ............................................................ 1909
◦ MapFragment vs. MapView ............................................................. 1910
◦ About That AbstractMapActivity Class… ........................................ 1910
◦ Helper Libraries for Maps V2 ........................................................... 1914
◦ Problems with Maps V2 at Runtime ............................................... 1918
◦ Problems with Maps V2 Deployment ............................................. 1918
◦ What Non-Compliant Devices Show .............................................. 1918
◦ Mapping Alternatives ....................................................................... 1919
• Crafting Your Own Views
◦ Prerequisites ...................................................................................... 1921
◦ Pick Your Poison ............................................................................... 1921
◦ Colors, Mixed How You Like Them ........................................ 1922
◦ ReverseChronometer: Simply a Custom Subclass .......................... 1933
◦ AspectLockedFrameLayout: A Custom Container ........................ 1939
◦ Mirror and MirroringFrameLayout: Draw It Yourself ................... 1942
• Advanced Preferences
◦ Prerequisites ...................................................................................... 1955
◦ Introducing PreferenceActivity ....................................................... 1955
◦ Intents for Headers or Preferences ................................................. 1960
◦ Conditional Headers ........................................................................ 1961
◦ Dependent Preferences ................................................................... 1966
◦ Nested Screens ................................................................................. 1969
◦ Listening to Preference Changes .................................................... 1972
◦ Defaults, and Defaults ...................................................................... 1975
◦ Listening to Preference Value Changes .......................................... 1976
xx

•

•

•

•

•

•

◦ Dynamic ListPreference Contents .................................................. 1976
◦ Dealing with External Changes to Preferences ............................... 1981
◦ Preferences in Device Settings App ....................................... 1983
Custom Dialogs and Preferences
◦ Prerequisites ...................................................................................... 1991
◦ Your Dialog, Chocolate-Covered ..................................................... 1991
◦ Preferring Your Own Preferences, Preferably ................................ 1995
Progress Indicators
◦ Prerequisites ..................................................................................... 2003
◦ Progress Bars .................................................................................... 2003
◦ ProgressBar and Threads ................................................................ 2007
◦ Tailoring Progress Bars .................................................................... 2010
◦ Progress Dialogs .............................................................................. 2020
◦ Title Bar and Action Bar Progress Indicators ................................ 2022
◦ Direct Progress Indication .............................................................. 2024
More Fun with Pagers
◦ Prerequisites ..................................................................................... 2027
◦ Hosting ViewPager in a Fragment .................................................. 2027
◦ Pages and the Action Bar ................................................................ 2029
◦ ViewPagers and Scrollable Contents .............................................. 2032
◦ Columns for Large, Pages for Small ................................................ 2032
◦ Introducing ArrayPagerAdapter ..................................................... 2038
◦ Columns for Large Landscape, Pages for the Rest ........................ 2041
◦ Adding, Removing, and Moving Pages .......................................... 2046
◦ Inside ArrayPagerAdapter ............................................................... 2050
Focus Management and Accessibility
◦ Prerequisites ..................................................................................... 2065
◦ Prepping for Testing ....................................................................... 2066
◦ Controlling the Focus ..................................................................... 2066
◦ Accessibility and Focus ................................................................... 2076
◦ Accessibility Beyond Focus ............................................................. 2077
◦ Accessibility Beyond Impairment ................................................... 2087
Miscellaneous UI Tricks
◦ Prerequisites .................................................................................... 2089
◦ Full-Screen and Lights-Out Modes ............................................... 2089
◦ Offering a Delayed Timeout ........................................................... 2100
Event Bus Alternatives
◦ Prerequisites ...................................................................................... 2105
◦ A Brief Note About the Sample Apps .............................................. 2105
◦ Standard Intents as Event Bus ......................................................... 2105
◦ LocalBroadcastManager as Event Bus ............................................ 2106
xxi

•

•

•

•

◦ greenrobot’s EventBus 3.x ................................................................ 2117
◦ greenrobot’s EventBus 2.x ................................................................ 2123
◦ Hey, What About Otto? .................................................................. 2124
Tasks
◦ Prerequisites ...................................................................................... 2125
◦ First, Some Terminology .................................................................. 2125
◦ And Now, a Bit About Task Killers .................................................. 2131
◦ A Canary for the Task’s Coal Mine ......................................... 2138
◦ The Default User Experience ........................................................... 2141
◦ Explaining the Default Behavior ...................................................... 2145
◦ Basic Scenarios for Changing the Behavior ................................... 2148
◦ Dealing with the Persistent Tasks ................................................... 2163
◦ Documents As Tasks ....................................................................... 2165
◦ Other Task-Related Activity Properties ......................................... 2168
◦ Other Task-Related Activity Methods ............................................. 2177
The Assist API (“Now On Tap”)
◦ Prerequisites ..................................................................................... 2180
◦ What Data Gets Disclosed .............................................................. 2180
◦ Adding to the Data ........................................................................... 2182
◦ Removing from the Data .................................................................. 2185
◦ Blocking Assist as a User ................................................................. 2188
◦ Implementing Your Own Assistant ................................................. 2191
The Autofill API
◦ Prerequisites ..................................................................................... 2206
◦ The Pieces of the Puzzle .................................................................. 2206
◦ The User Experience ........................................................................ 2207
◦ What Data Gets Disclosed .............................................................. 2209
◦ Blocking Autofill as a User .............................................................. 2223
◦ Supporting Autofill with Standard Widgets .................................. 2225
◦ Supporting Autofill with Custom Widgets .................................... 2228
◦ Dealing with Dynamic Changes ..................................................... 2228
◦ Security Requirements of Autofill Services .................................... 2229
The Data Binding Framework
◦ Prerequisites ..................................................................................... 2235
◦ The What, Now? .............................................................................. 2236
◦ The Basic Steps ................................................................................ 2237
◦ The Extended Layout Resource ...................................................... 2243
◦ The Binding Expression Language ................................................. 2247
◦ Observables and Updating the Binding ......................................... 2250
◦ Two-Way Binding ............................................................................ 2263
◦ Other Features of Note .................................................................... 2266
xxii

• Drag and Drop
◦ Prerequisites ..................................................................................... 2295
◦ The Scope of Drag and Drop ........................................................... 2295
◦ The Pieces of Drag-and-Drop ......................................................... 2297
◦ Drag-and-Drop, within an Activity ................................................. 2301
◦ Drag-and-Drop, Between Apps .............................................. 2310
◦ Detecting Cross-App Drag Events .................................................. 2322
◦ Intra-App Cross-Window Drag-and-Drop ..................................... 2322
◦ Pondering Legacy Multi-Window .................................................. 2325
◦ Dragging and Dropping Simple Stuff ............................................. 2325
◦ Multi-Action Drag-and-Drop ......................................................... 2326
◦ Nested Drop Targets .............................................................. 2332
◦ Pondering Standards ........................................................................ 2341
◦ Pondering Accessibility .................................................................... 2341
• Keyboard and Mouse Input
◦ Prerequisites ..................................................................................... 2343
◦ Offering Keyboard Shortcuts ................................................ 2343
◦ Custom Copy-and-Paste .................................................................. 2353
◦ Physical Keyboards and Focusing ................................................... 2357
◦ Offering Mouse Context Menus ...................................................... 2361
◦ Offering Tooltips ................................................................... 2367
◦ Pointer Capture ..................................................................... 2375
• Viewing PDFs
◦ Prerequisites ..................................................................................... 2377
◦ The Criteria ...................................................................................... 2378
◦ The Classic Solution: ACTION_VIEW ........................................... 2380
◦ The Really Bad Idea: Google Docs .................................................. 2380
◦ The Built-In Option: PdfRenderer ................................................... 2381
◦ The Thunder Lizard Choice: PDF.js ............................................... 2390
◦ The Native Approach: Pdfium ........................................................ 2394
◦ What To Choose? ............................................................................. 2398
• Home Screen App Widgets
◦ Prerequisites ..................................................................................... 2401
◦ App Widgets and Security .............................................................. 2401
◦ The Big Picture for a Small App Widget ........................................ 2402
◦ Crafting App Widgets ...................................................................... 2403
◦ Another and Another ...................................................................... 2410
◦ App Widgets: Their Life and Times ................................................ 2411
◦ Controlling Your (App Widget’s) Destiny ....................................... 2411
◦ One Size May Not Fit All ................................................................. 2412
◦ Lockscreen Widgets ........................................................................ 2418
xxiii

•

•

•

•

•

•

•

◦ Preview Images ................................................................................ 2424
◦ Being a Good Host ........................................................................... 2426
Adapter-Based App Widgets
◦ Prerequisites ..................................................................................... 2427
◦ AdapterViews for App Widgets ...................................................... 2427
◦ Building Adapter-Based App Widgets ........................................... 2428
Content Provider Theory
◦ Prerequisites ..................................................................................... 2445
◦ Using a Content Provider ................................................................ 2445
◦ Building Content Providers ............................................................ 2453
◦ Issues with Content Providers ........................................................ 2461
Content Provider Implementation Patterns
◦ Prerequisites ..................................................................................... 2463
◦ The Single-Table Database-Backed Content Provider .................. 2463
◦ The Local-File Content Provider ............................................ 2471
◦ The Protected Provider .................................................................. 2480
◦ The Stream Provider ........................................................................ 2482
◦ FileProvider .......................................................................... 2486
◦ StreamProvider ................................................................................ 2491
The Loader Framework
◦ Prerequisites ...................................................................................... 2501
◦ Cursors: Issues with Management .................................................. 2502
◦ Introducing the Loader Framework ............................................... 2502
◦ Choosing an Implementation ......................................................... 2504
◦ Using CursorLoader ......................................................................... 2504
◦ What Else Is Missing? ..................................................................... 2507
◦ What Happens When…? ................................................................. 2507
◦ Writing a Custom Loader ................................................................ 2508
The ContactsContract and CallLog Providers
◦ Prerequisites ...................................................................................... 2517
◦ Introducing You to Your Contacts .................................................. 2518
◦ Pick a Peck of Pickled People ......................................................... 2519
◦ Spin Through Your Contacts ............................................................ 2521
◦ Makin’ Contacts ............................................................................... 2528
◦ Looking at the CallLog .................................................................... 2532
The CalendarContract Provider
◦ Prerequisites ..................................................................................... 2538
◦ You Can’t Be a Faker ........................................................................ 2538
◦ Do You Have Room on Your Calendar? ......................................... 2538
◦ Penciling In an Event ....................................................................... 2544
The MediaStore Provider
xxiv

•

•

•

•

◦ Prerequisites ..................................................................................... 2547
◦ What Is the MediaStore? ................................................................. 2548
◦ MediaStore and “Other” External Storage ..................................... 2549
◦ How Does My Content Get Indexed? ............................................. 2550
◦ How Do I Retrieve Video from the MediaStore? ........................... 2550
Consuming Documents
◦ Prerequisites ..................................................................................... 2559
◦ The Storage Access… What? ........................................................... 2559
◦ The Storage Access Framework Participants .................................. 2561
◦ Picking How to Pick (a Peck of Pickled Pepper Photos) ............... 2561
◦ Opening a Document ...................................................................... 2562
◦ Why We Want Things To Be Openable ......................................... 2566
◦ The Rest of the CRUD ..................................................................... 2567
◦ The DocumentFile Helper .............................................................. 2568
◦ CWAC-Document and DocumentFileCompat ....................... 2568
◦ Getting Durable Access ................................................................... 2569
◦ Another Durable Example: Diceware ............................................. 2579
◦ Extended Example: A Tiny Text Editor .......................................... 2593
◦ Document Trees ............................................................................... 2623
◦ Getting a Tree: Example .................................................................. 2625
◦ Scoped Directory Access Bug .......................................................... 2642
◦ Android 8.0 Changes .............................................................. 2643
Providing Documents
◦ Prerequisites ..................................................................................... 2645
◦ Have Your Content, and Provide it Too ......................................... 2645
◦ Key Provider Concepts .................................................................... 2647
◦ Pieces of a Provider ......................................................................... 2648
◦ Optional Provider Capabilities ....................................................... 2663
Encrypted Storage
◦ Prerequisites ..................................................................................... 2670
◦ Scenarios for Encryption ................................................................. 2670
◦ Obtaining SQLCipher ..................................................................... 2670
◦ Using SQLCipher ............................................................................. 2671
◦ SQLCipher Limitations ................................................................... 2672
◦ Passwords and Sessions ................................................................... 2673
◦ About Those Passphrases… ............................................................. 2674
◦ Encrypted Preferences ..................................................................... 2681
◦ IOCipher ........................................................................................... 2683
Packaging and Distributing Data
◦ Prerequisites ..................................................................................... 2685
◦ Packing a Database To Go ............................................................... 2685
xxv

• Advanced Database Techniques
◦ Prerequisites .................................................................................... 2689
◦ Full-Text Indexing .......................................................................... 2689
• Data Backup
◦ Prerequisites ..................................................................................... 2707
◦ First, Some Terminology ................................................................. 2708
◦ Differing Definitions of “Backup” ................................................... 2708
◦ Implementing IT-Style Backup ....................................................... 2710
◦ The Google Backup Bootstrap ........................................................ 2735
◦ Boosting Backup Security ............................................................... 2744
◦ Alternative Approaches ................................................................... 2745
• SSL
◦ Prerequisites ...................................................................................... 2751
◦ Basic SSL Operation ......................................................................... 2751
◦ Problems in Paradise ....................................................................... 2752
◦ Introducing Network Security Configuration ................................ 2755
◦ SSL Problems and Network Security Configuration ..................... 2758
◦ Other SSL Strengthening Techniques ............................................ 2768
◦ Advanced Uses of CWAC-NetSecurity ............................................ 2771
◦ NetCipher ......................................................................................... 2774
• NetCipher
◦ Prerequisites ..................................................................................... 2775
◦ Network Security’s Got Onions ...................................................... 2775
◦ The NetCipher HTTP Integration APIs .......................................... 2777
◦ The Rest of the Builder API ............................................................ 2784
• Embedding a Web Server
◦ Prerequisites ..................................................................................... 2797
◦ Why a Web Server? .......................................................................... 2797
◦ Introducing AsyncHttpServer ......................................................... 2799
◦ Embedding a Simple Server ............................................................ 2799
◦ Template-Driven Responses, with Handlebars ............................. 2816
◦ Supporting WebSockets ................................................................... 2821
◦ Securing the Web Server ................................................................. 2827
◦ Towards a Reusable Web Server Service ........................................ 2834
• Miscellaneous Network Topics
◦ Prerequisites ..................................................................................... 2845
◦ Downloading Files ........................................................................... 2845
◦ Data Saver ......................................................................................... 2859
• Audio Playback
◦ Prerequisites ..................................................................................... 2863
◦ Get Your Media On .......................................................................... 2863
xxvi

•

•

•

•

•

•

◦ MediaPlayer for Audio .......................................................... 2864
◦ Other Ways to Make Noise ............................................................ 2869
Audio Recording
◦ Prerequisites ..................................................................................... 2873
◦ Recording by Intent ......................................................................... 2873
◦ Recording to Files ............................................................................ 2876
◦ Recording to Streams ...................................................................... 2881
◦ Raw Audio Input ............................................................................. 2884
◦ Requesting the Microphone .......................................................... 2884
Video Playback
◦ Prerequisites ..................................................................................... 2885
◦ Moving Pictures ..................................................................... 2885
Using the Camera via 3rd-Party Apps
◦ Prerequisites ..................................................................................... 2891
◦ Being Specific About Features ........................................................ 2891
◦ Still Photos: Letting the Camera App Do It ................................... 2892
◦ Permissions and Third-Party Camera Apps .................................. 2899
◦ A Matter of Orientation ................................................................. 2900
◦ Scanning with ZXing ....................................................................... 2907
◦ Videos: Letting the Camera App Do It .......................................... 2908
◦ Using a Camera Library ......................................................... 2911
◦ Directly Working with the Camera ................................................ 2923
Working Directly with the Camera
◦ Prerequisites ..................................................................................... 2925
◦ Notes About the Code Snippets ..................................................... 2925
◦ A Tale of Two APIs ........................................................................... 2926
◦ Performing Basic Camera Operations ............................................ 2927
◦ Configuring the Still Camera .......................................................... 2950
◦ And Now, The Problems ................................................................. 2959
Media Routes
◦ Prerequisites ..................................................................................... 2965
◦ Terminology ..................................................................................... 2965
◦ A Tale of Two MediaRouters .......................................................... 2966
◦ Attaching to MediaRouter .............................................................. 2967
◦ User Route Selection with MediaRouteActionProvider ............... 2969
◦ Using Live Video Routes ................................................................ 2984
◦ Using Remote Playback Routes ..................................................... 2984
Supporting External Displays
◦ Prerequisites ..................................................................................... 3003
◦ A History of External Displays ........................................................ 3003
◦ What is a Presentation? .................................................................. 3004
xxvii

•

•

•

•

•

◦ Playing with External Displays ............................................ 3005
◦ Detecting Displays ............................................................................ 3011
◦ A Simple Presentation ...................................................................... 3012
◦ A Simpler Presentation ................................................................... 3018
◦ Presentations and Configuration Changes .................................... 3024
◦ Presentations as Fragments ............................................................ 3025
◦ Another Sample Project: Slides ...................................................... 3036
◦ Device Support for Presentation .................................................... 3044
◦ Presentations from a Service .......................................................... 3045
◦ Hey, What About Chromecast? ...................................................... 3048
Google Cast and Chromecast
◦ Prerequisites ...................................................................................... 3051
◦ Here a Cast, There a Cast ................................................................. 3051
◦ Common Chromecast Development Notes ................................... 3053
◦ Your API Choices ............................................................................. 3053
◦ Senders and Receivers ..................................................................... 3054
◦ Supported Media Types ................................................................... 3055
◦ Cast SDK Dependencies .................................................................. 3056
◦ Developing Google Cast Apps ........................................................ 3058
The “Ten-Foot UI”
◦ Prerequisites ..................................................................................... 3059
◦ What is the “Ten-Foot UI”? ............................................................ 3060
◦ Overscan .......................................................................................... 3060
◦ Navigation ........................................................................................ 3061
◦ Stylistic Considerations ................................................................... 3062
◦ The Leanback UI .............................................................................. 3064
◦ Testing Your Theories ...................................................................... 3079
Putting the TVs All Together: Decktastic
◦ Prerequisites ..................................................................................... 3082
◦ Introducing Decktastic .................................................................... 3082
◦ Implementing Decktastic ............................................................... 3086
Creating a MediaRouteProvider
◦ Prerequisites ...................................................................................... 3121
◦ Terminology ...................................................................................... 3121
◦ DIY Chromecast ................................................................................ 3122
◦ Creating the MediaRouteProvider ................................................... 3124
◦ Consuming the MediaRouteProvider .............................................. 3135
◦ Implementing This “For Realz” ....................................................... 3139
The Media Projection APIs
◦ Prerequisites ...................................................................................... 3141
◦ Requesting Screenshots ................................................................... 3141
xxviii

•

•

•

•

•

◦ Recording the Screen ........................................................................ 3156
◦ Yet Another Sample: andshooter ..................................................... 3176
Advanced Permissions
◦ Prerequisites ...................................................................................... 3183
◦ Securing Yourself .............................................................................. 3183
◦ Signature Permissions ..................................................................... 3186
◦ The Custom Permission Vulnerability ........................................... 3188
◦ Custom Dangerous Permissions, and Android 6.0 ....................... 3198
◦ Finding the Available Permissions ................................................. 3202
Restricted Profiles and UserManager
◦ Prerequisites ...................................................................................... 3215
◦ Android Tablets and Multiple User Accounts ................................ 3215
◦ Determining What the User Can Do .............................................. 3221
◦ Impacts of Device-Level Restrictions ............................................. 3224
◦ Enabling Custom Restrictions ........................................................ 3224
◦ Implicit Intents May Go “Boom” .................................................... 3235
Miscellaneous Security Techniques
◦ Prerequisites ..................................................................................... 3237
◦ Public Key Validation ...................................................................... 3237
◦ Choosing Your Signing Keysize ...................................................... 3249
◦ Avoiding Accidental APIs ................................................................ 3250
◦ Other Ways to Expose Data ............................................................ 3255
◦ Jacking Attacks ................................................................................ 3256
◦ Using FLAG_SECURE ...................................................................... 3264
AlarmManager and the Scheduled Service Pattern
◦ Scenarios .......................................................................................... 3267
◦ Options ............................................................................................. 3268
◦ A Simple Example ............................................................................ 3270
◦ The Five set…() Varieties ................................................................. 3272
◦ The Four Types of Alarms ............................................................... 3274
◦ When to Schedule Alarms .............................................................. 3274
◦ Archetype: Scheduled Service Polling ............................................ 3276
◦ Staying Awake at Work ................................................................... 3280
◦ Warning: Not All Android Devices Play Nice ................................ 3285
◦ Debugging Alarms ........................................................................... 3285
◦ WakefulBroadcastReceiver .............................................................. 3288
◦ Android 6.0 and the War on Background Processing ................... 3292
◦ Android 7.0 and OnAlarmListener ................................................. 3292
PowerManager and WakeLocks
◦ Prerequisites ..................................................................................... 3295
◦ Keeping the Screen On, UI-Style .................................................... 3295
xxix

•

•

•

•

•

◦ The Role of the WakeLock .............................................................. 3296
◦ What WakefulIntentService Does .................................................. 3297
JobScheduler
◦ Prerequisites ..................................................................................... 3299
◦ The Limitations of AlarmManager ................................................. 3299
◦ Enter the JobScheduler ................................................................... 3300
◦ Employing JobScheduler ................................................................. 3300
◦ Pondering Backoff Criteria ............................................................... 3315
◦ Other JobScheduler Features ........................................................... 3316
◦ JobScheduler Period Limits .............................................................. 3317
◦ GcmNetworkManager ...................................................................... 3317
◦ Periodic Work, Across Device Versions ................................. 3318
◦ Android 6.0 and “the War on Background Processing” ................ 3322
◦ Scheduling Content Monitoring ............................................ 3337
Accessing Location-Based Services
◦ Prerequisites ...................................................................................... 3351
◦ Location Providers: They Know Where You’re Hiding ................. 3352
◦ Finding Yourself ............................................................................... 3352
◦ On the Move .................................................................................... 3354
◦ Getting Locations via PendingIntent ............................................. 3362
◦ Are We There Yet? Are We There Yet? Are We There Yet? ........... 3362
◦ Testing… Testing… ............................................................................ 3363
◦ Alternative Flavors of Updates ........................................................ 3364
◦ The Fused Option ............................................................................ 3365
◦ Locations and Features ................................................................... 3365
The Fused Location Provider
◦ Prerequisites ..................................................................................... 3367
◦ Why Use the Fused Location Provider? ......................................... 3367
◦ Why Not Use the Fused Location Provider? ................................. 3368
◦ Finding Our Location, Once ........................................................... 3368
◦ Requesting Location Updates ......................................................... 3373
◦ I Can Haz Location? ........................................................................ 3375
Working with the Clipboard
◦ Prerequisites ..................................................................................... 3385
◦ Working with the Clipboard ........................................................... 3385
◦ ClipData and Drag-and-Drop ......................................................... 3390
◦ Monitoring the Clipboard ................................................................ 3391
◦ The Android 4.3 Clipboard Bug ...................................................... 3392
Telephony
◦ Prerequisites ..................................................................................... 3395
◦ Report To The Manager ................................................................... 3396
xxx

•

•

•

•

•

◦ You Make the Call! ................................................................. 3396
◦ No, Really, You Make the Call! ........................................................ 3399
Working With SMS
◦ Prerequisites ..................................................................................... 3401
◦ Sending Out an SOS, Give or Take a Letter ................................... 3402
◦ Monitoring and Receiving SMS ...................................................... 3410
◦ The SMS Inbox ................................................................................. 3416
◦ Asking to Change the Default .......................................................... 3417
◦ SMS and the Emulator .................................................................... 3418
◦ SMS Tokens ............................................................................ 3419
NFC
◦ Prerequisites ..................................................................................... 3425
◦ What Is NFC? ................................................................................... 3425
◦ To NDEF, Or Not to NDEF .............................................................. 3427
◦ NDEF Modalities ............................................................................. 3427
◦ NDEF Structure and Android’s Translation ................................... 3428
◦ The Reality of NDEF ........................................................................ 3429
◦ Sources of Tags .................................................................................. 3431
◦ Writing to a Tag ................................................................................ 3431
◦ Responding to a Tag ........................................................................ 3440
◦ Expected Pattern: Bootstrap ........................................................... 3441
◦ Mobile Devices are Mobile .............................................................. 3442
◦ Enabled and Disabled ..................................................................... 3442
◦ Android Beam .................................................................................. 3442
◦ Beaming Files ................................................................................... 3450
◦ Another Sample: SecretAgentMan .................................................. 3451
◦ Additional Resources ....................................................................... 3461
Device Administration
◦ Prerequisites ..................................................................................... 3463
◦ Objectives and Scope ....................................................................... 3463
◦ Defining and Registering an Admin Component .......................... 3464
◦ Going Into Lockdown ...................................................................... 3470
◦ Passwords and Device Administration ........................................... 3477
◦ Getting Along with Others ............................................................. 3482
Basic Use of Sensors
◦ Prerequisites ..................................................................................... 3483
◦ The Sensor Abstraction Model ....................................................... 3483
◦ Considering Rates ............................................................................ 3484
◦ Reading Sensors ............................................................................... 3485
◦ Batching Sensor Readings ............................................................... 3496
Printing and Document Generation
xxxi

•

•

•

•

◦ Prerequisites ..................................................................................... 3498
◦ The Android Print System ............................................................... 3498
◦ About the Sample App .................................................................... 3499
◦ Printing a Bitmap ............................................................................ 3500
◦ Printing an HTML Document ........................................................ 3502
◦ Printing a PDF File .......................................................................... 3507
◦ Printing Using a Canvas ................................................................... 3515
◦ Print Jobs ........................................................................................... 3518
◦ Printing, Threads, and Services ....................................................... 3518
◦ Printing Prior to Android 4.4 ........................................................... 3521
◦ HTML Generation ............................................................................ 3521
◦ PDF Generation Options ................................................................. 3525
Basic Bluetooth RFCOMM
◦ Prerequisites .......................................................................... 3527
◦ A Quick Bit of Scope .............................................................. 3528
◦ About the Sample App ........................................................... 3528
◦ Bluetooth and Permissions ................................................... 3534
◦ The Rx for Your Bluetooth ..................................................... 3535
◦ I Can Haz Bluetooth? ............................................................. 3536
◦ I Feel a Bond Between Us ....................................................... 3539
◦ A Voyage of Discovery ............................................................ 3542
◦ Serving and Shouting ............................................................ 3545
◦ Reach Out and Touch Someone ............................................. 3551
◦ Ping and Pong ........................................................................ 3554
◦ Differences with Android Things ........................................... 3558
Dealing with Different Hardware
◦ Prerequisites ...................................................................................... 3561
◦ Filtering Out Devices ....................................................................... 3561
◦ Runtime Capability Detection ........................................................ 3564
◦ Dealing with Device Bugs ............................................................... 3565
Writing and Using Parcelables
◦ Prerequisites ..................................................................................... 3569
◦ The Role of Parcelable ..................................................................... 3569
◦ Writing a Parcelable ........................................................................ 3570
◦ The Limitations of Parcelable ......................................................... 3576
◦ Beware the PendingIntent .............................................................. 3580
Responding to URLs
◦ Prerequisites ..................................................................................... 3587
◦ Manifest Modifications ................................................................... 3587
◦ Creating a Custom URL ................................................................... 3589
◦ Reacting to the Link ........................................................................ 3590
xxxii

•

•

•

•

•

•

◦ App Links ......................................................................................... 3592
App Shortcuts
◦ Prerequisites ..................................................................................... 3603
◦ Enabling Deep Dives ....................................................................... 3604
◦ App Shortcuts, from the User’s POV .............................................. 3604
◦ Offering Manifest App Shortcuts .................................................. 3606
◦ Offering Dynamic App Shortcuts .................................................... 3612
◦ Privacy, Security, and App Shortcuts .............................................. 3624
Plugin Patterns
◦ Prerequisites ..................................................................................... 3625
◦ Definitions, Scenarios, and Scope .................................................. 3625
◦ The Keys to Any Plugin System ...................................................... 3626
◦ Case Study: DashClock .................................................................... 3634
◦ Other Plugin Examples .......................................................... 3637
PackageManager Tricks
◦ Prerequisites ..................................................................................... 3657
◦ Asking Around ................................................................................. 3657
◦ Preferred Activities .......................................................................... 3661
◦ Middle Management ....................................................................... 3667
Remote Services and the Binding Pattern
◦ Prerequisites ..................................................................................... 3671
◦ The Binding Pattern ........................................................................ 3672
◦ When IPC Attacks! .......................................................................... 3678
◦ Service From Afar ............................................................................ 3681
◦ Tightening Up the Security .................................................... 3687
◦ Servicing the Service ....................................................................... 3691
◦ Thinking About Security ................................................................ 3696
◦ The “Everlasting Service” Anti-Pattern ......................................... 3696
Advanced Manifest Tips
◦ Prerequisites .................................................................................... 3699
◦ Just Looking For Some Elbow Room ............................................. 3699
◦ Using an Alias .................................................................................. 3709
◦ Getting Meta (Data) ......................................................................... 3710
Miscellaneous Integration Tips
◦ Prerequisites ...................................................................................... 3715
◦ Direct Share ...................................................................................... 3715
◦ Take the Shortcut ............................................................................. 3724
◦ Homing Beacons for Intents ............................................................ 3731
◦ Integrating with Text Selection ............................................. 3731
◦ Quick Settings and TileService ....................................................... 3742
◦ Installing Packages ................................................................ 3751
xxxiii

•

•

•

•

•

•

•

◦ Deleting Packages ................................................................. 3754
◦ Detecting Changes in Packages ............................................ 3754
Replacing App Code Dynamically
◦ Prerequisites ..................................................................................... 3757
◦ Typical Objectives ............................................................................ 3758
◦ The Challenges ................................................................................. 3760
◦ The Scripting Solution .................................................................... 3762
◦ The Hybrid Solution ........................................................................ 3763
◦ The Patch Solution .......................................................................... 3764
◦ A DIY Solution ................................................................................. 3765
◦ Is Any Of This a Good Idea? ........................................................... 3788
Android Studio Editors and Dialogs
◦ Prerequisites ..................................................................................... 3789
◦ Project Structure .............................................................................. 3789
◦ Translations Editor ......................................................................... 3800
Advanced Emulator Capabilities
◦ Prerequisites ..................................................................................... 3807
◦ Other Notable Configuration Options ........................................... 3807
◦ The Emulator Sidebar ...................................................................... 3813
◦ Emulator Window Operations ....................................................... 3824
◦ Headless Operation ......................................................................... 3824
Lint and the Support Annotations
◦ Prerequisites ..................................................................................... 3827
◦ What It Is .......................................................................................... 3828
◦ When It Runs ................................................................................... 3828
◦ What to Fix ....................................................................................... 3829
◦ What to Configure ........................................................................... 3830
◦ Support Annotations ....................................................................... 3834
Inspecting Layouts
◦ Prerequisites ..................................................................................... 3847
◦ The Layout Inspector ...................................................................... 3847
◦ Hierarchy View ................................................................................ 3849
Screenshots and Screencasts
◦ Prerequisites ..................................................................................... 3855
◦ Collecting from Android Studio ..................................................... 3855
◦ Screencasts ....................................................................................... 3859
◦ Collecting from the Command Line .............................................. 3859
◦ Collecting from Another App ......................................................... 3861
◦ Tips and Tricks ................................................................................. 3862
ADB Tips and Tricks
◦ Prerequisites ..................................................................................... 3863
xxxiv

•

•

•

•

•

•

◦ This is the Droid That You Are Looking For .................................. 3863
◦ Installing and Uninstalling Apps .................................................... 3864
◦ Playing with Permissions ................................................................ 3864
◦ Starting and Stopping Components ............................................... 3865
◦ Killing Processes and Clearing Data .............................................. 3866
◦ Changing Display Metrics .............................................................. 3866
Stetho
◦ Wait, Wut? Chrome? ...................................................................... 3869
◦ Basic Stetho Integration ....................................................... 3869
◦ Connecting Chrome to Your App ................................................... 3876
◦ What You Get In Chrome Dev Tools .............................................. 3877
◦ Getting Help with Stetho ................................................................ 3885
Issues with Speed
◦ Prerequisites .................................................................................... 3889
◦ Getting Things Done ...................................................................... 3889
◦ Your UI Seems… Janky .................................................................... 3890
◦ Not Far Enough in the Background ............................................... 3890
◦ Playing with Speed .......................................................................... 3891
Finding CPU Bottlenecks
◦ Prerequisites ..................................................................................... 3893
◦ Android Studio’s Profiler ................................................................ 3894
◦ Method Tracing ............................................................................... 3896
◦ Other General CPU Measurement Techniques ............................. 3901
◦ UI “Jank” Measurement ................................................................... 3902
Focus On: NDK
◦ Prerequisites ..................................................................................... 3919
◦ The Role of the NDK ....................................................................... 3920
◦ Introducing CWAC-AndDown ....................................................... 3923
◦ Installing the NDK ........................................................................... 3923
◦ The Contents of an NDK Project .................................................... 3924
◦ Building Your Library ...................................................................... 3927
◦ libhoudini and the NDK .................................................................. 3933
Improving CPU Performance in Java
◦ Prerequisites ..................................................................................... 3935
◦ Reduce CPU Utilization .................................................................. 3935
◦ Reduce Time on the Main Application Thread ............................ 3940
◦ Improve Throughput and Responsiveness .................................... 3948
Finding and Eliminating Jank
◦ Prerequisites ...................................................................................... 3951
◦ The Case: ThreePaneDemoBC ......................................................... 3951
◦ Are We Janky? .................................................................................. 3952
xxxv

•

•

•

•

•

•

◦ Finding the Source of the Jank ....................................................... 3952
◦ Where Things Went Wrong ............................................................ 3963
◦ Removing the Jank ........................................................................... 3963
◦ Frame Metrics API .......................................................................... 3964
Issues with Bandwidth
◦ Prerequisites ..................................................................................... 3971
◦ You’re Using Too Much of the Slow Stuff ....................................... 3972
◦ You’re Using Too Much of the Expensive Stuff .............................. 3972
◦ You’re Using Too Much of Somebody Else’s Stuff .......................... 3973
◦ You’re Using Too Much… And There Is None ................................ 3974
Focus On: TrafficStats
◦ Prerequisites ..................................................................................... 3975
◦ TrafficStats Basics ............................................................................ 3975
◦ Example: TrafficMonitor ................................................................. 3977
◦ Other Ways to Employ TrafficStats ............................................... 3986
Measuring Bandwidth Consumption
◦ Prerequisites .................................................................................... 3989
◦ On-Device Measurement ............................................................... 3989
◦ Off-Device Measurement ................................................................ 3993
◦ Android Studio Profiler ................................................................... 3995
Being Smarter About Bandwidth
◦ Prerequisites ..................................................................................... 3997
◦ Bandwidth Savings .......................................................................... 3997
◦ Bandwidth Shaping ......................................................................... 4001
◦ Avoiding Metered Connections ..................................................... 4005
◦ Data Saver ........................................................................................ 4005
Issues with Application Heap
◦ Prerequisites .................................................................................... 4007
◦ You Are in a Heap of Trouble ......................................................... 4008
◦ Determining Your Heap Size At Runtime ..................................... 4009
◦ Fragments of Memory .................................................................... 4009
◦ Getting a Trim .................................................................................. 4010
◦ Warning: Contains Graphic Images ................................................ 4011
◦ Releasing SQLite Memory ............................................................... 4023
◦ Cheating ........................................................................................... 4023
◦ The 1MB IPC Transaction Limit ..................................................... 4024
Finding Memory Leaks
◦ Prerequisites ..................................................................................... 4027
◦ Android Studio Profiler .................................................................. 4028
◦ Getting Heap Dumps ....................................................................... 4031
◦ Analyzing Heap Dumps in Android Studio ................................... 4032
xxxvi

•

•

•

•

•

•

◦ Common Leak Scenarios ................................................................. 4038
◦ A Canary in a Leaky Coal Mine ...................................................... 4045
Issues with System RAM
◦ Prerequisites ..................................................................................... 4055
◦ Can’t We All Just Get Along? .......................................................... 4055
◦ Contributors to System RAM Consumption ................................. 4056
◦ Measuring System RAM Consumption: Tools ............................... 4057
◦ Measuring System RAM Consumption: Runtime ......................... 4073
◦ Learn To Let Go (Of Your Heap) .................................................... 4074
Issues with Battery Life
◦ Prerequisites ..................................................................................... 4077
◦ You’re Getting Blamed .................................................................... 4078
◦ Not All Batteries Are Created Equal .............................................. 4079
◦ Stretching Out the Last mWh ....................................................... 4079
Power Measurement Options
◦ Prerequisites ..................................................................................... 4081
◦ batterystats and the Battery Historian .......................................... 4082
◦ PowerTutor ....................................................................................... 4093
◦ Battery Screen in Settings Application ......................................... 4097
◦ BatteryInfo Dump ........................................................................... 4099
Sources of Power Drain
◦ Prerequisites ..................................................................................... 4103
◦ Screen ............................................................................................... 4104
◦ Disk I/O ............................................................................................ 4105
◦ WiFi and Mobile Data ..................................................................... 4106
◦ GPS ................................................................................................... 4109
◦ Camera .............................................................................................. 4110
◦ Additional Sources ............................................................................ 4110
Addressing Application Size Issues
◦ Prerequisites ...................................................................................... 4113
◦ The APK Analyzer ............................................................................. 4113
◦ Java Code, and the 64K Method Limit ............................................ 4116
◦ Native Code ....................................................................................... 4121
◦ Images ............................................................................................... 4122
◦ APK Expansion Files ........................................................................ 4124
Crash Reporting Using ACRA
◦ Prerequisites ...................................................................................... 4125
◦ What Happens When Things Go “Boom”? ..................................... 4125
◦ Introducing ACRA ........................................................................... 4126
◦ Where ACRA Reports Crashes ......................................................... 4127
◦ ACRA Integration Basics ................................................................. 4129
xxxvii

•

•

•

•

•

•

◦ What the User Sees ......................................................................... 4134
◦ What You See .................................................................................... 4141
◦ Customizing Where Reports Go ..................................................... 4148
◦ Adding Additional Data .................................................................. 4149
◦ Removing Data ................................................................................. 4152
◦ End-User Configuration ................................................................... 4153
◦ ACRA and Processes ......................................................................... 4153
JVM Scripting Languages
◦ Prerequisites ...................................................................................... 4155
◦ Languages on Languages ................................................................. 4155
◦ A Brief History of JVM Scripting .................................................... 4156
◦ Limitations ........................................................................................ 4157
◦ SL4A and JVM Languages ............................................................... 4158
◦ Embedding JVM Languages ............................................................ 4158
◦ Other JVM Scripting Languages ...................................................... 4172
In-App Diagnostics
◦ Prerequisites ...................................................................................... 4177
◦ The Diagnostic Activity ................................................................... 4178
◦ The Diagnostic Web App ................................................................ 4189
◦ The Diagnostic Overlay ................................................................... 4197
Anti-Patterns
◦ Prerequisites ...................................................................................... 4213
◦ Leak Threads… Or Things Attached to Threads ............................ 4213
◦ Use Large Heap Unnecessarily ......................................................... 4215
◦ Misuse the MENU Button ................................................................ 4217
◦ Interfere with Navigation ................................................................ 4218
◦ Use android:sharedUserId .............................................................. 4220
◦ Implement a “Quit” Button ............................................................. 4221
◦ Terminate Your Process ................................................................... 4223
◦ Try to Hide from the User ............................................................... 4224
◦ Use Multiple Processes .................................................................... 4225
◦ Hog System Resources ..................................................................... 4227
Widget Catalog: AdapterViewFlipper
◦ Key Usage Tips .................................................................................. 4231
◦ A Sample Usage ............................................................................... 4232
◦ Visual Representation ..................................................................... 4232
Widget Catalog: CalendarView
◦ Key Usage Tips ................................................................................. 4233
◦ A Sample Usage ............................................................................... 4234
◦ Visual Representation ..................................................................... 4235
Widget Catalog: DatePicker
xxxviii

•

•

•

•

•

•

•

•

◦ Key Usage Tips ................................................................................. 4239
◦ A Sample Usage .............................................................................. 4240
◦ Visual Representation ..................................................................... 4242
Widget Catalog: ExpandableListView
◦ Key Usage Tips ................................................................................. 4247
◦ A Sample Usage .............................................................................. 4248
◦ Visual Representation ..................................................................... 4254
Widget Catalog: SeekBar
◦ Key Usage Tips ................................................................................. 4257
◦ A Sample Usage ............................................................................... 4257
◦ Visual Representation .................................................................... 4260
Widget Catalog: SlidingDrawer
◦ Key Usage Tips ................................................................................. 4263
◦ A Sample Usage .............................................................................. 4264
◦ Visual Representation ..................................................................... 4265
Widget Catalog: StackView
◦ Key Usage Tips ................................................................................ 4269
◦ A Sample Usage ...................................................................... 4270
◦ Visual Representation ..................................................................... 4271
Widget Catalog: TabHost and TabWidget
◦ Deprecation Notes ........................................................................... 4273
◦ Key Usage Tips ................................................................................. 4273
◦ A Sample Usage ...................................................................... 4274
◦ Visual Representation ..................................................................... 4276
Widget Catalog: TimePicker
◦ Key Usage Tips ................................................................................. 4279
◦ A Sample Usage ............................................................................... 4279
◦ Visual Representation ..................................................................... 4281
Widget Catalog: ViewFlipper
◦ Key Usage Tips ................................................................................. 4285
◦ A Sample Usage ..................................................................... 4286
◦ Visual Representation ..................................................................... 4287
Device Catalog: Chrome and Chrome OS
◦ Prerequisites ..................................................................................... 4291
◦ How This Works .............................................................................. 4292
◦ Testing Your App on Chrome OS ................................................... 4293
◦ Be Prepared To Be Wiped Out ........................................................ 4303
◦ Enabling Your App for Chrome OS ................................................ 4304
◦ Your App on Chrome OS ................................................................. 4304
◦ Distribution Options ........................................................................ 4313
◦ Apps Sans Role .................................................................................. 4313
xxxix

•

•

•

•

•

•

◦ Getting Help ..................................................................................... 4314
Android Things Basics
◦ Prerequisites ...................................................................................... 4315
◦ Um, What’s a Thing? .............................................................. 4316
◦ Headless, But No Horseman .................................................. 4317
◦ Setting Up a Raspberry-Flavored Thing ................................ 4317
◦ An App For Your Thing ........................................................... 4328
◦ Control Interfaces .................................................................. 4332
◦ What’s Different? ................................................................... 4335
◦ Environment Details ............................................................. 4338
◦ Considerations ...................................................................... 4340
Device Catalog: BlackBerry
◦ I Thought BlackBerry Had Their Own OS? ................................... 4344
◦ What Else Is Different? ................................................................... 4344
◦ What Are We Making? .................................................................... 4347
◦ Getting Your Development Environment Established .................. 4347
◦ How Does Distribution Work? ....................................................... 4350
Device Catalog: Android TV
◦ Prerequisites ..................................................................................... 4353
◦ Hey, Wait a Minute… I Thought the Name Was “Google TV”? .... 4353
◦ Some Android TV Hardware .......................................................... 4354
◦ What Features and Configurations Does It Use? .......................... 4356
◦ What Is Really Different? ................................................................ 4357
◦ Getting Your Development Environment Established .................. 4359
◦ How Does Distribution Work? ....................................................... 4361
Device Catalog: Amazon Fire TV and Fire TV Stick
◦ Prerequisites ..................................................................................... 4365
◦ Introducing the Fire TV Devices .................................................... 4365
◦ What Features and Configurations Do They Use? ......................... 4371
◦ What Is Really Different? ................................................................ 4372
◦ Casting and Fire TV ......................................................................... 4373
◦ Getting Your Development Environment Established .................. 4374
◦ Working with the Remote and Controller ..................................... 4375
◦ How Does Distribution Work? ....................................................... 4377
◦ Getting Help ..................................................................................... 4377
Device Catalog: Samsung DeX
◦ DeX Screen Modes ........................................................................... 4381
◦ Other App Impacts .......................................................................... 4383
◦ For More Information ..................................................................... 4388
Appendix A: CWAC Libraries
◦ cwac-adapter .................................................................................... 4391
xl

◦ cwac-colormixer ............................................................................... 4391
◦ cwac-crossport ................................................................................. 4392
◦ cwac-document ............................................................................... 4392
◦ cwac-layouts ..................................................................................... 4392
◦ cwac-merge ...................................................................................... 4392
◦ cwac-netsecurity .............................................................................. 4393
◦ cwac-pager ....................................................................................... 4393
◦ cwac-presentation ........................................................................... 4393
◦ cwac-provider .................................................................................. 4393
◦ cwac-richedit ................................................................................... 4394
◦ cwac-sacklist .................................................................................... 4394
◦ cwac-saferoom ................................................................................. 4394
◦ cwac-security ................................................................................... 4394
◦ cwac-strictmodeex ........................................................................... 4394
◦ cwac-wakeful .................................................................................... 4395
• Appendix B: Android 8.0
◦ The War on Background Processing, Continued .......................... 4397
◦ JobScheduler Enhancements ................................................ 4406
◦ Auto-Fill ............................................................................................ 4411
◦ Notification Channels ........................................................... 4411
◦ Other Changes with Notifications ........................................ 4412
◦ Multi-Window Changes ......................................................... 4412
◦ WebView Changes .................................................................. 4412
◦ ContentProvider Changes ............................................................... 4413
◦ Storage Access Framework Changes ..................................... 4413
◦ Package Management ........................................................... 4413
◦ Fonts as Resources ........................................................................... 4413
◦ Other Major Changes in Android 8.0 .................................... 4414
◦ Other Minor Changes in Android 8.0 .................................... 4422
• Appendix C: Community Theater and the Appinars
◦ Viewing the Appinar Roster ............................................................ 4427
◦ Managing Appinars ......................................................................... 4430
◦ Viewing an Appinar ......................................................................... 4433

xli

Preface

Welcome to the Book!
Thanks!
Thanks for your interest in developing applications for Android! Android has grown
from nothing to arguably the world’s most popular smartphone OS in a few short
years. Whether you are developing applications for the public, for your business or
organization, or are just experimenting on your own, I think you will find Android to
be an exciting and challenging area for exploration.
And, most of all, thanks for your interest in this book! I sincerely hope you find it
useful and at least occasionally entertaining.

The Book’s Structure
As you may have noticed, this is a rather large book.
To make this vast quantity of material manageable, the chapters are divided into the
core chapters and a series of trails.
The core chapters represent many key concepts that Android developers need to
understand in order to build an app. While an occasional “nice to have” topic will
drift into the core — to help illustrate a point, for example — the core chapters
generally are fairly essential.
The core chapters are designed to be read in sequence and will interleave both
traditional technical book prose with tutorial chapters, to give you hands-on
experience with the concepts being discussed. Most of the tutorials can be skipped,
xliii

PREFACE
though the first two — covering setting up your SDK environment and creating a
project – everybody should read.
The bulk of the chapters are divided into trails, covering some particular general
topic, from data storage to advanced UI effects to performance measurement and
tuning. Each trail will have several chapters. However, those chapters, and the trails
themselves, are not necessarily designed to be read in any order. Each chapter in the
trails will point out prerequisite chapters or concepts that you will want to have
covered in advance. Hence, these chapters are mostly reference material, for when
you specifically want to learn something about a specific topic.
The core chapters will link to chapters in the trails, to show you where you can find
material related to the chapter you just read. So between the book’s table of
contents, this preface, the search tool in your digital book reader, and the crosschapter links, you should have plenty of ways of finding the material you want to
read.
You are welcome to read the entire book front-to-back if you wish. The trails will
appear after the core chapters. Those trails will be in a reasonably logical order,
though you may have to hop around a bit to cover all of the prerequisites.

The Trails
Here is a list of all of the trails and the chapters that pertain to those trails, in order
of appearance (except for those appearing in the list multiple times, where they span
major categories):

Code Organization and Gradle
•
•
•
•
•
•
•

Working with Library Projects
Gradle and Tasks
Gradle Build Variants
Manifest Merger Rules
Signing Your App
Distribution
Advanced Gradle for Android Tips

Testing
• Testing with JUnit4
xliv

PREFACE
•
•
•
•
•

Testing with Espresso
Testing with UIAutomator
Measuring Test Coverage
Unit Testing
MonkeyRunner and the Test Monkey

Rx
• Java 8 Lambda Expressions
• Rx Basics

Advanced UI
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

Notifications
Advanced Notifications
Multi-Window Support
Advanced ConstraintLayout
GridLayout
Dialogs and DialogFragments
Advanced ListViews
Action Modes and Context Menus
Other Advanced Action Bar Techniques
Toolbar
AppCompat: The Official Action Bar Backport
RecyclerView
Implementing a Navigation Drawer
The Android Design Support Library
Advanced Uses of WebView
The Input Method Framework
Fonts
Rich Text
Animators
Legacy Animations
Custom Drawables
Mapping with Maps V2
Crafting Your Own Views
Advanced Preferences
Custom Dialogs and Preferences
Progress Indicators
More Fun with Pagers
xlv

PREFACE
•
•
•
•
•
•
•
•
•
•

Focus Management and Accessibility
Miscellaneous UI Tricks
Event Bus Alternatives
Tasks
The Assist API (“Now On Tap”)
The Auto-Fill API
Data Binding
Drag-and-Drop
Keyboard and Mouse Input
Viewing PDFs

Home Screen Effects
• Home Screen App Widgets
• Adapter-Based App Widgets

Data Storage and Retrieval
•
•
•
•
•
•
•
•
•
•
•
•

Content Provider Theory
Content Provider Implementation Patterns
The Loader Framework
The ContactsContract Provider
The CalendarContract Provider
The MediaStore Provider
Consuming Documents
Providing Documents
Encrypted Storage
Packaging and Distributing Data
Advanced Database Techniques
Data Backup

Advanced Network Topics
•
•
•
•

SSL
NetCipher
Embedding a Web Server
Miscellaneous Network Capabilities

xlvi

PREFACE

Media
•
•
•
•
•
•
•
•
•
•
•
•
•

Audio Playback
Audio Recording
Video Playback
Using the Camera via 3rd-Party Apps
Working Directly with the Camera
The MediaStore Provider
Media Routes
Supporting External Displays
Google Cast and ChromeCast
The “10 Foot UI”
Putting the TVs All Together: Decktastic
Creating a MediaRouteProvider
The Media Projection APIs

Security
•
•
•
•
•
•

SSL
NetCipher
Encrypted Storage
Advanced Permissions
Restricted Profiles and UserManager
Miscellaneous Security Techniques

Hardware and System Services
•
•
•
•
•
•
•
•
•
•
•
•
•

AlarmManager and the Scheduled Service Pattern
PowerManager and WakeLocks
JobScheduler
Accessing Location-Based Services
The Fused Location Provider
Working with the Clipboard
Telephony
Working With SMS
NFC
Device Administration
Basic Use of Sensors
Printing and Document Generation
Basic Bluetooth RFCOMM
xlvii

PREFACE
• Dealing with Different Hardware

Integration and Introspection
•
•
•
•
•
•
•
•
•

Writing and Using Parcelables
Responding to URLs
App Shortcuts
Plugin Patterns
PackageManager Tricks
Remote Services and the Binding Pattern
Advanced Manifest Tips
Miscellaneous Integration Tips
Replacing App Code Dynamically

Other Tools
•
•
•
•
•
•
•
•
•

Android Studio Dialogs and Editors
Advanced Emulator Capabilities
Lint and the Support Annotations
Inspecting Layouts
Screenshots and Screencasts
ADB Tips and Tricks
Stetho
Finding CPU Bottlenecks
Finding Memory Leaks

Tuning Android Applications
•
•
•
•
•
•
•
•
•
•
•
•

Issues with Speed
Finding CPU Bottlenecks
NDK
Improving CPU Performance in Java
Finding and Eliminating Jank
Issues with Bandwidth
Focus On: TrafficStats
Measuring Bandwidth Consumption
Being Smarter About Bandwidth
Issues with Application Heap
Finding Memory Leaks
Issues with System RAM
xlviii

PREFACE
•
•
•
•

Issues with Battery Life
Other Power Measurement Options
Sources of Power Drain
Addressing Application Size Issues

Miscellaneous Topics
•
•
•
•

Crash Reporting with ACRA
JVM Scripting Languages
In-App Diagnostics
Anti-Patterns

Widget Catalog
•
•
•
•
•
•
•
•
•
•

AdapterViewFlipper
CalendarView
DatePicker
ExpandableListView
SeekBar
SlidingDrawer
StackView
TabHost
TimePicker
ViewFlipper

Device Catalog
•
•
•
•
•
•

Chrome and Chrome OS
Android Things Basics
BlackBerry
Google TV
Amazon Fire TV
Samsung DeX

Appendices
• Appendix A: CWAC Libraries
• Appendix B: O Developer Preview
• Appendix C: Community Theater and the Appinars

xlix

PREFACE

About the Updates
This book is updated frequently, typically every 6-8 weeks.
Each release has notations to show what is new or changed compared with the
immediately preceding release:
• The Table of Contents shows sections with changes in bold-italic font
• Those sections have changebars on the right to denote specific paragraphs
that are new or modified

What’s New in Version 8.9?
For those of you who have read previous editions of this book, here are some of the
highlights of what is new in the prose in Version 8.9.
In this update, I:
• Added a new chapter on basic Bluetooth RFCOMM communications.
• Restored the chapter on Android Things (which had been pulled from
Version 8.8) and updated it to DP 6.1, including the use of the Android
Things Console.
• “Mainstreamed” about a third of the material from the Android 8.0
appendix into long-term homes in the other chapters. In particular, the
chapters on notifications wound up with a significant overhaul to
accommodate notification channels.
• Updated the MapsV2 samples to 11.6.2, including getting rid of the license
notification requirements.
• Added a section on the Android Test Orchestrator, which did not involve
timpani, much to my disappointment.
• Updated the chapter on working with the camera for the latest versions of
CameraKit-Android (now under new management!) and Fotoapparat.
• Fixed a variety of errata
• Bulk-replaced various onCreate() methods on activities, that formerly took
a Bundle parameter named icicle, to have the Bundle named state instead

Warescription
You (hopefully) are reading this digital book by means of a Warescription.
l

PREFACE
The Warescription entitles you, for the duration of your subscription, to digital
editions of this book and its updates, in PDF, EPUB, and Kindle (MOBI/KF8)
formats. You also have access to a version of the book as its own Android APK file,
complete with high-speed full-text searching. You also have access to other titles
that CommonsWare may publish during that subscription period.
Each subscriber gets personalized editions of all editions of each title. That way,
your books are never out of date for long, and you can take advantage of new
material as it is made available. For example, when new releases of the Android SDK
are made available, this book will be quickly updated to be accurate with changes in
the APIs.
However, you can only download the books while you have an active Warescription.
There is a grace period after your Warescription ends: you can still download the
book until the next book update comes out after your Warescription ends. After
that, you can no longer download the book. Hence, please download your
updates as they come out. You can find out when new releases of this book are
available via:
1. The CommonsWare Twitter feed
2. The CommonsBlog
3. The Warescription newsletter, which you can subscribe to off of your
Warescription page
4. Just check back on the Warescription site every month or two
Subscribers also have access to other benefits, including:
• “Office hours” — online chats to help you get answers to your Android
application development questions. You will find a calendar for these on
your Warescription page.
• A Stack Overflow “bump” service, to get additional attention for a question
that you have posted there that does not have an adequate answer.
• A discussion board for asking arbitrary questions about Android app
development

About the APK Edition
In addition to classic digital book formats (PDF, EPUB, MOBI/Kindle), this book is
available as an Android app, in the form of an APK file. This app has an integrated

li

PREFACE
digital book reader, showing you the same contents as you would find in the EPUB
version of the book. However, it has a few features that are unique.
First, it has a very fast full-text-search index built in. You can quickly search for
keywords, class names, and the like, with sub-second response time on most
Android hardware. You can even use boolean search clauses (e.g., search on
encryption OR decryption).
Second, it has Community Theater, where you can view appinars, or app-based
training modules. These are presentations, complete with slides, videos, screencasts,
source code, and more. Through Community Theater, you can view available
appinars, download those of interest, and watch them when you want.
The APK edition of the book reader works on Android 4.0.3 and higher, though the
Community Theater portion only works on Android 4.4 and higher.
Installation instructions for the APK edition can be found on the CommonsWare
Web site. Details about using Community Theater can be found in an appendix of
this book.

Book Bug Bounty
Find a problem in the book? Let CommonsWare know!
Be the first to report a unique concrete problem in the current digital edition, and
CommonsWare will extend your Warescription by six months as a bounty for
helping CommonsWare deliver a better product.
By “concrete” problem, we mean things like:
1. Typographical errors
2. Sample applications that do not work as advertised, in the environment
described in the book
3. Factual errors that cannot be open to interpretation
By “unique”, we mean ones not yet reported. Be sure to check the book’s errata page,
though, to see if your issue has already been reported. One coupon is given per
email containing valid bug reports.
We appreciate hearing about “softer” issues as well, such as:

lii

PREFACE
1. Places where you think we are in error, but where we feel our interpretation
is reasonable
2. Places where you think we could add sample applications, or expand upon
the existing material
3. Samples that do not work due to “shifting sands” of the underlying
environment (e.g., changed APIs with new releases of an SDK)
However, those “softer” issues do not qualify for the formal bounty program.
The Book Bug Bounty also extends to the appinars that you view in the Community
Theater portion of the APK edition of the book. Typos and similar concrete issues in
an appinar will qualify. Be sure to point out which appinar it is and what slide (or
code, screenshot, video, etc.) has the problem.
In addition, the Book Bug Bounty covers reproducible bugs in the APK itself. If you
are having problems using the APK, due to crashes or some other problem, be sure
to let us know, with sufficient steps to reproduce the problem (including
information about the device that you are using, such as the Android OS version).
Questions about the bug bounty, or problems you wish to report for bounty
consideration, should be sent to bounty@commonsware.com.

Source Code and Its License
The source code samples shown in this book are available for download from the
book’s GitHub repository. All of the Android projects are licensed under the Apache
2.0 License, in case you have the desire to reuse any of it.
If you wish to use the source code from the GitHub repository, please follow the
instructions on that repository’s home page for details of how to use the projects in
various development environments, notably Android Studio.
Copying source code directly from the book, in the PDF editions, works best with
Adobe Reader, though it may also work with other PDF viewers. Some PDF viewers,
for reasons that remain unclear, foul up copying the source code to the clipboard
when it is selected.

liii

PREFACE

Creative Commons and the Four-to-Free (42F)
Guarantee
Each CommonsWare book edition will be available for use under the Creative
Commons Attribution-Noncommercial-ShareAlike 3.0 license as of the fourth
anniversary of its publication date, or when 4,000 copies of the edition have been
sold, whichever comes first. That means that, once four years have elapsed (perhaps
sooner!), you can use this prose for non-commercial purposes. That is our Four-toFree Guarantee to our readers and the broader community. For the purposes of this
guarantee, new Warescriptions and renewals will be counted as sales of this edition,
starting from the time the edition is published.
This edition of this book will be available under the aforementioned Creative
Commons license on 1 December 2021. Of course, watch the CommonsWare Web
site, as this edition might be relicensed sooner based on sales.
For more details on the Creative Commons Attribution-Noncommercial-ShareAlike
3.0 license, visit the Creative Commons Web site
Note that future editions of this book will become free on later dates, each four years
from the publication of that edition or based on sales of that specific edition.
Releasing one edition under the Creative Commons license does not automatically
release all editions under that license.

Acknowledgments
I would like to thank the Android team, not only for putting out a good product, but
for invaluable assistance on the Android Google Groups and Stack Overflow.
I would also like to thank the thousands of readers of past editions of this book, for
their feedback, bug reports, and overall support.
Of course, thanks are also out to the overall Android ecosystem, particularly those
developers contributing their skills to publish libraries, write blog posts, answer
support questions, and otherwise contribute to the strength of Android.
Portions of this book are reproduced from work created and shared by the Android
Open Source Project and used according to terms described in the Creative
Commons 2.5 Attribution License.
liv

Core Chapters

Key Android Concepts

No doubt, you are in a hurry to get started with Android application development.
After all, you are reading this book, aimed at busy coders.
However, before we dive into getting tools set up and starting in on actual
programming, it is important that we “get on the same page” with respect to several
high-level Android concepts. This will simplify further discussions later in the book.

Android Applications
This book is focused on writing Android applications. An application is something
that a user might install from the Play Store or otherwise download to their device.
That application should have some user interface, and it might have other code
designed to work in the background (multi-tasking).
This book is not focused on modifications to the Android firmware, such as writing
device drivers. For that, you will need to seek other resources.
This book assumes that you have some hands-on experience with Android devices,
and therefore you are familiar with buttons like HOME and BACK, the built-in
Settings application, the concept of a home screen and launcher, and so forth. If you
have never used an Android device, you are strongly encouraged to get one (new or
used) and spend some time with it before starting in on learning Android
application development.

1

KEY ANDROID CONCEPTS

Programming Language
The vast majority of Android applications are written exclusively in Java. Hence, that
is what this book will spend most of its time on and will demonstrate with a
seemingly infinite number of examples.
However, there are other options:
• You can write parts of the app in C/C++, for performance gains, porting over
existing code bases, etc.
• You can write an entire app in C/C++, mostly for games using OpenGL for
3D animations
• You can write the guts of an app in HTML, CSS, and JavaScript, using tools
to package that material into an Android application that can be distributed
through the Play Store and similar venues
• And so on
Some of this will be covered later in the book, but the vast majority of this book is
focused on Java-based app development.
The author assumes that you know Java at this point. If you do not, you will need to
learn Java before you go much further. You do not need to know everything about
Java, as Java is vast. Rather, focus on:
•
•
•
•
•
•
•
•
•
•
•
•

Language fundamentals (flow control, etc.)
Classes and objects
Methods and data members
Public, private, and protected
Static and instance scope
Exceptions
Threads
Collections
Generics
File I/O
Reflection
Interfaces

The links are to Wikibooks material on those topics, though there are countless
other Java resources for you to consider.

2

KEY ANDROID CONCEPTS
Google also supports Kotlin as a programming language for Android apps. Kotlin
can be used as a replacement for Java. While Kotlin has plenty of benefits, it is also a
relatively new programming language. This book is focused on the Android SDK,
more so than on Java (or Kotlin), and so regardless of which of those two languages
you use, the material in this book will be relevant. This book’s examples are mostly
in Java, due to that being the dominant Android app development language today.

Components
When you first learned Java — whether that was yesterday or back when dinosaurs
roamed the Earth — you probably started off with something like this:
class SillyApp {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}

In other words, the entry point into your application was a public static void
method named main() that took a String array of arguments. From there, you were
responsible for doing whatever was necessary.
However, there are other patterns used elsewhere in Java. For example, you do not
usually write a main() method when writing a Java servlet. Instead, you extend a
particular class supplied by a framework (e.g., HttpServlet) to create a component,
then write some metadata that enumerates your components and tell the framework
when and how to use them (e.g., WEB.XML).
Android apps are closer in spirit to the servlet approach. You will not write a
public static void main() method. Instead, you will create subclasses of some
Android-supplied base classes that define various application components. In
addition, you will create some metadata that tells Android about those subclasses.
There are four types of components, all of which will be covered extensively in this
book:
Activities
The building block of the user interface is the activity. You can think of an activity as
being the Android analogue for the window or dialog in a desktop application, or
the page in a classic Web app. It represents a chunk of your user interface and, in
3

KEY ANDROID CONCEPTS
some cases, a discrete entry point into your app (i.e., a way for other apps to link to
your app).
Normally, an activity will take up most of the screen, leaving space for some
“chrome” bits like the clock, signal strength indicators, and so forth.
However, bear in mind that on some devices, the user will be able to work with more
than one activity at a time, such as split-screen mode on a phone or tablet. So, while
it is easy to think of activities as being equivalent to the screen, just remember that
this is a simplification, and that reality is more complicated (as reality often is).
Services
Activities are short-lived and can be shut down at any time, such as when the user
presses the BACK button. Services, on the other hand, are designed to keep running,
if needed, independent of any activity, for a moderate period of time. You might use
a service for checking for updates to an RSS feed, or to play back music even if the
controlling activity is no longer operating. You will also use services for scheduled
tasks (akin to Linux or macOS “cron jobs”) and for exposing custom APIs to other
applications on the device, though the latter is a relatively advanced capability.
Content Providers
Content providers provide a level of abstraction for any data stored on the device
that is accessible by multiple applications. The Android development model
encourages you to make your own data available to other applications, as well as
your own — building a content provider lets you do that, while maintaining a degree
of control over how your data gets accessed.
So, for example, if you have a PDF file that you downloaded on behalf of the user,
and you want to allow the user to view that PDF file, you might create a content
provider to make that PDF file available to other apps. You can then start up an
activity that will be able to view that PDF, where Android and the user will
determine what PDF-viewing activity handles that request.
Broadcast Receivers
The system, or applications, will send out broadcasts from time to time, for
everything from the battery getting low, to when the screen turns off, to when

4

KEY ANDROID CONCEPTS
connectivity changes from WiFi to mobile data. A broadcast receiver can arrange to
listen for these broadcasts and respond accordingly.

Widgets, Containers, and Resources
Most of the focus on Android application development is on the UI layer and
activities. Most Android activities use what is known as “the widget framework” for
rendering their user interface, though you are welcome to use the 2D (Canvas) and
3D (OpenGL) APIs as well for more specialized GUIs.
In Android terms, a widget is the “micro” unit of user interface. Fields, buttons,
labels, lists, and so on are all widgets. Your activity’s UI, therefore, is made up of one
or more of these widgets. This is a common approach in most UI toolkits, and so
most likely you have already worked with buttons, labels, fields, and similar sorts of
widgets somewhere else previously.
If you have more than one widget — which is fairly typical — you will need to tell
Android how those widgets are organized on the screen. To do that, you will use
various container classes referred to as layout managers. These will let you put
things in rows, columns, or more complex arrangements as needed.
To describe how the containers and widgets are connected, you will typically create a
layout resource file. Resources in Android refer to things like images, strings, and
other material that your application uses but is not in the form of some
programming language source code. UI layouts are another type of resource. You will
create these layouts either using a structured tool, such as an IDE’s drag-and-drop
GUI builder, or by hand in XML form.
Sometimes, your UI will work across all sorts of devices: phones, tablets, televisions,
etc. Sometimes, your UI will need to be tailored for different environments. You will
be able to put resources into resource sets that indicate under what circumstances
those resources can be used (e.g., use these for normal-sized screens, but use those
for larger screens).
We will be examining all of these concepts, in much greater detail, as we get deeper
into the book.

5

KEY ANDROID CONCEPTS

Apps and Packages
Given a bucket of source code and a basket of resources, the Android build tools will
give you an application as a result. The application comes in the form of an APK file.
It is that APK file that you will upload to the Play Store or distribute by other means.
Each Android application has a package name, also referred to as an application ID.
A package name must fulfill three requirements:
1. It must be a valid Java package name, as some Java source code will be
generated by the Android build tools in this package
2. No two applications can exist on a device at the same time with the same
application ID
3. No two applications can be uploaded to the Play Store having the same
application ID
When you create your Android project — the repository of that source code and
those resources — you will declare what package name is to be used for your app.
Typically, you will pick a package name following the Java package name “reverse
domain name” convention (e.g., com.commonsware.android.foo). That way, the
domain name system ensures that your package name prefix (com.commonsware) is
unique, and it is up to you to ensure that the rest of the package name distinguishes
one of your apps from any other.

Android Devices
There are well in excess of one billion Android devices in use today, representing
thousands of different models from dozens of different manufacturers. Android
itself has evolved since Android 1.0 in 2008. Between different device types and
different Android versions, many a media pundit has lobbed the term
“fragmentation” at Android, suggesting that creating apps that run on all these
different environments is impossible.
In reality, it is not that bad. Some apps will have substantial trouble, but most apps
will work just fine if you follow the guidance presented in this book and in other
resources.

6

KEY ANDROID CONCEPTS

Types
Android devices come in all shapes, sizes, and colors. However, there are three
dominant “form factors”:
• the phone
• the tablet
• the notebook (mostly, these run Chrome OS, which has some support for
Android apps)
Beyond that, there are several less-common form factors
• the television (TV)
• the wearable (smart watches, etc.)
• the desktop (a device designed to be plugged into a monitor, keyboard, and
mouse)
You will often hear developers and pundits refer to these form factors, and this book
will do so from time to time as well. However, it is important that you understand
that Android has no built-in concept of a device being a “phone” or a “tablet” or a
“TV”. Rather, Android distinguishes devices based on capabilities and features. So,
you will not see an isPhone() method anywhere, though you can ask Android:
• what is the screen size?
• does the device have telephony capability?
• etc.
Similarly, as you build your applications, rather than thinking of those form factors,
focus on what capabilities and features you need. Not only will this help you line up
better with how Android wants you to build your apps, but it will make it easier for
you to adapt to other form factors that will come about such as:
• airplane seat-back entertainment centers
• in-car navigation and entertainment devices
• and so on

The Emulator
While there are ~2 billion Android devices representing ~10,000 device models,
probably you do not have one of each model. You may only have a single piece of

7

KEY ANDROID CONCEPTS
Android hardware. And if you do not even have that, you most certainly will want to
acquire one before trying to publish an Android app.
To help fill in the gaps between the devices you have and the devices that are
possible, the Android developer tools ship an emulator. The emulator behaves like a
piece of Android hardware, but it is a program you run on your development
machine. You can use this emulator to emulate many different devices, with
different screen sizes and Android OS versions, by creating one or more Android
virtual devices, or AVDs.
In an upcoming chapter, we will discuss how you install the Android developer tools
and how you will be able to create these AVDs and run the emulator.

OS Versions and API Levels
Android has come a long way since the early beta releases from late 2007. Each new
Android OS version adds more capabilities to the platform and more things that
developers can do to exploit those capabilities.
Moreover, the core Android development team tries very hard to ensure forwards
and backwards compatibility. An app you write today should work unchanged on
future versions of Android (forwards compatibility), albeit perhaps missing some
features or working in some sort of “compatibility mode”. And there are well-trod
paths for how to create apps that will work both on the latest and on previous
versions of Android (backwards compatibility).
To help us keep track of all the different OS versions that matter to us as developers,
Android has API levels. A new API level is defined when an Android version ships
that contains changes that affect developers. When you create an emulator AVD to
test your app, you will indicate what API level that emulator should emulate. When
you distribute your app, you will indicate the oldest API level your app supports, so
the app is not installed on older devices.
At the time of this writing, the API levels of significance to most Android developers
are:
•
•
•
•
•

API Level 19 (Android 4.4)
API Level 21 (Android 5.0)
API Level 22 (Android 5.1)
API Level 23 (Android 6.0)
API Level 24 (Android 7.0)
8

KEY ANDROID CONCEPTS
Here, “of significance” refers to API levels that have a reasonable number of Android
devices — 5% or more, as reported by the “Platform Versions” dashboard chart.
The latest version of Android is 8.1, API Level 27.
Note that API Level 20 was used for the version of Android 4.4 running on the firstgeneration Android Wear devices. Unless you are specifically developing apps for
Wear, you will not be worrying much about API Level 20.

Dalvik and ART
In terms of Android, Dalvik and ART are virtual machines (VM)s. Virtual machines
are used by many programming languages, such as Java, Perl, and Smalltalk. Dalvik
and ART are designed to work much like a Java VM, but optimized for embedded
Linux environments.
Primarily, the difference between the two is that ART is used on Android 5.0 and
higher, while Dalvik was used on older devices. In truth, the story is more
complicated than this, but this will do for now.
So, what really goes on when somebody writes an Android application is:
1. Developers write Java-syntax source code, leveraging class libraries published
by the Android project and third parties.
2. Developers compile the source code into Java VM bytecode, using the javac
compiler that comes with the Java SDK.
3. Developers translate the Java VM bytecode into Dalvik VM bytecode, which
is packaged with other files into a ZIP archive with the .apk extension (the
APK file).
4. An Android device or emulator runs the APK file, causing the bytecode to be
executed by an instance of a Dalvik or ART VM.
From your standpoint, most of this is hidden by the build tools. You pour Java source
code into the top, and the APK file comes out the bottom.
However, there will be places from time to time where the differences between the
Dalvik VM and the traditional Java VM will affect application developers, and this
book will point out some of them where relevant.

9

KEY ANDROID CONCEPTS

Processes and Threads
When your application runs, it will do so in its own process. This is not significantly
different than any other traditional operating system. Part of Dalvik’s magic is
making it possible for many processes to be running many Android applications at
one time without consuming ridiculous amounts of RAM.
Android will also set up a batch of threads for running your app. The thread that
your code will be executed upon, most of the time, is variously called the “main
application thread” or the “UI thread”. You do not have to set it up, but, as we will
see later in the book, you will need to pay attention to what you do and do not do on
that thread. You are welcome to fork your own threads to do work, and that is fairly
common, though in some places Android handles that for you behind the scenes.

Don’t Be Scared
Yes, this chapter threw a lot of terms at you. We will be going into greater detail on
all of them in this book. However, Android is like a jigsaw puzzle with lots of
interlocking pieces. To be able to describe one concept in detail, we will need to at
least reference some of the others. Hence, this chapter was meant to expose you to
terms, in hopes that they will sound vaguely familiar as we dive into the details.

10

Choosing Your Development
Toolchain

Before you go much further in your Android endeavors (or possibly endeavours,
depending upon your preferred spelling), you will need to determine what
toolchain you will use to build your Android applications.

Android Studio
The current Google-backed Android IDE is Android Studio. Based on IntelliJ IDEA,
Android Studio is the new foundation of Google’s efforts to give Android developers
top-notch development tools.
The next chapter contains a section with instructions on how to set up Android
Studio.
Note, though, that Android Studio requires a fairly powerful development machine
to work well: a fast CPU, lots of RAM (8GB or more), and an SSD are all strongly
recommended.

Eclipse
Eclipse is also a popular IDE, particularly for Java development. Eclipse was Google’s
original IDE for Android development, by means of the Android Developer Tools
(ADT) add-in, which gives the core of Eclipse awareness of Android. The ADT addin, in essence, takes regular Eclipse operations and extends them to work with
Android projects.

11

CHOOSING YOUR DEVELOPMENT TOOLCHAIN
Note, though, that Google has discontinued maintenance of ADT. The Eclipse
Foundation is setting up the “Andmore” project to try to continue work on allowing
Eclipse to build Android apps. This book does not cover the Andmore project at this
time, and developers are strongly encouraged to not use the ADT-enabled Eclipse
from Google.

IntelliJ IDEA
While Android Studio is based on IntelliJ IDEA, you can still use the original IntelliJ
IDEA for Android app development. A large subset of the Android Studio
capabilities are available in the Android plugin for IDEA. Plus, the commercial IDEA
Ultimate Edition will go beyond Android Studio in many areas outside of Android
development.
In particular, if you are looking for “the one true IDE” that you can use for Android
and non-Android projects, you should consider IntelliJ IDEA. Android Studio is
nice, but it is mostly for Android projects.

Command-Line Builds via Gradle
And, of course, you do not need to use an IDE at all. While this may sound
sacrilegious to some, IDEs are not the only way to build applications. Much of what
is accomplished via an IDE can be accomplished through command-line equivalents,
meaning a shell and an editor is all you truly need.
The recommended way to build Android apps outside of an IDE is by means of
Gradle. Google has published a Gradle plugin that teaches Gradle how to build
Android apps. Android Studio itself uses Gradle for its builds, so a single build
configuration (e.g., build.gradle files) can be used both from an IDE and from a
build automation tool like a continuous integration server.
An upcoming chapter gets into more about what Gradle (and the Android Gradle
Plugin) are all about.

Yet Other Alternatives
Other IDEs have their equivalents of the ADT, albeit with minimal assistance from
Google. For example, NetBeans has support via the NBAndroid add-on, and
reportedly this has advanced substantially in the past few years.
12

CHOOSING YOUR DEVELOPMENT TOOLCHAIN
You will also hear reference to using Apache Ant for doing command-line builds of
Android apps. This has been supplanted by the Android Gradle Plugin at this time,
and there is little support for Apache Ant anymore. Newcomers to Android are
encouraged to not invest time in new work with Apache Ant for Android
development projects.

IDEs… And This Book
You are encouraged to use Android Studio as you work through this book. You are
welcome to use another IDE if you wish. You are even welcome to skip the IDE
outright and just use an editor.
This book is focused primarily on demonstrating Android capabilities and the APIs
for exploiting those capabilities. Hence, the sample code will work with any IDE.
However, this book will cover some Android Studio-specific instructions, since that
is the predominant Android IDE in use today.

What We Are Not Covering
In the beginning (a.k.a., 2007), we were lucky to have any means of creating an
Android app.
Nowadays, there seems to be no end to the means by which we can create an
Android app.
There are a few of these “means”, though, that are specifically out of scope for this
book.

App Inventor
You may also have heard of a tool named App Inventor and wonder where it fits in
with all of this.
App Inventor was originally created by an education group within Google, as a
means of teaching students how to think about programming constructs (branches,
loops, etc.) and create interesting output (Android apps) without classic
programming in Java or other syntax-based languages. App Inventor is purely dragand-drop, both of widgets and application logic, the latter by means of “blocks” that
snap together to form logic chains.

13

CHOOSING YOUR DEVELOPMENT TOOLCHAIN
App Inventor was donated by Google to MIT, which has recently re-opened it to the
public.
However, App Inventor is a closed system — at the present time, it does not
somehow generate Java code that you can later augment. That limits you to whatever
App Inventor is natively capable of doing, which, while impressive in its own right,
offers a small portion of the total Android SDK capabilities.

App Generators
There are a seemingly infinite number of “app generators” available as online
services. These are designed mostly for creating apps for specific vertical markets,
such as apps for restaurants or apps for grocers. The resulting apps are mostly
“brochure-ware”, with few capabilities beyond a mobile Web site, yet still requiring
the user to find, download, and install the app. Few of these generators provide the
source code to the generated app, to allow the apps to be customized beyond what
the generator generates.

14

Tutorial #1 - Installing the Tools

Now, let us get you set up with the pieces and parts necessary to build an Android
app.
NOTE: The instructions presented here are accurate as of the time of this writing.
However, the tools change rapidly, and so these instructions may be out of date by
the time you read this. Please refer to the Android Developers Web site for current
instructions, using this as a base guideline of what to expect.

But First, Some Notes About Android’s Emulator
The Android tools include an emulator, a piece of software that pretends to be an
Android device. This is very useful for development — not only does it mean you
can get started on Android without a device, but the emulator can help test device
configurations that you do not own.
There are two types of emulator: x86 and ARM. These are the two major types of
CPUs used for Android devices. You really want to be able to use the x86 emulator,
as the ARM emulator is extremely slow.
However, to use the x86 emulator, your development machine must have things set
up properly first. Linux users need KVM, while Mac and Windows users need the
“Intel Hardware Accelerated Execution Manager” (a.k.a., HAXM).
Also, this only works for certain CPU architectures, ones that support virtualization
in hardware:
• Intel Virtualization Technology (VT, VT-x, vmx) extensions
• AMD Virtualization (AMD-V, SVM) extensions (Linux only)
15

TUTORIAL #1 - INSTALLING THE TOOLS
Those virtualization extensions must also be enabled in your device’s BIOS, and
other OS-specific modifications may be required.
Also, at least for newer API levels, your CPU must support SSSE3 extensions, though
the details of this requirement are not documented as of October 2017.
Part of the Android Studio installation process will try to set you up to be able to use
the x86 emulator. Make note of any messages that you see in the installation wizard
regarding “HAXM” (or, if you are running Linux, KVM), as those will be important
later.

Step #1: Checking Your Hardware
Compiling and building an Android application, on its own, can be a hardwareintensive process, particularly for larger projects. Beyond that, your IDE and the
Android emulator will stress your development machine further. Of the two, the
emulator poses the bigger problem.
The more RAM you have, the better. 8GB or higher is a very good idea if you intend
to use an IDE and the emulator together. If you can get an SSD for your data storage,
instead of a conventional hard drive, that too can dramatically improve the IDE
performance.
A faster CPU is also a good idea. The Android SDK emulator, as of 2016, supports
CPUs with multiple cores — previously, it only supported a single core. However,
other processes on your development machine will be competing with the emulator
for CPU time, and so the faster your CPU is, the better off you will be. Ideally, your
CPU has 2 to 4 cores, each 2.5GHz or faster at their base speed.
Beyond that, to use the x86 emulator — the emulator that runs well — you need a
CPU with certain features:
Development
OS
Windows
Mac
Linux

CPU Requirements
an Intel CPU with support for VT-x, EM64T, and “Execute Disable”
(XD)
any
an Intel CPU with support for VT-x, EM64T, and “Execute Disable”
(XD), or an AMD CPU with support for AMD-V

16

TUTORIAL #1 - INSTALLING THE TOOLS
If your CPU does not meet those requirements, you will want to have 1+ Android
devices available to you, so that you can test on hardware.
Also, if you are running Windows or Linux, you need to ensure that your computer’s
BIOS is set up to support Intel’s virtualization extensions. Unfortunately, many PC
manufacturers disable this by default. The details of how to get into your BIOS
settings will vary by PC, but usually it involves rebooting your computer and
pressing some function key on the initial boot screen. In the BIOS settings, you are
looking for references to “virtualization” or “VT-x”. Enable them if they are not
already enabled. macOS machines come with virtualization extensions pre-enabled.

Step #2: Setting Up Java and 32-Bit Linux Support
When you write Android applications, you typically write them in Java source code.
That Java source code is then turned into the stuff that Android actually runs
(Dalvik bytecode in an APK file).
Android Studio, starting with version 2.2, ships with its own private copy of
OpenJDK 8, and it will use that by default. You are welcome to install and use your
own JDK if you wish, though ideally it is for Java 8.
If your development OS is Linux, make sure that you can run 32-bit Linux binaries.
This may or may not already be enabled in your Linux distro. For example, on
Ubuntu 14.10, you may need to run the following to get the 32-bit binary support
installed that is needed by the Android build tools:
sudo apt-get install lib32z1 lib32ncurses5 lib32stdc++6

You may also need lib32bz2-1.0, depending on your version of Linux.

Step #3: Install Android Studio
As noted in the previous chapter, there are a few developer tools that you can choose
from.
This book’s tutorials focus on Android Studio. You are welcome to attempt to use
Eclipse, another IDE, or no IDE at all for building Android apps. However, you will
need to translate some of the tutorials’ IDE-specific instructions to be whatever is
needed for your development toolchain of choice.

17

TUTORIAL #1 - INSTALLING THE TOOLS
At the time of this writing, the current production version of Android Studio is 3.0.0,
and this book covers that version. If you are reading this in the future, you may be
on a newer version of Android Studio, and there may be some differences between
what you have and what is presented here.
You have two major download options. You can get the latest shipping version of
Android Studio from the Android Studio download page.

Figure 1: Android Studio Download Page
Or, you can download Android Studio 3.0.1 — the version used in this edition of
this book — directly, for:
• Windows
• macOS
• Linux
Windows users can download a self-installing EXE, which will add suitable launch
options for you to be able to start the IDE.
macOS users can download a DMG disk image and install it akin to other macOS
software, dragging the Android Studio icon into the Applications folder.
Linux users (and power Windows users) can download a ZIP file, then unZIP it to
some likely spot on your hard drive. Android Studio can then be run from the
studio batch file or shell script from your Android Studio installation’s bin/
directory.
18

TUTORIAL #1 - INSTALLING THE TOOLS

Step #4: Install the SDKs and Add-Ons
Next, we need to review what pieces of the Android SDK we have already and
perhaps install some new items. To do that, you need to access the SDK Manager.
When you first run Android Studio, you may be asked if you want to import settings
from some other prior installation of Android Studio:

Figure 2: Android Studio First-Run Settings Migration Dialog
For most users, particularly those using Android Studio for the first time, the “I do
not have…” option is the correct choice to make.
Then, after a short splash screen and a potentially long “Finding Available SDK
Components” progress dialog, you will be taken to the Android Studio Setup
Wizard:

19

TUTORIAL #1 - INSTALLING THE TOOLS

Figure 3: Android Studio Setup Wizard, First Page
Just click “Next” to advance to the second page of the wizard:

20

TUTORIAL #1 - INSTALLING THE TOOLS

Figure 4: Android Studio Setup Wizard, Second Page
Here, you have a choice between “Standard” and “Custom” setup modes. Most likely,
right now, the “Standard” route will be fine for your environment.
If you go the “Standard” route and click “Next”, you should be taken to a wizard page
where you can choose your UI theme:

21

TUTORIAL #1 - INSTALLING THE TOOLS

Figure 5: Android Studio Setup Wizard, UI Theme Page
Choose whichever you like, then click Next, to go to a wizard page to verify what will
be downloaded and installed:

22

TUTORIAL #1 - INSTALLING THE TOOLS

Figure 6: Android Studio Setup Wizard, Verify Settings Page
Clicking Next may take you to a wizard page explaining some information about the
Android emulator:

23

TUTORIAL #1 - INSTALLING THE TOOLS

Figure 7: Android Studio Setup Wizard, Emulator Info Page
What is explained on this page may not make much sense to you. That is perfectly
normal, and we will get into what this page is trying to say later in the book. Just
click “Finish” to begin the setup process. This will include downloading a copy of the
Android SDK and installing it into a directory adjacent to where Android Studio
itself is installed.
When that is done, after clicking “Finish”, Android Studio will busily start
downloading stuff to your development machine. If you are running Linux, and your
installation crashes with an “Unable to run mksdcard SDK tool” error, go back to
Step #2 and set up 32-bit support on your Linux environment.
Clicking “Finish” will then take you to the Android Studio Welcome dialog:

24

TUTORIAL #1 - INSTALLING THE TOOLS

Figure 8: Android Studio Welcome Dialog
Then, in the welcome dialog, click Configure, to bring up a configuration drop-down
list:

Figure 9: Android Studio Welcome Dialog, Configure Drop-Down List
There, tap on SDK Manager to bring up the SDK Manager.

25

TUTORIAL #1 - INSTALLING THE TOOLS

Using SDK Manager and Updating Your Environment
You should now have the SDK Manager open, as part of the overall default settings
for Android Studio:

Figure 10: Android SDK Manager, “SDK Platforms” Tab
The “SDK Platforms” tab lists the versions of Android that you can compile against.
The latest version of Android (or possibly a preview edition) is usually installed
when you set up Android Studio initially. However, for the tutorials, please also
check “Android 7.1 (Nougat)” in the list if it is not already checked, and then click
the “Apply” button to download and install those versions. You may need to accept a
license confirmation dialog as part of this process — review the license, and if you
accept it, click Next to begin the download:

26

TUTORIAL #1 - INSTALLING THE TOOLS

Figure 11: Android SDK Manager, License Confirmation Dialog
When that has completed, you can click “Finish” to close up the download dialog,
and then you will be returned to the SDK Manager. Then, you can close up the SDK
Manager by clicking the OK button.

In Our Next Episode…
… we will create an Android project that will serve as the basis for all our future
tutorials, plus set up our emulator and device.

27

Android and Projects

When you work on creating an app for Android, you will do so by working in a
“project”. The project is a directory containing your source code and other files, like
images and UI definitions. Your IDE or other build tools will take what is in your
project and generate an Android app (APK) as output.
The details of how you get started with a project vary based upon what IDE you are
using, so this chapter goes through the various possibilities.

Projects and Android Studio
With Android Studio, to work on a project, you can either create a new project from
scratch, you can copy an existing Android Studio project to a new one, or you can
import an existing Android project into Android Studio. The following sections will
review the steps needed for each of these.

Creating a New Project
You can create a project from one of two places:
• If you are at the initial dialog that you first encountered when you opened
Android Studio, choose the “Start a new Android Studio project…” menu
item
• If you are inside the Android Studio IDE itself, choose File > New > New
Project… from the main menu
This brings up the new-project wizard:

29

ANDROID AND PROJECTS

Figure 12: Android Studio Create-Project Wizard, First Page
The first page of the wizard is where you can specify:
• The application name, which is the initial name of your project as seen by
the user, in places like your home screen launcher icon and the list of
installed applications.
• The package name, which refers to a Java package name (e.g.,
com.commonsware.empublite). This package name will be used for
generating some Java source code, and it also is used as a unique identifier of
this package, as was mentioned earlier in this book.
• The directory where you want the project files to go
• Whether you know right now if you will be using C++ or not, as part of the
Android Native Development Kit (NDK)
• Whether you know right now if you will be using Kotlin or not
Nothing that you choose here is permanent; you can revise everything later on if
needed. The most painful to change is the package name, so ideally you choose a
good value up front.
By default, the package name will be made up of two pieces:

30

ANDROID AND PROJECTS
1. The domain name that you specify in the “Company Domain” field
2. The application name, converted into all lowercase with no spaces or other
punctuation
If this is not what you want, click the “Edit” button on the far right side of the
proposed package name, which will now allow you to edit the package name
directly:

Figure 13: Android Studio Create-Project Wizard, First Page, with Editable Package
Name
Clicking “Next” will advance you to a wizard page where you indicate what sort of
project you are creating, in terms of intended device type (phones/tablets, TVs, etc.)
and minimum required SDK level:

31

ANDROID AND PROJECTS

Figure 14: Android Studio Create-Project Wizard, Second Page
The “Minimum SDK” refers to how far back in Android’s version history you are
willing to support. The lower the value you specify here, the more Android devices
can run your app, but the more work you will have to do to test whether your app
really does support those devices.
Developers just starting out on Android should only check “Phone and Tablet” as
the device type, leaving the other checkboxes unchecked. The default “Minimum
SDK” value also usually is a good choice, and it can be changed readily in your
project, as we will see later in the book.
Clicking “Next” advances you to the third page of the wizard, where you can choose
if Android Studio should create an initial activity for you, and if so, based on what
template:

32

ANDROID AND PROJECTS

Figure 15: Android Studio Create-Project Wizard, Third Page
None of these templates are especially good, as they add a lot of example material
that you will wind up replacing. “Empty Activity” is the best of the available options
for first-time Android developers, simply because it adds the least amount of this
“cruft”.
If you choose any option other than “Add No Activity”, clicking “Next” will advance
you to a page in the wizard where you can provide additional details about the
activity to be created:

33

ANDROID AND PROJECTS

Figure 16: Android Studio Create-Project Wizard, Fourth Page
What options appear here will vary based upon the template you chose in the
previous page. Common options include “Activity Name” (the name of the Java class
for your activity) and “Layout Name” (the base name of an XML file that will contain
a UI definition of your activity).
The “Backwards Compatibility (AppCompat)” checkbox indicates if you want to use
a library known as AppCompat. We will discuss using libraries later in the book, as
well as what this “AppCompat” is. Unless you know for certain that you want to use
AppCompat — and few of this book’s example apps do — uncheck this checkbox.
Clicking “Finish” will generate your project files.

Copying a Project
Android Studio projects are simply directories of files, with no special metadata held
elsewhere. Hence, to copy a project, just copy its directory.

Importing a Project
You can import a project from one of two places:
34

ANDROID AND PROJECTS
• If you are at the initial dialog that you first encountered when you opened
Android Studio, choose the “Import Project…” menu item
• If you are inside the Android Studio IDE itself, choose File > New… > Import
Project… from the main menu
Then, choose the directory containing the project to be imported.
What happens now depends upon the nature of the project. If the project was
already set up for use with Android Studio, or at least with the Android Gradle
Plugin, the Android Studio-specific files will be created (or updated) in the project
directory.
However, if the project was not set up for Android Studio (or at least for the Android
Gradle Plugin), but does have Eclipse project files (or at least a project.properties
file), you will be led through an Eclipse import wizard. This will be fairly uncommon
nowadays.

Starter Project Generators
In addition to creating projects through an IDE’s new-project wizard, there are
various Web sites that offer online project generators:
• Android Bootstrap
• Android Kickstartr
On those sites, you provide basic configuration data, such as your application’s
package name, and they generate a complete starter project for you. These projects
tend to be significantly more advanced than what you get from the IDE wizards. On
the plus side, you get a more elaborate “scaffold” on which you can “hang” your own
business logic. However, understanding what those generators create and how to
change the generated code requires a fair bit of Android development experience.

35

Tutorial #2 - Creating a Stub Project

Creating an Android application first involves creating an Android “project”. As with
many other development environments, the project is where your source code and
other assets (e.g., icons) reside. And, the project contains the instructions for your
tools for how to convert that source code and other assets into an Android APK file
for use with an emulator or device, where the APK is Android’s executable file
format.
Hence, in this tutorial, we kick off development of a sample Android application, to
give you the opportunity to put some of what you are learning in this book in
practice.

About Our Tutorial Project
The application we will be building in these tutorials is called EmPubLite. EmPubLite
will be a digital book reader, allowing users to read a digital book like the one that
you are reading right now.
EmPubLite

will be a partial implementation of the EmPub reader used for the APK
version of this book. EmPub itself is a fairly extensive application, so EmPubLite will
have only a subset of its features.
The “Em” of EmPub and EmPubLite stands for “embedded”. These readers are not
designed to read an arbitrary EPUB or MOBI formatted book that you might
download from somewhere. Rather, the contents of the book (largely an unpacked
EPUB file) will be “baked into” the reader APK itself, so by distributing the APK, you
are distributing the book.

37

TUTORIAL #2 - CREATING A STUB PROJECT

About the Rest of the Tutorials
Of course, you may have little interest in writing a digital book reader app.
The tutorials presented in this book are certainly optional. There is no expectation
that you have to write any code in order to get value from the book. These tutorials
are here simply as a way to help those of you who “learn by doing” have an
opportunity to do just that.
Hence, there are any number of ways that you can use these tutorials:
• You can ignore them entirely. That is not the best answer, but you are
welcome to do it.
• You can read the tutorials but not actually do any of the work. This is the
best low-effort answer, as it is likely that you will learn things from the
tutorials that you might have missed by simply reading the non-tutorial
chapters.
• You can follow along the steps and actually build the EmPubLite app.
• You can download the answers from the book’s GitHub repository. There,
you will find one directory per tutorial, showing the results of having done
the steps in that tutorial. For example, you will find a T2-Project/ directory
containing a copy of the EmPubLite sample app after having completed the
steps found in this tutorial. You can import these projects into your IDE,
examine what they contain, cross-reference them back to the tutorials
themselves, and run them.
Any of these are valid options — you will need to choose for yourself what you wish
to do.

About Our Tools
The instructions in the remaining tutorials should be accurate for Android Studio
3.0.x. The instructions may work for other versions of this IDE, but there may also
be some differences.

Step #1: Importing the Project
We need to create the Android project for EmPubLite.

38

TUTORIAL #2 - CREATING A STUB PROJECT
Normally, you would use the new-project wizard to create a new project. However,
the problem with the new-project wizard is that Google keeps changing what the
new-project wizard generates. In most situations, that is not a huge problem.
However, it becomes a problem for tutorials like this one, as if Google changes what
is in the new project, the tutorial’s instructions become out of date.
So, instead, we will import an existing project, so we can start from a stable base.
Visit the releases page of this book’s GitHub repository. Then, scroll down to this
book’s version and download the EmPubLite-Starter.zip file for it. UnZIP that
project to some place on your development machine. It will unZIP into an
EmPubLite/ directory.
Then, import the project. From the Android Studio welcome dialog, that is handled
by the “Import project (Eclipse ADT, Gradle, etc.)” option. From an existing open
Android Studio IDE window, you would use File > New > Import Project… from the
main menu.
Importing a project brings up a typical directory-picker dialog. Pick the EmPubLite/
directory and click OK to begin the import process. This may take a while,
depending on the speed of your development machine. A “Tip of the Day” dialog
may appear, which you can dismiss.
At this point, you should have an empty Android Studio IDE window, probably with
an error message:

39

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 17: Android Studio, As Initially Launched, Showing Error
In the “Messages Gradle Sync” tool pane, towards the bottom of the screen, you may
have a “Failed to find Build Tools revision 25.0.3”. Each Android project states what
version of the development tools it uses, and this one uses a version slightly older
than the current. In that tool pane, the “Install Build Tools 25.0.3 and sync project”
message is a hyperlink — click that to download the missing bits. This is a common
pattern with these error messages, where the message will contain a link to try to fix
the problem.
Next, after several moments, you will get a pop-up dialog like this one:

Figure 18: Android Studio, Update Recommendation Dialog

40

TUTORIAL #2 - CREATING A STUB PROJECT
The trigger for this dialog is similar to the trigger for the preceding error message:
the project that you imported is looking to use some older tools than what is the
latest-and-greatest. For projects that you create yourself from scratch, you will not
get this message, as the new-project wizard always uses the latest tools… even if that
is not always the best idea. For projects like this one, that you import from
elsewhere, this dialog is common. For the purposes of these tutorials, click the
“Don’t remind me again for this project” button. For other projects that you import,
you could opt to click the “Update” button, which will adjust the project to use the
newer tools, though this may cause compatibility problems that you would have to
debug.
The “Project” tool — docked by default on the left side, towards the top — brings up
a way for you to view what is in the project. Android Studio has several ways of
viewing the contents of Android projects. The default one, that you are presented
with when creating or importing the project, is known as the “Android view”:

Figure 19: Android Studio “Android View”
While you are welcome to navigate your project using it, the tutorial chapters in this
book, where they have screenshots of Android Studio, will show the project view:

41

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 20: Android Studio “Project View”
To switch to this view — and therefore match what the tutorials will show you —
click the “Android” entry above the tree, to display a drop-down of different views.
Choose “Project”, and that will switch you to the project view used by these tutorials.

Step #2: Get Ready for the x86 Emulator
Your first decision to make is whether or not you want to bother setting up an
emulator image right now. If you have an Android device, you may prefer to start
testing your app on it, and come back to set up the emulator at a later point. In that
case, skip to Step #4.
Otherwise, here is what you may need to do, based on the operating system on your
development machine.

Windows
If your CPU met the requirements, and you successfully enabled the right things in
your system’s BIOS, the Android Studio installation should have installed HAXM,
and you should be ready to go.
If, on the other hand, you got some error messages in the installation wizard
regarding HAXM, you would need to address those first.

42

TUTORIAL #2 - CREATING A STUB PROJECT

Mac
The wizards of Cupertino set up their Mac hardware to be able to run the Android
x86 emulator, which is awfully nice of them, considering that Android competes
with iOS. The Android Studio installation wizard should have installed HAXM
successfully, and you should be able to continue with the next step of the tutorial.

Linux
The Android x86 emulator on Linux does not use HAXM. Instead, it uses KVM, a
common Linux virtualization engine.
If, during the Android Studio installation process, the wizard showed you a page
that said that you needed to configure KVM, you will need to do just that before you
can set up and use the x86 emulator. The details of how to set up KVM will vary by
Linux distro (e.g., Ubuntu).

Step #3: Set Up the AVD
The Android emulator can emulate one or several Android devices. Each
configuration you want is stored in an “Android virtual device”, or AVD. The AVD
Manager is where you create these AVDs.
Note that Android Studio now has its own implementation of the AVD Manager that
is separate from the one Android developers have traditionally used. You may see
screenshots of the older AVD Manager in blog posts, Stack Overflow answers, and
the like. The AVD Manager still fills the same role, but it has a different look and
feel.
To open the AVD Manager in Android Studio, choose Tools > Android > AVD
Manager from the main menu.
You should be taken to “welcome”-type screen:

43

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 21: Android Studio AVD Manager, Welcome Screen
Click the “Create Virtual Device” button, which brings up a “Virtual Device
Configuration” wizard:

44

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 22: Android Studio Virtual Device Configuration Wizard, First Page
The first page of the wizard allows you to choose a device profile to use as a starting
point for your AVD. The “New Hardware Profile” button allows you to define new
profiles, if there is no existing profile that meets your needs.
Since emulator speeds are tied somewhat to the resolution of their (virtual) screens,
you generally aim for a device profile that is on the low end but is not completely
ridiculous. For example, an 800x480 or 1280x768 phone would be considered by
many people to be fairly low-resolution. However, there are plenty of devices out
there at that resolution (or lower), and it makes for a reasonable starting emulator.
If you want to create a new device profile based on an existing one — to change a
few parameters but otherwise use what the original profile had – click the “Clone
Device” button once you have selected your starter profile.
However, in general, at the outset, using an existing profile is perfectly fine. The
Galaxy Nexus or Nexus 4 images are likely choices to start with.
Clicking “Next” allows you to choose an emulator image to use:

45

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 23: Android Studio Virtual Device Configuration Wizard, Second Page
The emulator images are spread across three tabs:
• “Recommended”
• “x86 Images”
• “Other Images”
For the purposes of the tutorials, you do not need an emulator image with the
“Google APIs” — those are for emulators that have Google Play Services in them and
related apps like Google Maps. However, in terms of API level, you can choose
anything from API Level 15 (Android 4.0.3) on up. You should have one or more
suitable images already set up for you, courtesy of having installed Android Studio.
If you click on the x86 Images tab, you should see some images with a “Download”
link, and others without it:

46

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 24: Android Studio Virtual Device Configuration Wizard, x86 Images
The emulator images with “Download” next to them will trigger a one-time
download of the files necessary to create AVDs for that particular API level and CPU
architecture combination, after another license dialog and progress dialog:

47

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 25: Android Studio Component Installer Dialog, Downloading API 23 ARM
Image
Once you have identified the image(s) that you want — and have downloaded any
that you did not already have — click on one of them in the wizard:

48

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 26: Android Studio Virtual Device Configuration Wizard, After Choosing
Image
Clicking “Next” allows you to finalize the configuration of your AVD:

49

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 27: Android Studio Virtual Device Configuration Wizard, Third Page
A default name for the AVD is suggested, though you are welcome to replace this
with your own value.
Change the AVD name, if necessary, to something valid: only letters, numbers,
spaces, and select punctuation (e.g., ., _, -, (, )) are supported.
The rest of the default values should be fine for now.
Clicking “Finish” will return you to the main AVD Manager, showing your new AVD.
You can then close the AVD Manager window.

Step #4: Set Up the Device
You do not need an Android device to get started in Android application
development. Having one is a good idea before you try to ship an application (e.g.,
upload it to the Play Store). And, perhaps you already have a device – maybe that is
what is spurring your interest in developing for Android.

50

TUTORIAL #2 - CREATING A STUB PROJECT
If you do not have an Android device that you wish to set up for development, skip
this step.
The first step to make your device ready for use with development is to go into the
Settings application on the device. What happens now depends a bit on your
Android version:
• On Android 1.x/2.x, go into Applications, then into Development
• On Android 3.0 through 4.1, go into “Developer options” from the main
Settings screen
• On Android 4.2 and higher, go into About, tap on the build number seven
times, then press BACK, and go into “Developer options” (which was
formerly hidden)

Figure 28: Developer Options, in Settings App
You may need to slide a switch in the upper-right corner of the screen to the “ON”
position to modify the values on this screen.
Generally, you will want to scroll down and enable USB debugging, so you can use
your device with the Android build tools:

51

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 29: Debugging Options, in Settings App
You can leave the other settings alone for now if you wish, though you may find the
“Stay awake” option to be handy, as it saves you from having to unlock your phone
all of the time while it is plugged into USB.
Note that on Android 4.2.2 and higher devices, before you can actually use the
setting you just toggled, you will be prompted to allow USB debugging with your
specific development machine via a dialog box:

52

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 30: Allow USB Debugging Dialog
This occurs when you plug in the device via the USB cable and have the driver
appropriately set up. That process varies by the operating system of your
development machine, as is covered in the following sections.

Windows
When you first plug in your Android device, Windows will attempt to find a driver
for it. It is possible that, by virtue of other software you have installed, that the
driver is ready for use. If it finds a driver, you are probably ready to go.
If the driver is not found, here are some options for getting one.
Windows Update
Some versions of Windows (e.g., Vista) will prompt you to search Windows Update
for drivers. This is certainly worth a shot, though not every device will have supplied
its driver to Microsoft.
Standard Android Driver
In your Android SDK installation, if you chose to install the “Google USB Driver”
package from the SDK Manager, you will find an extras/google/usb_driver/
53

TUTORIAL #2 - CREATING A STUB PROJECT
directory, containing a generic Windows driver for Android devices. You can try
pointing the driver wizard at this directory to see if it thinks this driver is suitable
for your device. This will often work for Nexus devices.
Manufacturer-Supplied Driver
If you still do not have a driver, the OEM USB Drivers in the developer
documentation may help you find one for download from your device manufacturer.
Note that you may need the model number for your device, instead of the model
name used for marketing purposes (e.g., GT-P3113 instead of “Samsung Galaxy Tab 2
7.0”).

macOS and Linux
Odds are decent that simply plugging in your device will “just work”. You can see if
Android recognizes your device via running adb devices in a shell (e.g., macOS
Terminal), where adb is in your platform-tools/ directory of your SDK. If you get
output similar to the following, the build tools detected your device:
List of devices attached
HT9CPP809576 device

If you are running Ubuntu (or perhaps other Linux variants), and this command did
not work, you may need to add some udev rules. For example, here is a
51-android.rules file that will handle the devices from a handful of manufacturers:
SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666"
SUBSYSTEM=="usb", SYSFS{idVendor}=="22b8", MODE="0666"
SUBSYSTEM=="usb", SYSFS{idVendor}=="18d1", MODE="0666"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="0c01", MODE="0666",
OWNER="[me]"
SUBSYSTEM=="usb", SYSFS{idVendor}=="19d2", SYSFS{idProduct}=="1354", MODE="0666"
SUBSYSTEM=="usb", SYSFS{idVendor}=="04e8", SYSFS{idProduct}=="681c", MODE="0666"

Drop that in your /etc/udev/rules.d directory on Ubuntu, then either reboot the
computer or otherwise reload the udev rules (e.g., sudo service udev reload).
Then, unplug and re-plug in the device and see if it is detected.

54

TUTORIAL #2 - CREATING A STUB PROJECT

Step #5: Running the Project
Now, we can confirm that our project is set up properly by running it on a device or
emulator.
To do that in Android Studio, just press the Run toolbar button (usually depicted as
a green rightward-pointing triangle).
You will then be presented with a dialog indicating where you want the app to run:
on some existing device or emulator, or on some newly-launched emulator:

Figure 31: Android Studio Device Chooser Dialog
If you do not have an emulator running, choose one from the list, then click OK.
Android Studio will launch your emulator for you.
And, whether you start a new emulator instance or reuse an existing one, your app
should appear on it:

55

TUTORIAL #2 - CREATING A STUB PROJECT

Figure 32: Android 7.0 Emulator with EmPubLite
Note that you may have to unlock your device or emulator to actually see the app
running. It will not unlock automatically for you, except the very first time that you
run the emulator.

In Our Next Episode…
… we will modify the AndroidManifest.xml file of our tutorial project.

56

Getting Around Android Studio

This chapter will serve as a quick tour of the Android Studio IDE, to help you get
settled in. Other Android-specific capabilities of Android Studio will be explored in
the chapters that follow.

Navigating The Project Explorer
After the main editing area — where you will modify your Java source code, your
resources, and so forth — the piece of Android Studio you will spend the most time
with is the project explorer, usually available on the left side of the IDE window:

Figure 33: Android Studio Project Explorer, Showing Android Project View
This explorer pane has two main “project views” that an Android developer will use:
the Android project view and the classic project view.

57

GETTING AROUND ANDROID STUDIO

Android Project View
By default, when you create or import a project, you will wind up in the Android
project view.
In theory, the Android project view is designed to simplify working with Android
project files. In practice, it may do so, but only for some advanced developers. On
the whole, it makes the IDE significantly more complicated for newcomers to
Android, as it is rather difficult to see where things are and what relates to what.
We will return to the Android project view a bit later in the book and explain its
benefits relative to resources and Gradle’s source sets.
However, for most of the book — most importantly, for the tutorials – we will use
the classic project view.

Classic Project View
To switch to the classic project view, click the pair of arrowheads to the right of the
“Project Files” tab just above the tree in the explorer, and choose Project:

Figure 34: Android Studio Project Explorer, Showing Project View Drop-Down
On some machines, in some cases, the pair of arrowheads is instead a single dropdown arrowhead next to the currently-chosen view (e.g., Android).
Switching to the project view will change the contents of the tree to show you all of
the files, in their associated directories:

58

GETTING AROUND ANDROID STUDIO

Figure 35: Android Studio Project Explorer, Showing Classic Project View
This project view is much like its equivalent in other IDEs, allowing you to find all of
the pieces of your Android project. We will be exploring what those pieces are, and
how their files are organized in our projects, in the next chapter.

Context Menus in the Explorer
Right-clicking over a directory or file in the explorer will give you a context menu
with a variety of options. Some of these will be typical of any sort of file manager,
such as “cut”, “copy”, and/or “paste” options. Some of these will be organized
according to how Android Studio manages application development, such as the
“Refactor” sub-menu, where you can rename or move files around. Yet others will be
specific to Android Studio, such as the ability to invoke wizards to create certain
types of Android components or other Java classes.

Opening Files from the Explorer
Double-clicking on a file usually opens that file in a tab that allows you to edit that
file, using some sort of editor.

59

GETTING AROUND ANDROID STUDIO
Some file types, like images, can be opened but not edited, as Android Studio does
not have editors for all file types.

Running Projects
Of course, as you change your app, you will want to try it out and see if it works,
whether on a device or an emulator.

The Basics
As noted in Tutorial #2, to run your project, just press the Run toolbar button:

Figure 36: Android Studio Run Controls, Showing Green Arrow to Run the App
You will then be presented with a dialog indicating where you want the app to run:

Figure 37: Android Studio Device Chooser Dialog
The “Connected Devices” category lists any devices or running emulators that the
build tools can find. Some may be disabled due to compatibility issues, such as
having an emulator for an old version of Android where your app requires a newer
version of Android.
The “Available Emulators” category lists all AVDs that you have defined in the AVD
Manager that are not already running. Again, you may find that some are disabled
for compatibility reasons.
60

GETTING AROUND ANDROID STUDIO
The “Create New Emulator” button brings up the wizard to create a new AVD, just
like the one you can launch from the AVD Manager.

“Instant Run”
Next to the green “run” arrow button in the toolbar is a lightning bolt button.
Sometimes, this will be grayed out and unusable. Other times, it will appear in
yellow:

Figure 38: Android Studio Run Controls, With Instant Run Enabled
This button performs what is called “Instant Run”. Instead of building your app and
pushing the app to the device or emulator, Instant Run attempts to patch your
existing app based on whatever changes you made to the project since you last ran
it.
On the plus side, Instant Run is very fast. However, the patched app is not exactly
the same as would be your app built from scratch. Feel free to use this for smaller
changes if you wish.

Viewing Output
Beyond your app itself, Android Studio will generate other sorts of diagnostic
output, in the form of “console”-style transcripts of things that have occurred. The
two of these that probably will matter most for you are the Gradle console and
Logcat.

Gradle Console
By default, docked in the lower-right corner of your Android Studio window is a
“Gradle Console” item. Tapping on that will open up a pane showing the output of
attempts to build your application:

61

GETTING AROUND ANDROID STUDIO

Figure 39: Android Studio Gradle Console
This may automatically appear from time to time, if specific build problems are
detected, and you can always go examine it whenever you need.
Click on the “Gradle Console” item again to collapse the view and get it out of your
way.

Logcat
Messages that appear at runtime — including the all-important Java stack traces
triggered by bugs in your code — are visible in Logcat. The Logcat tool docked
towards the lower-left corner of your Android Studio window will display Logcat
when tapped:

Figure 40: Android Studio Logcat Tool
Logcat is explained in greater detail a bit later in this book.

Accessing Android Tools
Not everything related to Android is directly part of Android Studio itself. In some
cases, tools need to be shared between users of Android Studio, users of Eclipse, and
62

GETTING AROUND ANDROID STUDIO
users of “none of the above”. In some cases, while the long term direction may be to
incorporate the tools’ functionality directly into Android Studio, that work simply
has not been completed to date.
Here are some noteworthy Android-related tools that you can access via the Tools >
Android main menu option.

SDK and AVD Managers
As we saw in Tutorial #1, the SDK Manager is Android’s tool for downloading pieces
of the Android SDK, including:
•
•
•
•
•

“SDK Platform” editions, allowing us to compile against a particular API level
ARM and (sometimes) x86 emulator images
Documentation
Updates to the core build tools
Etc.

You can launch the SDK Manager via Tools > Android > SDK Manager from the
Android Studio main menu, or by clicking on the “droid in a box” toolbar button:

Figure 41: Android Studio SDK Manager Toolbar Icon
The AVD Manager is the tool for creating emulators that emulate certain Android
environments, based upon API level, screen size, and other characteristics.
You can launch the AVD Manager via Tools > Android > AVD Manager from the
Android Studio main menu, or by clicking the “droid and a screen” toolbar button:

63

GETTING AROUND ANDROID STUDIO

Figure 42: Android Studio AVD Manager Toolbar Icon

Android Studio and Release Channels
When you install Android Studio for the first time, your installation will be set up to
get updates on the “stable” release channel. Here, a “release channel” is a specific set
of possible upgrades. The “stable” release channel means that you are getting full
production-ready updates. Android Studio will check for updates when launched,
and you can manually check for updates via the main menu (e.g., Help > Check for
Update… on Windows and Linux).
If an update is available, you will be presented with a dialog box showing you details
of the update:

Figure 43: Android Studio Update Dialog
Choosing “Release Notes” will bring up a Web page with release notes for the new
release. Clicking “Update and Restart” does pretty much what the button name
suggests: it downloads the update and restarts the IDE, applying the update along
the way.

64

GETTING AROUND ANDROID STUDIO
Clicking the “Updates” hyperlink in the dialog brings up yet another dialog, allowing
you to choose which release channel you want to subscribe to:

Figure 44: Android Studio Update Release Channel Dialog
You have four channels to choose from:
•
•
•
•

Stable, which is appropriate for most developers
Beta, which will get updates that are slightly ahead of stable
Dev, which is even more ahead than is the beta channel
Canary, which is updated very early (and the name, suggestive of a “canary in
a coal mine”, indicates that you are here to help debug the IDE)

Visit the Trails!
Android Studio’s Project Structure dialog and Translations Editor are covered later in
this book.

65

Contents of Android Projects

The Android build system is organized around a specific directory tree structure for
your Android project, much like any other Java project. The specifics, though, are
fairly unique to Android — the Android build tools do a few extra things to prepare
the actual application that will run on the device or emulator.
Here is a quick primer on the project structure, to help you make sense of it all,
particularly for the sample code referenced in this book.

What You Get, In General
The details of exactly what files are in your project depend on a variety of things:
• What IDE and version the project was used to create the project
• What project template was used to create the project
• What other changes have been made to the project after it was created
However, usually, there are many elements in common.

The Modules
A default Android Studio project will have an app/ directory off of the project root
directory (i.e., the directory in which you told Android Studio to create the project).
That app/ directory represents what Android Studio refers to as a module. Most
projects just have this one app/ module, though you can have more than one
module if needed.

67

CONTENTS OF ANDROID PROJECTS

The Source Sets
Inside of app/ you will find a src/main/ directory. This represents the main source
set, and it contains all of the “source” that your project is contributing to build the
application. Here, “source” means more than just programming language source
code (e.g., Java). It also includes other types of files, such as resources and the
manifest, that contribute to the app.

The Manifest
Inside of app/src/main/, you will find a file named AndroidManifest.xml.
AndroidManifest.xml is an XML file describing the application being built and what
components — activities, services, etc. — are being supplied by that application. You
can think of it as being the “table of contents” of what your application is about,
much as a book has a “table of contents” listing the various parts, chapters, and
appendices that appear in the book.
We will examine the manifest a bit more closely starting in the next chapter.

The Java
When you created the project, if you had Android Studio create an activity for you,
you supplied the class name of the “main” activity for the application (e.g.,
MainActivity). That will be combined with the package name that you provided for
the project to determine the fully-qualified class name for this activity (e.g.,
com.commonsware.android.MainActivity).
You will find that your project’s Java source tree already has the package’s directory
tree in place, plus a class representing your requested activity (e.g., com/
commonsware/android/MainActivity.java). This will be inside the main source set,
so the full path from the project root would be something like app/src/main/java/
com/commonsware/android/MainActivity.java.
You are welcome to modify this file and add Java classes as needed to implement
your application, and we will demonstrate that countless times as we progress
through this book.
Elsewhere — in directories that you normally do not work with — the Android build
tools will also be code-generating some source code for you each time you build
your app. One of the code-generated Java classes (R.java) will be important for
68

CONTENTS OF ANDROID PROJECTS
controlling our user interfaces from our own Java code, and we will see many
references to this R class as we start building applications in earnest.

The Resources
You will also find that your project has a res/ directory tree inside of the main
source set. This holds “resources” — static files that are packaged along with your
application, either in their original form or, occasionally, in a preprocessed form.
Some of the subdirectories you will find or create under res/ include:
1. res/drawable/ and res/mipmap-*/ (for a few values of *) for images (PNG,
JPEG, etc.)
2. res/layout/ for XML-based UI layout specifications
3. res/menu/ for XML-based menu specifications
4. res/raw/ for general-purpose files (e.g., an audio clip, a CSV file of account
information)
5. res/values/ for strings, dimensions, and the like
6. res/xml/ for other general-purpose XML files you wish to ship
Some of the directory names may have suffixes, like res/mipmap-hdpi/. This
indicates that the directory of resources should only be used in certain
circumstances — in this case, the mipmap resources are designed for devices with
high-density screens.
We will cover all of these, and more, later in this book.

The Build Instructions
The IDE needs to know how to take all of this stuff and come up with an Android
APK file. Some of this is already “known” to the IDE based upon how the IDE was
written. But some details are things that you may need to configure from time to
time, and so those details are stored in files that you will edit, by one means or
another, from your IDE.
In Android Studio, most of this knowledge is kept in files named build.gradle.
These are for a build engine known as Gradle, that Android Studio uses to build
APKs and other Android outputs.

69

CONTENTS OF ANDROID PROJECTS

More About the Directory Structure
All of those items are stored in a particular directory structure in an Android Studio
project… at least by default. Android Studio and Gradle are powerful and can be
configured to handle other structures, though most projects stick with the standard
setup.

The Root Directory
In the root directory of your project, the most important item is the app/ directory
representing your application module. We will look at that more in the next section.
Beyond the app/ directory, the other noteworthy files in the root of your project
include:
• build.gradle, which is part of the build instructions for your project, as is
described above
• Various other Gradle-related files (settings.gradle, gradle.properties,
gradlew, gradlew.bat, and so forth)
• local.properties, which indicates where your Android SDK tools reside
• An .iml file, where Android Studio holds some additional metadata about
your project
• A .gitignore file, representing standard rules for what should and should
not go into version control, particularly with respect to the Git version
control system
Eventually, you will have:
• A build/ directory, containing the compiled output of your app, plus various
reports and other files related to the build process and app testing
• A .gradle/ directory, containing Gradle executable code
• An .idea/ directory — this, along with the .iml file, represents data needed
by IntelliJ IDEA, on which Android Studio is based

The App Directory
The app/ directory, and its contents, are where you will spend most of your time as a
developer. Only infrequently do you need to manipulate the files in the project root.

70

CONTENTS OF ANDROID PROJECTS
The most important thing in the app/ directory is the src/ directory, which is the
root of your project’s source sets. We will explore those more in the next section.
Beyond the src/ directory, there are a few other items of note in app/:
• A build/ directory, which will hold the outputs of building your app,
including your APK file
• A build.gradle file, where most of your project-specific Gradle
configuration will go, to teach Android Studio how to build your app
• An app.iml file, containing more Android Studio metadata
• Another .gitignore file, for overrides to the Git version control rules from
the .gitignore file in the project root
• proguard-rules.pro, which are rules for a tool called ProGuard, which helps
reduce the size of your app

The Source Sets
Source sets are where the “source” of your project is organized. As noted earlier,
“source” not only refers to programming language source code (e.g., Java), but other
types of inputs to the build, such as your resources.
The source set that you will spend most of your time in is main/. You may also have
stub source sets named androidTest and test, for use in testing your app, as will be
covered later in the book.
Inside of a source set, common items include:
• Java code, in a java/ directory
• Resources, in a res/ directory
• Assets, in an assets/ directory, representing other static files you wish
packaged with the application for deployment onto the device
• Your AndroidManifest.xml file

71

CONTENTS OF ANDROID PROJECTS

Figure 45: Android Studio Project Explorer, Showing EmPubLite
Some projects will have additional items, usually tied to specific add-on tools that
the project happens to employ.

What You Get Out Of It
As part of running your app on a device or emulator, the IDE will generate an APK
file. You will find this in the build/outputs/apk directory of your module’s
directory, (e.g., app/build/outputs/apk for a traditional Android Studio project).
The APK file is a ZIP archive containing your compiled Java classes along with
packaged versions of the rest of your source (e.g., resources, manifest). The APK is
what gets distributed to your users, whether through an app distribution service like
Google’s Play Store or through other means.

72

Introducing Gradle and the Manifest

In the discussion of Android Studio, this book has mentioned something called
“Gradle”, without a lot of explanation.
In this chapter, the mysteries of Gradle will be revealed to you.
(well, OK, some of the mysteries…)
We also mentioned in passing in the previous chapter the concept of the “manifest”
— AndroidManifest.xml — as being a special file in our Android projects.
On the one hand, Gradle and the manifest are not strictly related. On the other
hand, some (but far from all) of the things that we can set up in the manifest can be
overridden in Gradle.
So, in this chapter, we will review both what Gradle is, what the manifest is, what
each of their roles are, and the basics of how they tie together.

Gradle: The Big Questions
First, let us “set the stage” by examining what this is all about, through a series of
fictionally-asked questions (FAQs).

What is Gradle?
Gradle is software for building software, otherwise known as “build automation
software” or “build systems”. You may have used other build systems before in other
environments, such as make (C/C++), rake (Ruby), Ant (Java), Maven (Java), etc.

73

INTRODUCING GRADLE AND THE MANIFEST
These tools know — via intrinsic capabilities and rules that you teach them — how
to determine what needs to be created (e.g., based on file changes) and how to
create them. A build system does not compile, link, package, etc. applications
directly, but instead directs separate compilers, linkers, and packagers to do that
work.
Gradle uses a domain-specific language (DSL) built on top of Groovy to accomplish
these tasks.

What is Groovy?
There are many programming languages that are designed to run on top of the Java
VM. Some of these, like JRuby and Jython, are implementations of other common
programming languages (Ruby and Python, respectively). Other languages are
unique, and Groovy is one of those.
Groovy scripts look a bit like a mashup of Java and Ruby. As with Java, Groovy
supports:
•
•
•
•
•

Defining classes with the class keyword
Creating subclasses using extends
Importing classes from external JARs using import
Defining method bodies using braces ({ and })
Objects are created via the new operator

As with Ruby, though:
• Statements can be part of a class, or simply written in an imperative style,
like a scripting language
• Parameters and local variables are not typed
• Values can be automatically patched into strings, though using slightly
different syntax ("Hello, $name" for Groovy instead of "Hello, #{name}"
for Ruby)
Groovy is an interpreted language, like Ruby and unlike Java. Groovy scripts are run
by executing a groovy command, passing it the script to run. The Groovy runtime,
though, is a Java JAR and requires a JVM in order to operate.
One of Groovy’s strengths is in creating a domain-specific language (or DSL).
Gradle, for example, is a Groovy DSL for doing software builds. Gradle-specific
capabilities appear to be first-class language constructs, generally indistinguishable
74

INTRODUCING GRADLE AND THE MANIFEST
from capabilities intrinsic to Groovy. Yet, the Groovy DSL is largely declarative, like
an XML file.
To some extent, we get the best of both worlds: XML-style definitions (generally
with less punctuation), yet with the ability to “reach into Groovy” and do custom
scripting as needed.

What Does Android Have To Do with Gradle?
Google has published the Android Gradle Plugin, which gives Gradle the ability to
build Android projects. Google is also using Gradle and the Android Gradle Plugin
as the build system behind Android Studio.

Obtaining Gradle
As with any build system, to use it, you need the build system’s engine itself.
If you will only be using Gradle in the context of Android Studio, the IDE will take
care of getting Gradle for you. If, however, you are planning on using Gradle outside
of Android Studio (e.g., command-line builds), you will want to consider where your
Gradle is coming from. This is particularly important for situations where you want
to build the app with no IDE in sight, such as using a continuous integration (CI)
server, like Jenkins.
Also, the way that Android Studio works with Gradle — called the Gradle Wrapper –
opens up security issues for your development machine, if you are the sort to
download open source projects from places like GitHub and try using them.

Direct Installation
What most developers looking to use Gradle outside of Android Studio will wind up
doing is installing Gradle directly.
The Gradle download page contains links to ZIP archives for Gradle itself: binaries,
source code, or both.
You can unZIP this archive to your desired location on your development machine.

75

INTRODUCING GRADLE AND THE MANIFEST

Linux Packages
You may be able to obtain Gradle via a package manager on Linux environments. For
example, there is an Ubuntu PPA for Gradle.

The gradlew Wrapper
If you are starting from a project that somebody else has published, you may find a
gradlew and gradlew.bat file in the project root, along with a gradle/ directory.
This represents the “Gradle Wrapper”.
The Gradle Wrapper consists of three pieces:
• the batch file (gradlew.bat) or shell script (gradlew)
• the JAR file used by the batch file and shell script (in the gradle/wrapper/
directory)
• the gradle-wrapper.properties file (also in the gradle/wrapper/ directory)
Android Studio uses the gradle-wrapper.properties file to determine where to
download Gradle from, for use in your project, from the distributionUrl property
in that file:
#Sun Nov 05 06:56:08 EST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\:
\://services.gradle.org/distributions/gradle-4.1-all.zip
(from Basic/Button/gradle/wrapper/gradle-wrapper.properties)

When you create or import a project, or if you change the version of Gradle
referenced in the properties file, Android Studio will download the Gradle pointed
to by the distributionUrl property and install it to a .gradle/ directory (note the
leading .) in your project. That version of Gradle will be what Android Studio uses.
RULE #1: Only use a distributionUrl that you trust.
If you are importing an Android project from a third party — such as the samples for
this book — and they contain the gradle/wrapper/gradle-wrapper.properties
file, examine it to see where the distributionUrl is pointing to. If it is loading from
services.gradle.org, or from an internal enterprise server, it is probably
76

INTRODUCING GRADLE AND THE MANIFEST
trustworthy. If it is pointing to a URL located somewhere else, consider whether you
really want to use that version of Gradle, considering that it may have been
tampered with.
The batch file, shell script, and JAR file are there to support command-line builds. If
you run the gradlew command, it will use a local copy of Gradle installed in
.gradle/ in the project. If there is no such copy of Gradle, gradlew will download
Gradle from the distributionUrl, as does Android Studio. Note that Android
Studio does not use gradlew for this role — that logic is built into Android Studio
itself.
RULE #2: Only use a gradlew that you REALLY trust.
It is relatively easy to examine a .properties file to check a URL to see if it seems
valid. Making sense of a batch file or shell script can be cumbersome. Decompiling a
JAR file and making sense of it can be rather difficult. Yet, if you use gradlew that
you obtained from somebody, that script and JAR are running on your development
machine, as is the copy of Gradle that they install. If that code was tampered with,
the malware has complete access to your development machine and anything that it
can reach, such as servers within your organization.
Note that you do not have to use the Gradle Wrapper at all. If you would rather not
worry about it, install a version of Gradle on your development machine yourself
and remove the Gradle Wrapper files. You can use the gradle command to build
your app (if your Gradle’s bin/ directory is in your PATH), and Android Studio will
use your Gradle installation (if you teach it where to find it, such as via the
GRADLE_HOME environment variable).

Versions of Gradle and the Android Gradle Plugin
The Android Gradle Plugin that we will use to give Gradle “super Android powers!” is
updated periodically. Each update has its corresponding required version of Gradle.
Google maintains a page listing the Gradle versions supported by each Android
Gradle Plugin version
If you are using the Gradle Wrapper, you are using an installation of Gradle that is
local to the project. So long as the version of Gradle in the project matches the
version of the Android Gradle Plugin requested in the project’s build.gradle file —
as will be covered later in this chapter — you should be in fine shape.

77

INTRODUCING GRADLE AND THE MANIFEST
If you are not using the Gradle Wrapper, you will need to decide when to take on a
new Android Gradle Plugin release and plan to update your Gradle installation and
build.gradle files in tandem at that point.

Gradle Environment Variables
If you installed Gradle yourself, you will want to define a GRADLE_HOME environment
variable, pointing to where you installed Gradle, and to add the bin/ directory inside
of Gradle to your PATH environment variable.
You may also consider setting up a GRADLE_USER_HOME environment variable,
pointing to a directory in which Gradle can create a .gradle/ subdirectory, for peruser caches and related materials. By default, Gradle will use your standard home
directory.

Examining the Gradle Files
An Android Studio project usually has two build.gradle files, one at the project
level and one at the “module” level (e.g., in the app/ directory).

The Project-Level File
The build.gradle file in the project directory controls the Gradle configuration for
all modules in your project. Right now, most likely you only have one module, and
many apps only ever use one module. However, it is possible for you to add other
modules to this project, and we will explore reasons for doing so later in this book.
Here is a typical top-level build.gradle file:
// Top-level build file where you can add configuration options common to all
sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'

78

INTRODUCING GRADLE AND THE MANIFEST
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

buildscript
In Groovy terms, a “closure” is a block of code wrapped in braces ({ }).
The buildscript closure in Gradle is where you configure the JARs and such that
Gradle itself will use for interpreting the rest of the file. Hence, here you are not
configuring your project so much as you are configuring the build itself.
The repositories closure inside the buildscript closure indicates where plugins
can come from. Here, jcenter() is a built-in method that teaches Gradle about
JCenter, a popular location for obtaining open source libraries. Similarly, google() is
a built-in method that teaches Gradle about a site where it can download plugins
from Google.
The dependencies closure indicates what is required to be able to run the rest of the
build script. classpath 'com.android.tools.build:gradle:3.0.0' is not especially
well-documented by the Gradle team. However the
'com.android.tools.build:gradle:3.0.0' portion means:
• Find the com.android.tools.build group of plugins
• Find the gradle artifact within that group
• Ensure that we have version 3.0.0 of the plugin
The first time you run your build, with the buildscript closure as shown above,
Gradle will notice that you do not have this dependency. It will then download that
artifact from Google, as Google serves up its plugin from its own site nowadays.
79

INTRODUCING GRADLE AND THE MANIFEST
Sometimes, the last segment of the version is replaced with a + sign (e.g., 3.0.+).
This tells Gradle to download the latest version, thereby automatically upgrading
you to the latest patch-level (e.g., 3.0.1 at some point).
allprojects
The allprojects closure says “apply these settings to all modules in this project”.
Here, we are setting up jcenter() and google() as places to find libraries used in
any of the modules in our project. We will use lots of libraries in our projects —
having these “repositories” set up in allprojects makes it simpler for us to request
them.

The Module-Level Gradle File
In your app/ module, you will also find a build.gradle file. This has settings unique
for this module, independent of any other module that your project may have in the
future.
Here is a typical module-level build.gradle file:
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.commonsware.myapplication"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support.constraint:constraint-layout:1.0.2'

80

INTRODUCING GRADLE AND THE MANIFEST
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

For now, let’s focus on some key elements of this file.
dependencies
This build.gradle file also has a dependencies closure. Whereas the dependencies
closure in the buildscript closure in the top-level build.gradle file is for libraries
used by the build process, the dependencies closure in the module’s build.gradle
file is for libraries used by your code in that module. We will get into the concept of
these libraries later in the book.
android
The android closure contains all of the Android-specific configuration information.
This closure is what the Android plugin enables, where the plugin itself comes from
the apply plugin: 'com.android.application' line at the top, coupled with the
classpath line from the project-level build.gradle file.
But before we get into what is in this closure, we should “switch gears” and talk
about the manifest file, as what goes in the android closure is related to what goes in
the manifest file.

Introducing the Manifest
The foundation for any Android application is the manifest file:
AndroidManifest.xml. This will be in your app module’s src/main/ directory (the
main source set) for typical Android Studio projects.
Here is where you declare what is inside your application — the activities, the
services, and so on. You also indicate how these pieces attach themselves to the
overall Android system; for example, you indicate which activity (or activities)
should appear on the device’s main menu (a.k.a., launcher).
When you create your application, you will get a starter manifest generated for you.
For a simple application, offering a single activity and nothing else, the autogenerated manifest will probably work out fine, or perhaps require a few minor
81

INTRODUCING GRADLE AND THE MANIFEST
modifications. On the other end of the spectrum, the manifest file for the Android
API demo suite is over 1,000 lines long. Your production Android applications will
probably fall somewhere in the middle.
As mentioned previously, some items can be defined in both the manifest and in a
build.gradle file. The approach of putting that stuff in the manifest still works. For
Android Studio users, you will probably use the Gradle file and not have those
common elements be defined in the manifest.

Things In Common Between the Manifest and
Gradle
There are a few key items that can be defined in the manifest and can be overridden
in build.gradle statements. These items are fairly important to the development
and operation of our Android apps as well.

Package Name and Application ID
The root of all manifest files is, not surprisingly, a manifest element:

>

Note the android namespace declaration. You will only use the namespace on many
of the attributes, not the elements (e.g., , not ).
The biggest piece of information you need to supply on the  element is
the package attribute.
The package attribute will always need to be in the manifest, even for Android
Studio projects. The package attribute will control where some source code is
generated for us, notably some R and BuildConfig classes that we will encounter
later in the book.
Since the package value is used for Java code generation, it has to be a valid Java
package name. Java convention says that the package name should be based on a
reverse domain name (e.g., com.commonsware.myapplication), where you own the
domain in question. That way, it is unlikely that anyone else will accidentally collide
with the same name.

82

INTRODUCING GRADLE AND THE MANIFEST
The package also serves as our app’s default “application ID”. This needs to be a
unique identifier, such that:
• no two apps can be installed on the same device at the same time with the
same application ID
• no two apps can be uploaded to the Play Store with the same application ID
(and other distribution channels may have the same limitation)
By default, the application ID is the package value, but Android Studio users can
override it in their Gradle build files. Specifically, inside of the android closure can
be a defaultConfig closure, and inside of there can be an applicationId statement:
android {
// other stuff
defaultConfig {
applicationId "com.commonsware.myapplication"
// more other stuff
}
}

Not only can Android Studio users override the application ID in the defaultConfig
closure, but there are ways of having different application ID values for different
scenarios, such as a debug build versus a release build. We will explore that more
later in the book.

minSdkVersion and targetSdkVersion
Your defaultConfig closure inside the android closure in your module’s
build.gradle file has a pair of properties named minSdkVersion and
targetSdkVersion. Technically, these override values that could be defined via a
 element in the manifest, though few projects will have such an element
nowadays.
Of the two, the more critical one is minSdkVersion. This indicates what is the oldest
version of Android you are testing with your application. The value of the attribute
is an integer representing the Android API level. So, if you are only testing your
application on Android 4.1 and newer versions of Android, you would set your
minSdkVersion to be 16. The initial value is what you requested when you had
Android Studio create the project.

83

INTRODUCING GRADLE AND THE MANIFEST
You can also specify a targetSdkVersion. This indicates what version of Android
you are thinking of as you are writing your code. If your application is run on a
newer version of Android, Android may do some things to try to improve
compatibility of your code with respect to changes made in the newer Android.
Nowadays, most Android developers should specify a target SDK version of 15 or
higher. We will start to explore more about the targetSdkVersion as we get deeper
into the book; for the moment, whatever your IDE gives you as a default value is
probably a fine starting point.

Version Code and Version Name
Similarly, the defaultConfig closure has versionCode and versionName properties.
In principle, these override android:versionName and android:versionCode
attributes on the root  element in the manifest, though you will not find
many projects using those XML attributes.
These two values represent the versions of your application. The versionName value
is what the user will see for a version indicator in the Applications details screen for
your app in their Settings application. Also, the version name is used by the Play
Store listing, if you are distributing your application that way. The version name can
be any string value you want.
The versionCode, on the other hand, must be an integer, and newer versions must
have higher version codes than do older versions. Android and the Play Store will
compare the version code of a new APK to the version code of an installed
application to determine if the new APK is indeed an update. The typical approach
is to start the version code at 1 and increment it with each production release of
your application, though you can choose another convention if you wish. During
development, you can leave these alone, but when you move to production, these
attributes will matter greatly.

Other Gradle Items of Note
The android closure has a compileSdkVersion property. compileSdkVersion
specifies the API level to be compiled against, usually as a simple API level integer
(e.g., 19). This indicates what Java classes, methods, and so on are available to you
when you write your app. Typically, you set this to be the latest production release of
Android, using the values noted earlier in the book.

84

INTRODUCING GRADLE AND THE MANIFEST
The android closure may have a buildToolsVersion property. buildToolsVersion
indicates the version of the Android SDK build tools that you wish to use with this
project. The Android Gradle Plugin really is a thin wrapper around a series of “build
tools” that handle most of the work of creating an APK out of your project. If your
android closure does not have buildToolsVersion, the Android Gradle Plugin will
use its own default version of these build tools, and for many projects this will
suffice. In this book, most projects will state their buildToolsVersion, though some
will skip that line and use the plugin-provided default.

Where’s the GUI?
You might wonder why we have to slog through all of this Groovy code and wonder
if there is some GUI for affecting Gradle settings.
The answer is yes… and no.
There is the project structure dialog, that allows you to maintain some of this stuff.
And you are welcome to try it. However, the more complex your build becomes, the
more likely it is that the GUI will not suffice, and you will need to work with the
Gradle build files more directly. Hence, this book will tend to focus on the build
files.

The Rest of the Manifest
Not everything in the manifest can be overridden in the Gradle build files. Here are a
few key items that will always be defined in the manifest, not in a build.gradle file.

An Application For Your Application
In your initial project’s manifest, the primary child of the  element is an
 element.
By default, when you create a new Android project, you get a single 
element inside the  element:


>

>

>








The  element supplies android:name for the class implementing the
activity, android:label for the display name of the activity, and (sometimes) an
 child element describing under what conditions this activity will
be displayed. The stock  element sets up your activity to appear in the
launcher, so users can choose to run it. As we’ll see later in this book, you can have
several activities in one project, if you so choose.
The android:name attribute, in this case, has a bare Java class name (MainActivity).
Sometimes, you will see android:name with a fully-qualified class name (e.g.,
com.commonsware.myapplication.MainActivity). Sometimes, you will see a Java
class name with a single dot as a prefix (e.g., .MainActivity). Both MainActivity
and .MainActivity refer to a Java class that will be in your project’s package — the
one you declared in the package attribute of the  element.

Supporting Multiple Screens
Android devices come with a wide range of screen sizes, from 2.8” tiny smartphones
to 46” TVs. Android divides these into four buckets, based on physical size and the
distance at which they are usually viewed:
1.
2.
3.
4.

Small (under 3”)
Normal (3” to around 4.5”)
Large (4.5” to around 10”)
Extra-large (over 10”)

86

INTRODUCING GRADLE AND THE MANIFEST
By default, your application will support small and normal screens. It also will
support large and extra-large screens via some automated conversion code built into
Android.
To truly support all the screen sizes you want, you should consider adding a
 element to your manifest. This enumerates the screen sizes you
have explicit support for. For example, if you are providing custom UI support for
large or extra-large screens, you will want to have the  element.
So, while the starting manifest file works, handling multiple screen sizes is
something you will want to think about.
You wind up with an element akin to:


Much more information about providing solid support for all screen sizes, including
samples of the  element, will be found later in this book as we
cover large-screen strategies.

Other Stuff
As we proceed through the book, you will find other elements being added to the
manifest, such as:
• , to tell the user that you need permission to use certain
device capabilities, such as accessing the Internet
• , to tell Android that you need the device to have certain
features (e.g., a camera), and therefore your app should not be installed on
devices lacking such features
• , for bits of information needed by particular extensions to
Android, such as by FileProvider.
These and other elements will be introduced elsewhere in the book.

87

INTRODUCING GRADLE AND THE MANIFEST

Learning More About Gradle
This book will go into more about Gradle, both in the core chapters and in the trails.
But, the focus will be on the Android Gradle Plugin, and Gradle itself offers a lot
more than that. The Gradle Web site hosts documentation, links to Gradle-specific
books, and links to other Gradle educational resources.

Visit the Trails!
There are a few more chapters in this book getting into more details about the use of
Gradle and the Android Gradle Plugin.
• Gradle and Tasks explains how we ask Gradle to do things on our behalf
(“tasks”), such as compile our APK for us
• Gradle and Build Variants gets into what capabilities we get from the Gradle
project structure, including the ability to configure “build types” and
“product flavors”
There is also the “Advanced Gradle for Android Tips” chapter for other Gradle topics,
and the chapter on manifest merging in Gradle.

88

Tutorial #3 - Manifest Changes

As we build EmPubLite, we will need to make a number of changes to our project’s
manifest. In this tutorial, we will take care of a couple of these changes, to show you
how to manipulate the AndroidManifest.xml file. Future tutorials will make yet
more changes.
Android Studio users will also get their first chance to work with the build.gradle
file.
This is a continuation of the work we did in the previous tutorial.
You can find the results of the previous tutorial and the results of this tutorial in the
book’s GitHub repository.

Some Notes About Relative Paths
In these tutorials, you will see references to relative paths, like
AndroidManifest.xml, res/layout/, and so on.
You should interpret these paths as being relative to the app/src/main/ directory
within the project, except as otherwise noted. So, for example, Step #1 below will ask
you to open AndroidManifest.xml — that file can be found in app/src/main/
AndroidManifest.xml from the project root.

Step #1: Supporting Screens
Our application will restrict its supported screen sizes. Tablets make for ideal ebook
readers. Phones can also be used, but the smaller the phone, the more difficult it
89

TUTORIAL #3 - MANIFEST CHANGES
will be to come up with a UI that will let the user do everything that is needed, yet
still have room for more than a sentence or two of the book at a time.
We will get into screen size strategies and their details later in this book. For the
moment, though, we will add a  element to keep our
application off “small” screen devices (under 3” diagonal size).
Android Studio users can double-click on AndroidManifest.xml in the project
explorer.
As a child of the root  element, add a  element as
follows:

/>

Step #2: Blocking Backups
If you look at the  element, you will see that it has a few attributes,
including android:allowBackup="true". This attribute indicates that EmPubLite
should participate in Android’s automatic backup system.
That is not a good idea, until you understand the technical and legal ramifications of
that choice, which we will explore much later in this book.
In the short term, change android:allowBackup to be false.

Step #3: Ignoring Lint
Even after that change, the application element name may have a beige
background. If you hover your mouse over it and look at the explanatory tooltip, you
will see that it is complaining that this app is not indexable, and that you should add
an ACTION_VIEW activity to the app.
This is ridiculous. This app (hopefully) will never wind up on the Play Store, and so
Google’s “app indexing” capability will never be relevant.

90

TUTORIAL #3 - MANIFEST CHANGES
Put your text cursor somewhere inside the application element name and press
Alt-Enter (or Option-Return on macOS). This should bring up a popup
window showing some “quick fixes” for the problem:

Figure 46: Quick Fixes
Choose the “suppress” option. Then, press Ctrl-Alt-L (or Command-Option-L
on macOS) to reformat the file. You will wind up with something like:


>


>

>








91

TUTORIAL #3 - MANIFEST CHANGES
(from EmPubLite-AndroidStudio/T3-Manifest/EmPubLite/app/src/main/AndroidManifest.xml)

The  element now has a tools:ignore="GoogleAppIndexingWarning"
attribute, and the root  element defines the tools XML namespace. The
net effect is that we are telling the build tools — specifically the Lint utility – that it
should ignore this particular issue.

In Our Next Episode…
… we will make some changes to the resources of our tutorial project

92

Some Words About Resources

It is quite likely that by this point in time, you are “chomping at the bit” to get into
actually writing some code. This is understandable. That being said, before we dive
into the Java source code for our stub project, we really should chat briefly about
resources.
Resources are static bits of information held outside the Java source code. As we
discussed previously, resources are stored as files under the res/ directory in your
source set (e.g., app/src/main/res/). Here is where you will find all your icons and
other images, your externalized strings for internationalization, and more.
These are separate from the Java source code not only because they are different in
format. They are separate because you can have multiple definitions of a resource, to
use in different circumstances. For example, with internationalization, you will have
strings for different languages. Your Java code will be able to remain largely oblivious
to this, as Android will choose the right resource to use, from all candidates, in a
given circumstance (e.g., choose the Spanish string if the device’s locale is set to
Spanish).
We will cover all the details of these resource sets later in the book. Right now, we
need to discuss the resources in use by our stub project, plus one more.
This chapter will refer to the res/ directory as a shorthand for the app/src/main/
res/ directory of the project.

String Theory
Keeping your labels and other bits of text outside the main source code of your
application is generally considered to be a very good idea. In particular, it helps with
93

SOME WORDS ABOUT RESOURCES
internationalization (I18N) and localization (L10N). Even if you are not going to
translate your strings to other languages, it is easier to make corrections if all the
strings are in one spot instead of scattered throughout your source code.

Plain Strings
Generally speaking, all you need to do is have an XML file in the res/values
directory (typically named res/values/strings.xml), with a resources root
element, and one child string element for each string you wish to encode as a
resource. The string element takes a name attribute, which is the unique name for
this string, and a single text element containing the text of the string:


>The quick brown fox...


>He who laughs last...



One tricky part is if the string value contains a quote or an apostrophe. In those
cases, you will want to escape those values, by preceding them with a backslash (e.g.,
These are the times that try men\'s souls). Or, if it is just an apostrophe, you
could enclose the value in quotes (e.g., "These are the times that try men's
souls.").
For example, a project’s strings.xml file could look like this:


>EmPubLite


(from EmPubLite-AndroidStudio/T3-Manifest/EmPubLite/app/src/main/res/values/strings.xml)

We can reference these string resources from various locations, in our Java source
code and elsewhere. For example, the app_name string resource often is used in the
AndroidManifest.xml file:


>


>

>







(from EmPubLite-AndroidStudio/T3-Manifest/EmPubLite/app/src/main/AndroidManifest.xml)

Here, the android:label attribute of the  element refers to the
app_name string resource. This will appear in a few places in the application, notably
in the list of installed applications in Settings. So, if you wish to change how your
application’s name appears in these places, simply adjust the app_name string
resource to suit.
The syntax @string/app_name tells Android “find the string resource named
app_name”. This causes Android to scan the appropriate strings.xml file (or any
other file containing string resources in your res/values/ directory) to try to find
app_name.

Um, Wait, My Manifest Does Not Look Like That
When you view a manifest like that in Android Studio, it may appear as though you
are not using resources, as you may not see @string/... references:

95

SOME WORDS ABOUT RESOURCES

Figure 47: AndroidManifest.xml, As Initially Viewed in Android Studio
Here, android:label looks as though it is the hard-coded value “EmPubLite”.
However, notice that the attribute value is formatted differently than the others. The
rest are green text with a white background, while this one is gray text with a shaded
background.
That is because Android Studio is lying to you.
If you hover your mouse over the value, you will see the real attribute appear just
below it:

96

SOME WORDS ABOUT RESOURCES

Figure 48: AndroidManifest.xml, With Mouse Hovering Over “EmPubLite”
And, if you click on the fake value, you will see the real XML, with the real string
resource value.
What is happening is that Android Studio, by default, will substitute a candidate
value for the resource in its presentation of the manifest, other resources that refer
to resources, and even Java code. Any time you see that gray-on-light-blue
formatting, remember that this is not the real value, and that you have to uncover
the real value via hovering over it or clicking on it.

Styled Text
Many things in Android can display rich text, where the text has been formatted
using some lightweight HTML markup: , , and . Your string resources
support this, simply by using the HTML tags as you would in a Web page:


>This has 
bold
 in it.


>Whereas this has 
italics
!



97

SOME WORDS ABOUT RESOURCES

CDATA. CDATA Run. Run, DATA, Run.
Since a strings resource XML file is an XML file, if your message contains <, >, or &
characters (other than the formatting tags listed above), you will need to use a CDATA
section:

>


TPS Report for: {{reportDate}}

Here are the contents of the TPS report:

{{message}}

If you have any questions regarding this report, please do not ask Mark Murphy.

]]>
The Directory Name Our string resources in our stub project are in the res/values/strings.xml file. Since this directory name (values) has no suffixes, the string resources in that directory will be valid for any sort of situation, including any locale for the device. We will need additional directories, with distinct strings.xml files, to support other languages. We will cover how to do that later in this book. Editing String Resources If you double-click on a string resource file, like res/values/strings.xml, in Android Studio, you are presented the XML and edit it that way. There is an option for entering a dedicated string translation view, covered later in this book. Multi-Locale Support Android 7.0+ users can indicate that they support more than one language: 98 SOME WORDS ABOUT RESOURCES Figure 49: Android 7.0 Language Settings The user can choose the relative priorities of these languages, by grabbing the handle on the right side of the row and dragging the language higher or lower in the list. This has impacts on resource resolution for any locale-dependent resources, such as strings. Now Android will check multiple languages for resource matches, before falling back to the default language (e.g., whatever you have in res/values/ strings.xml). Hence, it is important that you ensure that you have a complete set of strings for every language that you support, lest the user perhaps wind up with a mixed set of languages in the UI. You can find out what languages the user has requested via a LocaleList class and its getDefault() static method. This, as the name suggests, has a list of Locale objects representing the user’s preferred languages. If you had previously been using Locale alone for this (e.g., for specialized in-app language assistance beyond resources), you will want to switch to LocaleList for Android 7.0 and beyond. Got the Picture? All Android versions support images in the PNG, JPEG, and GIF formats. GIF is officially discouraged, however; PNG is the overall preferred format. Android also 99 SOME WORDS ABOUT RESOURCES supports some proprietary XML-based image formats, though we will not discuss those at length until later in the book. Many newer versions of Android also support Google’s WebP image format, though this is not especially popular. There are two types of resources that use images like these: drawables and mipmaps. In truth, they are nearly identical. Mipmaps are used mostly for “launcher icons” — the icons seen in home screen launchers that identify activities that the user can start. Drawables hold everything else. (if you are a seasoned Android developer and are reading this section: while drawable resources might be removed when packaging an APK, such as for the Android Gradle Plugin split system for making density-specific editions of an app, mipmap resources are left alone, apparently) It is possible to have res/drawable/ and res/mipmap/ directories in an Android module. However, you will not find bitmaps there usually. Instead, those reside in directories like res/drawable-mdpi/ and res/drawable-hdpi/. These refer to distinct resource sets. The suffixes (e.g., -mdpi, -hdpi) are filters, indicating under what circumstances the images stored in those directories should be used. Specifically, -ldpi indicates images that should be used on devices with low-density screens (around 120 dots-per-inch, or “dpi”). The -mdpi suffix indicates resources for medium-density screens (around 160dpi), -hdpi indicates resources for high-density screens (around 240dpi). -xhdpi indicates resources for extra-highdensity screens (around 320dpi), -xxhdpi indicates extra-extra-high-density screens (around 480dpi), -xxxhdpi indicates extra-extra-extra-high-density screens (around 640dpi), and so on. In the EmPubLite tutorial project, you will find a series of mipmap directories with the same sorts of suffixes (e.g., res/mipmap-hdpi). Inside each of those directories, you will see an ic_launcher.png file. This is the stock icon that will be used for your application in the home screen launcher. Each of the images is of the same icon, but the higher-density icons have more pixels. The objective is for the image to be roughly the same physical size on every device, using higher densities to have more detailed images. Our AndroidManifest.xml file then references our ic_launcher icon in the element: > > > (from EmPubLite-AndroidStudio/T3-Manifest/EmPubLite/app/src/main/AndroidManifest.xml) Note that the manifest simply refers to @mipmap/ic_launcher, telling Android to find a mipmap resource named ic_launcher. The resource reference does not indicate the file type of the resource — there is no .png in the resource identifier. This means you cannot have ic_launcher.png and ic_launcher.jpg in the same project, as they would both be identified by the same identifier. You will need to keep the “base name” (filename sans extension) distinct for all of your images. Also, the @mipmap/ic_launcher reference does not mention what screen density to use. That is because Android will choose the right screen density to use, based upon the device that is running your app. You do not have to worry about it explicitly, beyond having multiple copies of your icon. If Android detects that the device has a screen density for which you lack an icon, Android will take the next-closest one and scale it. 101 SOME WORDS ABOUT RESOURCES Some Notes About WebP Android 4.0 added partial support for Google’s WebP image format, and Android 4.3 devices support the previously-missing features (lossless compression and transparency). WebP serves as a replacement for both PNG and JPEG, and in some circumstances it can result in smaller on-disk sizes for near-equivalent image quality. Android Studio, starting with version 2.3, has special support to help you convert drawable resources and other images from JPEG and PNG to WebP. Simply rightclick over the image in the project tree and choose “Convert to WebP” from the context menu. Initially, you are given a window for controlling the quality and output: Figure 50: WebP Converter in Android Studio “Lossy encoding” refers to the type performed by JPEG, taking into account that humans have limited ability to distinguish similar colors to achieve tighter compression. “Lossless encoding” refers to the type performed by PNG, where the compressed image is identical to the original, just as a ZIP file’s contents are identical to the files before they were ZIPped. For lossy encoding, you can choose a quality percentage, where higher quality images will not compress as well. You can also: • Skip anything that results in a bigger image (as sometimes WebP will be bigger than the JPEG or PNG equivalent) 102 SOME WORDS ABOUT RESOURCES • Skip a type of PNG called a nine-patch PNG, used for widget backgrounds • Skip images that use transparency, in case your minSdkVersion will not support such images If you choose lossy compression and leave the “preview” checkbox checked, you are then presented with a window showing the results of the conversion at your requested quality level: Figure 51: WebP Conversion Preview You can adjust the quality slider below the images to see how the image changes with different quality levels and how much additional disk savings you will get from the WebP conversion. When you are done, the WebP converter will replace your old PNG or JPEG file with the converted WebP image. Dimensions Dimensions are used in several places in Android to describe distances, such as a widget’s size. There are several different units of measurement available to you: 103 SOME WORDS ABOUT RESOURCES 1. px means hardware pixels, whose size will vary by device, since not all devices have the same screen density 2. in and mm for inches and millimeters, respectively, based on the actual size of the screen 3. pt for points, which in publishing terms is 1/72nd of an inch (again, based on the actual physical size of the screen) 4. dip (or dp) for density-independent pixels — one dip equals one hardware pixel for a ~160dpi resolution screen, but one dip equals two hardware pixels on a ~320dpi screen 5. sp for scaled pixels, where one sp equals one dip for normal font scale levels, increasing and decreasing as needed based upon the user’s chosen font scale level in Settings Dimension resources, by default, are held in a dimens.xml file in the res/values/ directory that also holds your strings. To encode a dimension as a resource, add a dimen element to dimens.xml, with a name attribute for your unique name for this resource, and a single child text element representing the value: >10dip >1in In a layout, you can reference dimensions as @dimen/..., where the ellipsis is a placeholder for your unique name for the resource (e.g., thin and fat from the sample above). In Java, you reference dimension resources by the unique name prefixed with R.dimen. (e.g., Resources.getDimension(R.dimen.thin)). While our stub project does not use dimension resources, we will be seeing them soon enough. Editing Dimension Resources As with most types of XML resources, Android Studio just has you edit the XML directly, when you double-click on the resource in the project explorer. 104 SOME WORDS ABOUT RESOURCES The Resource That Shall Not Be Named… Yet Your stub project also has a res/layout/ directory, in addition to the ones described above. That is for UI layouts, describing what your user interface should look like. We will get into the details of that type of resource as we start examining our user interfaces in an upcoming chapter. 105 Icons Icons are drawable resources. Except when they are mipmap resources. And except when they are multiple resources, combined together at runtime to create an image with a “squircle” background. And… Are you confused yet? In theory, setting up icons for your app would be quite simple, and for years that was the case. Nowadays, setting up an app icon is unnecessarily complex, though at least Android Studio has an Asset Studio tool to try to make it a bit simpler. In this chapter, we will explore what it takes to set up one of these app icons. App Icons… And Everything Else Each app has an icon. This is used for places like the list of installed apps in Settings. Traditionally — and to reduce user confusion — this icon is also used for the home screen launcher. Google has been making this icon increasingly complicated over the past few years: • App icons are mipmap resources, while everything else is a drawable resource • Android 7.1 introduced the concept of a separate “round icon” that an app can have, which would be used in place of the regular app icon on certain Android 7.1 devices… then dropped this feature with Android 8.0 • Android 8.0 introduced the concept of “adaptive icons”, where you have to provide separate “foreground” and “background” images, mostly so that 107 ICONS certain home screen launchers can shape the background image as they want (square, round, “squircle”, etc.) Most other icons — other than notification icons – are comparatively straightforward. Creating an App Icon with the Asset Studio If you right-click over pretty much any directory in the Android Studio tree, the context menu will have an “Image Asset” option. This is also available from File > New > Image Asset. This brings up the Asset Studio, to help you to assemble icons. By default, the Asset Studio has its “Icon Type” drop-down set for “Launcher Icons (Adaptive and Legacy)”, which is how you set up an app icon nowadays: Figure 52: Asset Studio, As Initially Launched The overall name for your launcher icon is found in the Name field, above the tabs. The default is ic_launcher, and unless you have a good reason to change it, you are best served by leaving it alone. 108 ICONS Foreground Layer What you would ordinarily think of as your icon is what Android Studio and Android 8.0+ refer to as the “Foreground Layer”. The Asset Studio starts on the Foreground Layer tab for you to configure this layer. Your icon can come from three main sources: • Some image of your own design, which you would load into the Foreground Layer tab by selecting the Image radio button, then clicking the “…” button next to the Path field, to browse your development machine and find that image • A piece of canned clip art, which you would choose by clicking on the “Clip Art” radio button, clicking the “Clip Art” button to choose the image, and clicking the Color button to choose a color to apply to that image: Figure 53: Asset Studio, Showing Clip Art Options • A letter or two, which you would choose by clicking on the Text radio button, filling in 1-2 letters in the Text field, choosing a font from your development machine in the adjacent drop-down, and clicking the Color button to choose a color to apply to the font: 109 ICONS Figure 54: Asset Studio, Showing Text Options For all three of these, you can: • Choose the name to use for this image, in the “Layer Name” field • Choose, via the Trim radio buttons, whether to remove all transparent space from the edges of the image (“Yes”) or not (“No”) • Resize the image from its default size That latter choice is particularly important, as you need to keep your foreground layer content within the “safe zone”. That shows up in the previews as a dark gray circle. So long as your foreground layer is in the safe zone, you should not have to worry about any launcher accidentally cutting off part of the layer when it renders your app icon. Background Layer In the preview area, by default, you will see a blue-green grid behind your foreground layer. That is the default background layer. If you would like to use something else, click the “Background Layer” tab: 110 ICONS Figure 55: Asset Studio, Showing Background Layer Your two main options are: • a flat color • an image of your choosing (akin to the foreground, where you click the “…” button next to the Path field to pick the background image) The background needs to be designed to be cropped into a variety of shapes, such as those shown in the preview (circle, various rounded forms of squares, etc.). Hence, outside of flat colors, typical backgrounds will be gradients or simple patterns, such as the default grid. Legacy On Android 8.0+ devices, the foreground layer, background layer, and launcherchosen shape (e.g., squircle) combine to create your app icon. On older devices, the app icon is whatever you choose it to be, where the Legacy tab helps you decide what that is: 111 ICONS Figure 56: Asset Studio, Showing Legacy Options The most important legacy option is the “Legacy Icon (API <= 25)” section. If your minSdkVersion is below 26, this will be the icon rendition that will be used as your app icon by default. The Asset Studio will merge your foreground and background layers itself, then apply your selected shape from the drop-down (e.g., square). For Android 7.1 devices, you can also opt to have the Asset Studio create a separate round icon, that you can declare in your manifest, as will be seen later in this chapter. If you are going to be distributing your app through the Play Store, you can also generate a Play Store rendition of your icon. This is reminiscent of the legacy icon, but at a higher resolution. Generating the Icon Once you have adjusted your app icon via the three tabs, click Next at the bottom of the Asset Studio wizard. This will bring up the final wizard page, showing you what will be generated for you by the wizard: 112 ICONS The Output Directories tree shows you each file that will be created or replaced. Those that show up in red are ones that will be replaced; ones that show up in black are new files. Typically, unless you changed the icon or layer names, most of the files will be replacements for files that exist already. Some of these files will be typical bitmap-style resources. Some are vector drawables. Using In Your Manifest Then, in your manifest, you can have android:icon and optionally android:roundIcon attributes on the element to associate your icons with your app. If you did not change the names of the icons, then your manifest should already have the appropriate attribute values. > > > Creating Other Icons with the Asset Studio In principle, you can use the Asset Studio to create other types of icons, by choosing another type of icon from the drop down, such as “Action Bar and Tab Icons”. In practice, the Asset Studio does not do much for you here, other than create multiple versions of your icon for different screen densities. 113 ICONS For most Android app developers, there are two other options: 1. Get icons at the right resolutions for different densities from your graphic designer, perhaps exported from Adobe Photoshop 2. Create vector icons, as will be covered in an upcoming chapter 114 Tutorial #4 - Adjusting Our Resources Our EmPubLite project has some initial resources. However, the defaults are not what we want for the long term. So, in addition to adding new resources in future tutorials, we will fix the ones we already have in this tutorial. This is a continuation of the work we did in the previous tutorial. You can find the results of the previous tutorial and the results of this tutorial in the book’s GitHub repository. Step #1: Changing the Name Our application shows up everywhere as “EmPubLite”: • • • • In the title bar of our activity As the caption under our icon in the home screen launcher In the Application list in the Settings app And so on We should change that to be “EmPub Lite”, adding a space for easier reading, and to illustrate that this is a “lite” version of the full EmPub application. Double-click on the res/values/strings.xml file in your project explorer. In the XML editor for the string resources, you will find an element that looks like: >EmPubLite 115 TUTORIAL #4 - ADJUSTING OUR RESOURCES Change the text node in this element to EmPub Lite. Then save your changes, giving you something like: >EmPub Lite Step #2: Changing the Icon The build tools provide us with a stock icon to use for the launcher — the actual image used varies by Android tools release. However, we can change it to something else. For example, we could use the icon portion of the CommonsWare logo: Figure 57: CommonsWare Download the molecule PNG file from the CommonsWare Web site and save it somewhere on your development machine. Then, right-click over the res/ directory in your main source set in the project explorer, and choose New > Image Asset from the context menu. That will bring up the Asset Studio wizard: 116 TUTORIAL #4 - ADJUSTING OUR RESOURCES Figure 58: Asset Studio Wizard, First Page In the Icon Type drop-down, choose “Launcher Icons (Legacy only)”. This will change the wizard to look like: 117 TUTORIAL #4 - ADJUSTING OUR RESOURCES Figure 59: Asset Studio Wizard, First Page, Legacy Mode Click the “Image” radio button in the “Asset Type” row. Then, click the “…” to the right of the “Path” field and choose the molecule.png file that you downloaded. Also, ensure that “Scaling” is set to “Shrink to Fit”, and choose “None” from the “Shape” drop-down. This should give you a preview of what the icons will look like: 118 TUTORIAL #4 - ADJUSTING OUR RESOURCES Figure 60: Asset Studio Wizard, First Page, After Loading Image Leave the rest of the wizard alone, then click Next to proceed to the next page: 119 TUTORIAL #4 - ADJUSTING OUR RESOURCES Figure 61: Asset Studio Wizard, Second Page You should get a warning towards the bottom, indicating that if you finish the wizard, you will overwrite existing files. This is expected, as we are trying to replace the old ic_launcher.png files with new ones. So, go ahead and click Finish. Step #3: Running the Result If you run the resulting app, you will see that it shows up with the new name and icon, such as in the launcher: 120 TUTORIAL #4 - ADJUSTING OUR RESOURCES Figure 62: EmPubLite with New Icons In Our Next Episode… … we will add a progress indicator to the UI of our tutorial project. 121 The Theory of Widgets There is a decent chance that you have already done work with widget-based UI frameworks. In that case, much of this chapter will be review, though checking out the section on the absolute positioning anti-pattern should certainly be worthwhile. There is a chance, though, that your UI background has come from places where you have not been using a traditional widget framework, where either you have been doing all of the drawing yourself (e.g., game frameworks) or where the UI is defined more in the form of a document (e.g., classic Web development). This chapter is aimed at you, to give you some idea of what we are talking about when discussing the notion of widgets and containers. What Are Widgets? Wikipedia has a nice definition of a widget: In computer programming, a widget (or control) is an element of a graphical user interface (GUI) that displays an information arrangement changeable by the user, such as a window or a text box. The defining characteristic of a widget is to provide a single interaction point for the direct manipulation of a given kind of data. In other words, widgets are basic visual building blocks which, combined in an application, hold all the data processed by the application and the available interactions on this data. (quote from the 7 March 2014 version of the page) Take, for example, this Android screen: 123 THE THEORY OF WIDGETS Figure 63: A Sample Android Screen Here, we see: • • • • some text, like “Phone-only, unsynced co…” and “PHONE” an icon of a contact “Rolodex” card some data entry fields with hints like “Name” and “Company” some “spinner” drop-down lists (the items with the arrowheads pointing southeast) • some gray divider lines Everything listed above is a widget. The user interface for most Android screens (“activities”) is made up of one or more widgets. This does not mean that you cannot do your own drawing. In fact, all the existing widgets are implemented via low-level drawing routines, which you can use for everything from your own custom widgets to games. This also does not mean that you cannot use Web technologies. In fact, we will see later in this book a widget designed to allow you to embed Web content into an Android activity. However, for most non-game applications, your Android user interface will be made up of several widgets. 124 THE THEORY OF WIDGETS Size, Margins, and Padding Widgets have some sort of size, since a zero-pixel-high, zero-pixel-wide widget is not especially user-friendly. Sometimes, that size will be dictated by what is inside the widget itself, such as a label (TextView) having a size dictated by the text in the label. Sometimes, that size will be dictated by the size of whatever holds the widget (a “container”, described in the next section), where the widget wants to take up all remaining width and/or height. Sometimes, that size will be a specific set of dimensions. Widgets can have margins. As with CSS, margins provide separation between a widget and anything adjacent to it (e.g., other widgets, edges of the screen). Margins are really designed to help prevent widgets from running right up next to each other, so they are visually distinct. Some developers, however, try to use margins as a way to hack “absolute positioning” into Android, which is an anti-pattern that we will examine later in this chapter. Widgets can have padding. As with CSS, padding provides separation between the contents of a widget and the widget’s edges. This is mostly used with widgets that have some sort of background, like a button, so that the contents of the widget (e.g., button caption) does not run right into the edges of the button, once again for visual distinction. What Are Containers? Containers are ways of organizing multiple widgets into some sort of structure. Widgets do not naturally line themselves up in some specific pattern — we have to define that pattern ourselves. In most GUI toolkits, a container is deemed to have a set of children. Those children are widgets, or sometimes other containers. Each container has its basic rule for how it lays out its children on the screen, possibly customized by requests from the children themselves. Common container patterns include: • put all children in a row, one after the next • put all children in a column, one below the next • arrange the children into a table or grid with some number of rows and columns 125 THE THEORY OF WIDGETS • anchor the children to the sides of the container, according to requests made by those children • anchor the children to other children in the container, according to requests made by those children • stack all children, one on top of the next • and so on In the sample activity above, the dominant pattern is a column, with things laid out from top to bottom. Some of those things are rows, with contents laid out left to right. However, as it turns out, the area with most of those widgets is scrollable. Android supplies a handful of containers, designed to handle most common scenarios, including everything in the list above. You are also welcome to create your own custom containers, to implement business rules that are not directly supported by the existing containers. Note that containers also have size, padding, and margins, just as widgets do. The Absolute Positioning Anti-Pattern You might wonder why all of these containers and such are necessary. After all, can’t you just say that such-and-so widget goes at this pixel coordinate, and this other widget goes at that pixel coordinate, and so on? Many developers have taken that approach — known as absolute positioning – over the years, to their eventual regret. For example, many of you may have used Windows apps, back in the 1990’s, where when you would resize the application window, the app would not really react all that much. You would expand the window, and the UI would not change, except to have big empty areas to the right and bottom of the window. This is because the developers simply said that such-and-so widget goes at this pixel coordinate, and this other widget goes at that pixel coordinate, regardless of the actual window size. In modern Web development, you see this in the debate over fixed versus fluid Web design. The consensus seems to be that fluid designs are better, though frequently they are more difficult to set up. Fluid Web designs can better handle differing browser window sizes, whether those window sizes are because the user resized their browser window manually, or because those window sizes are dictated by the 126 THE THEORY OF WIDGETS screen resolution of the device viewing the Web page. Fixed Web designs — effectively saying that such-and-so element goes at such-and-so pixel coordinate and so on — tend to be easier to build but adapt more poorly to differing browser window sizes. In mobile, particularly with Android, we have a wide range of possible screen resolutions, from QVGA (320x240) to beyond 1080p (1920x1080), and many values in between. Moreover, any device manufacturer is welcome to create a device with whatever resolution they so desire – there are no rules limiting manufacturers to certain resolutions. Hence, as developers, having the Android equivalent of fluid Web designs is critical, and the way you will accomplish that is by sensible use of containers, avoiding absolute positioning. The containers (and, to a lesser extent, the widgets) will determine how extra space is employed, as the screens get larger and larger. The Theme of This Section: Themes In Web development, we have had stylesheets for quite a while. Through such Cascading Style Sheets (CSS) files, we can stipulate various rules about how our Web pages should look. This includes: • Establishing a default look for certain HTML tags by tag name (e.g., setting the font and size for all

and

elements) • Establishing a look for specific HTML elements by class or ID (e.g., setting the width of a specific
to a certain number of CSS pixels) In Android, the equivalent concepts can be found in styles and themes. Styles are a collection of values for properties (e.g., have a foreground color of red). These can be applied to specific widgets (e.g., this label should adopt this style), or they can be employed by “themes” that provide the default look for all sorts of widgets and other elements of our UI. Of course, you do not have to declare any theme for your app. Android will give you a default look-and-feel without any specific theme. That look-and-feel has varied over the years, though, affecting the visual fundamentals of various Android widgets. These themes have names by which we refer to them: Theme, Theme.Holo, and Theme.Material. 127 THE THEORY OF WIDGETS In the Beginning, There Was “Theme”, And It Was Meh Way back in Android 1.0, the default theme was known simply as Theme. Technically, all themes inherit from Theme, much as how later CSS stylesheets effectively “inherit” the settings established by prior stylesheets. The Theme UI had a particular look to it: Figure 64: Labels, Fields, and Buttons in Theme For example: • At the top of the screen, we had a thin gray “title bar” with the name of our app • The focused field (an EditText widget) had a bright orange outline, whereas normally it was a plain white rectangle • The buttons (“OK” and “Cancel”) were… well… buttons Holo, There! Android 3.0 (API Level 11) introduced a new default theme, Theme.Holo, with the socalled “holographic widget theme”. This changed the look of our UI somewhat: 128 THE THEORY OF WIDGETS Figure 65: Labels, Fields, and Buttons in Theme.Holo Now: • At the top of the screen, we have an “action bar”, containing our app’s logo and name • The focused field has a blue “underbracket”, whereas normally it is gray • The buttons are styled slightly differently, with a bigger font, alternative backgrounds, etc. Considering the Material Android 5.0 changed the default theme yet again, to Theme.Material: 129 THE THEORY OF WIDGETS Figure 66: Labels, Fields, and Buttons in Theme.Material Now: • The action bar at the top of the screen no longer shows the app icon • Our field is indicated by an underline, which is teal when focused or gray when unfocused • The buttons are now forced into all-caps font, with a slightly smaller font size and subtly different background than we had with Theme.Holo Doing More with Themes Of course, we can do a lot more than just use these. There are other stock themes, with different characteristics. Furthermore, we can customize the themes, by defining our own (inheriting from a stock theme) and changing some of the properties (e.g., replacing the teal color with something else). We will get much more into creating custom styles and themes later in the book. However, we will see the effects of Theme, Theme.Holo, and Theme.Material on stock widgets in an upcoming chapter. 130 The Android User Interface The project you created in an earlier tutorial was just the default files generated by the Android build tools — you did not write any Java code yourself. In this chapter, we will examine the basic Java code and resources that make up an Android activity. The Activity The Java source code that you maintain will be in a standard Java-style tree of directories based upon the Java package you chose when you created the project (e.g., com.commonsware.android results in com/commonsware/android/). Android Studio will have that source, by default, in app/src/main/java/ off of the top-level project root. If, in the new-project wizard, you elected to create an activity, you will have, in the innermost directory, a Java source file representing an activity class. A very simple activity looks like: package com.commonsware.empublite; import android.app.Activity android.app.Activity; import android.os.Bundle android.os.Bundle; public class EmPubLiteActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super super.onCreate(savedInstanceState); setContentView(R.layout.main); } } 131 THE ANDROID USER INTERFACE (from EmPubLite-AndroidStudio/T2-Project/EmPubLite/app/src/main/java/com/commonsware/empublite/EmPubLiteActivity.java) Dissecting the Activity Let’s examine this Java code piece by piece: package com.commonsware.empublite; import android.app.Activity android.app.Activity; import android.os.Bundle android.os.Bundle; (from EmPubLite-AndroidStudio/T2-Project/EmPubLite/app/src/main/java/com/commonsware/empublite/EmPubLiteActivity.java) By default, the package declaration is the same as the one you used when creating the project. And, like any other Java project, you need to import any classes you reference. Most of the Android-specific classes are in the android package. Remember that not every Java SE class is available to Android programs! Visit the Android class reference to see what is and is not available. public class EmPubLiteActivity extends Activity { (from EmPubLite-AndroidStudio/T2-Project/EmPubLite/app/src/main/java/com/commonsware/empublite/EmPubLiteActivity.java) Activities are public classes, inheriting from the android.app.Activity base class (or, possibly, from some other class that itself inherits from Activity). You can have whatever data members you decide that you need, though the initial code has none. @Override protected void onCreate(Bundle savedInstanceState) { super super.onCreate(savedInstanceState); setContentView(R.layout.main); (from EmPubLite-AndroidStudio/T2-Project/EmPubLite/app/src/main/java/com/commonsware/empublite/EmPubLiteActivity.java) The onCreate() method is invoked when the activity is started. We will discuss the Bundle parameter to onCreate() in a later chapter. For the moment, consider it an opaque handle that all activities receive upon creation. The first thing you normally should do in onCreate() is chain upward to the superclass, so the stock Android activity initialization can be done. The only other statement in our stub project’s onCreate() is a call to setContentView(). This is where we tell Android what the user interface is supposed to be for our activity. 132 THE ANDROID USER INTERFACE This raises the question: what does R.layout.main mean? Where did this R come from? To explain that, we need to start thinking about layout resources and how resources are referenced from within Java code. Using XML-Based Layouts As noted in the previous chapter, Android uses a series of widgets and containers to describe your typical user interface. These all inherit from an android.view.View base class, for things that can be rendered into a standard widget-based activity. While it is technically possible to create and attach widgets and containers to our activity purely through Java code, the more common approach is to use an XMLbased layout file. Dynamic instantiation of widgets is reserved for more complicated scenarios, where the widgets are not known at compile-time (e.g., populating a column of radio buttons based on data retrieved off the Internet). With that in mind, it’s time to break out the XML and learn how to lay out Android activity contents that way. What Is an XML-Based Layout? As the name suggests, an XML-based layout is a specification of its widgets’ relationships to each other — and to containers — encoded in XML format. Specifically, Android considers XML-based layouts to be resources, and as such layout files are stored in the res/layout/ directory inside your Android project (or, as we will see later, other layout resource sets, like res/layout-land/ for layouts to use when the device is held in landscape). As has been noted elsewhere in this book, the initial location of res/ is in app/src/main/ for Android Studio. Each XML file contains a tree of elements specifying a layout of widgets and containers that make up one View. The attributes of the XML elements are properties, describing how a widget should look or how a container should behave. For example, if a Button element has an attribute value of android:textStyle = "bold", that means that the text appearing on the face of the button should be rendered in a boldface font style. For example, here is a res/layout/main.xml file that could be used with the aforementioned activity: 133 THE ANDROID USER INTERFACE > (from EmPubLite-AndroidStudio/T2-Project/EmPubLite/app/src/main/res/layout/main.xml) The class name of a widget or container — such as RelativeLayout or TextView – forms the name of the XML element. Since TextView is an Android-supplied widget, we can just use the bare class name. If you create your own widgets as subclasses of android.view.View, you would need to provide a full package declaration as well (e.g., com.commonsware.android.MyWidget). The root element needs to declare the Android XML namespace (xmlns:android="http://schemas.android.com/apk/res/android"). All other elements will be children of the root and will inherit that namespace declaration. The attributes are properties of the widget or container, describing what it should look and work like. For example, the android:layout_width and android:layout_height attributes on the TextView element make a request from the child (TextView) to its parent (a RelativeLayout) for what size the child should be. We will get into details about these attributes, their possible values, and their uses, in upcoming chapters. Note that those attributes in the tools namespace (e.g., tools:context) are there solely to support the Android build tools, and do not affect the runtime execution of your project. Android’s SDK ships with a tool (aapt) which uses the layouts. This tool will be automatically invoked by your Android tool chain (e.g., Android Studio). Of particular importance to you as a developer is that aapt generates an R.java source 134 THE ANDROID USER INTERFACE file, allowing you to access layouts and widgets within those layouts directly from your Java code. In other words, this is where that magic R value used in setContentView() comes from. We will discuss that a bit more later in this chapter. XML Layouts and Your IDE If you are using Android Studio, and you double-click on the res/layout/main.xml file in your project, you will not initially see that XML. Instead, you will be taken to the graphical layout editor: Figure 67: Android Studio Graphical Layout Editor We will go into much more detail about using the graphical layout editor in an upcoming chapter, as we start to work more with specific widgets and containers. Why Use XML-Based Layouts? Almost everything you do using XML layout files can be achieved through Java code. For example, you could use setText() to have a button display a certain caption, instead of using a property in an XML layout. Since XML layouts are yet another file for you to keep track of, we need good reasons for using such files. 135 THE ANDROID USER INTERFACE Perhaps the biggest reason is to assist in the creation of tools for view definition, such as the aforementioned graphical layout editors in Android Studio. Such GUI builders could, in principle, generate Java code instead of XML. The challenge is rereading the definition in to support edits — that is far simpler if the data is in a structured format like XML than in a programming language. Moreover, keeping the generated bits separated out from hand-written code makes it less likely that somebody’s custom-crafted source will get clobbered by accident when the generated bits get re-generated. XML forms a nice middle ground between something that is easy for tool-writers to use and easy for programmers to work with by hand as needed. Also, XML as a GUI definition format is becoming more commonplace. Microsoft’s XAML, Adobe’s Flex, Google’s GWT, and Mozilla’s XUL all take a similar approach to that of Android: put layout details in an XML file and put programming smarts in source files (e.g., JavaScript for XUL). Many less-well-known GUI frameworks, such as ZK, also use XML for view definition. While “following the herd” is not necessarily the best policy, it does have the advantage of helping to ease the transition into Android from any other XML-centered view description language. Using Layouts from Java Given that you have painstakingly set up the widgets and containers for your view in an XML layout file named main.xml stored in res/layout/, all you need is one statement in your activity’s onCreate() callback to use that layout, as we saw in our stub project’s activity: setContentView(R.layout.main); Here, R.layout.main tells Android to load in the layout (layout) resource (R) named main.xml (main). 136 Basic Widgets Every GUI toolkit has some basic widgets: fields, labels, buttons, etc. Android’s toolkit is no different in scope, and the basic widgets will provide a good introduction as to how widgets work in Android activities. We will examine a number of these in this chapter. Common Concepts There are a few core features of widgets that we need to discuss at the outset, before we dive into details on specific types of widgets. Widgets and Attributes As mentioned in a previous chapter, widgets have attributes that describe how they should behave. In an XML layout file, these are literally XML attributes on the widget’s element in the file. Usually, there are corresponding getter and setter methods for manipulating this attribute at runtime from your Java code. If you visit the JavaDocs for a widget, such as the JavaDocs for TextView, you will see an “XML Attributes” table near the top. This lists all of the attributes defined uniquely on this class, and the “Inherited XML Attributes” table that follows lists all those that the widget inherits from superclasses, such as View. Of course, the JavaDocs also list the fields, constants, constructors, and public/protected methods that you can use on the widget itself. This book does not attempt to explain each and every attribute on each and every widget. We will, however, cover the most popular widgets and the most commonlyused attributes on those widgets. 137 BASIC WIDGETS Referencing Widgets By ID Many widgets and containers only need to appear in the XML layout file and do not need to be referenced in your Java code. For example, a static label (TextView) frequently only needs to be in the layout file to indicate where it should appear. Anything you do want to use in your Java source, though, needs an android:id. The convention is to use @+id/... as the id value (where the ... represents your locally-unique name for the widget) for the first occurrence of a given id value in your layout file. The second and subsequent occurrences in the same layout file should drop the + sign. Android provides a few special android:id values, of the form @android:id/... — we will see some of these in various chapters of this book. To access our identified widgets, use findViewById(), passing it the numeric identifier of the widget in question. That numeric identifier was generated by Android in the R class as R.id.something (where something is the specific widget you are seeking). This concept will become important as we try to attach listeners to our widgets (e.g., finding out when a checkbox is checked) or when we try referencing widgets from other widgets in a layout XML file (e.g., with RelativeLayout). All of this will be covered later in this chapter. The Curious Case of the Cast Most sample code that you will see for Android will show the results of the findViewById() call being cast to some other class: TextView tv=(TextView)findViewById(R.id.name); That is because for most of Android’s existence, findViewById() returned a View, so we would need to down-cast that to a more appropriate class. However, if you are using Android Studio 3.0+, with an app with a compileSdkVersion of 26 or higher, you will notice that you no longer need those casts. Any existing ones will show up in gray, with a tooltip indicating that the cast is unnecessary. 138 BASIC WIDGETS What happened is that Android 8.0 changed findViewById() to return T, using Java generics to automatically cast it to the data type you request in the assignment. Casts are a compile-time thing in Java — they do not appear in compiled code and have no effects at runtime. As a result, code that skips the casts works perfectly fine on older devices as well. Size Most of the time, we need to tell Android how big we want our widgets to be. Occasionally, this will be handled for us — we will see an example of that with TableLayout in an upcoming chapter. But generally we need to provide this information ourselves. To do that, you need to supply android:layout_width and android:layout_height attributes on your widgets in the XML layout file. These attributes’ values have three flavors: 1. You can provide a specific dimension, such as 125dip to indicate the widget should take up exactly a certain size (here, 125 density-independent pixels) 2. You can provide wrap_content, which means the widget should take up as much room as its contents require (e.g., a TextView label widget’s content is the text to be displayed) 3. You can provide match_parent, which means the widget should fill up all remaining available space in its enclosing container The latter two flavors are the most common, as they are independent of screen size, allowing Android to adjust your view to fit the available space. Note that you will also see fill_parent. This is an older synonym for match_parent. match_parent is the recommended value going forward, but fill_parent will certainly work. This chapter focuses on individual widgets. Size becomes much more important when we start combining multiple widgets on the screen at once, and so we will be spending more time on sizing scenarios in later chapters. The layout_ prefix on these attributes means that these attributes represent requests by the widget to its enclosing container. Whether those requests will be truly honored will depend a bit on what other widgets there are in the container and what their requests are. 139 BASIC WIDGETS Introducing the Graphical Layout Editor If you open a layout resource in Android Studio, by default you will see the graphical layout editor: Figure 68: Android Studio Graphical Layout Editor This offers a drag-and-drop means of defining the contents of that layout resource. Android IDEs have had drag-and-drop GUI building capability for several years, dating back to when Eclipse was the official IDE. However, Android Studio 2.2 made some significant changes in the way the drag-and-drop GUI builder looks and works, and later updates have changed it further. This book covers the current look-andfeel, but older blog posts, Stack Overflow answers, and similar resources may refer to aspects of previous GUI builders. With all that in mind, let’s look at the different pieces of the graphical layout editor. Palette The upper-left side of the graphical layout editor is the Palette tool: 140 BASIC WIDGETS Figure 69: Palette Tool This lists all sorts of widgets and containers that you can drag and drop. They are divided into categories (“Widgets”, “Text”, “Layouts”, etc.) with many options in each. A few are not strictly widgets or containers but rather other sorts of XML elements that you can have in a layout resource (e.g., , ). As we cover how to use the graphical layout editor, we will see how to create and configure several of these widgets, containers, and other items. Preview The main central area of the graphical layout editor consists of two perspectives on your layout resource contents. The one on the left is a preview of what your UI should resemble, if this layout were used for the UI of an activity: 141 BASIC WIDGETS Figure 70: UI Preview This pours your layout resource contents into a preview frame that has aspects of a regular Android device, such as the navigation bar at the bottom and the status bar at the top. If you drag items out of the Palette and drop them into the preview area, they will be added to your layout resource. Blueprint To the right of the preview area is the blueprint view. This also visually depicts your layout resource. However, rather than showing you a preview of what your UI might look like, it visually represents what widget and container classes you are using. And, for some types of containers, it will show some of the sizing and positioning rules that you are using for children of that container: 142 BASIC WIDGETS Figure 71: Blueprint For a trivial layout resource, the blueprint view does not show you much. It will become more useful with more complex layout resources. In particular, it is very useful when you have designated some widgets or containers as being invisible, as they will show up in the blueprint but not in the preview: Figure 72: Layout Resource with Invisible TextView 143 BASIC WIDGETS Preview Toolbar Above the preview and blueprint is a bi-level toolbar that allows you to configure various aspects of the preview and blueprint appearance and behavior. Upper Toolbar Level From left to right, the upper level of the toolbar contains: • A drop-down to toggle whether you see the preview, the blueprint, or both • A toggle to control whether you are seeing the layout as applied to portrait or landscape perspectives • A drop-down to choose what device size and resolution should be used for the preview, culled from your emulator images and the available device definitions • A drop-down to choose what API level should be used for the simulated UI of the preview • A button to choose what theme to use for presenting the UI of the preview • A button to choose what language to use for determining which of your string resources gets used in the preview Figure 73: Preview Toolbar, Top Level A couple of those — particularly the theme selector — pertain to topics that we will explore later in the book. Lower Toolbar Level On the right side of the lower toolbar level are: • Zoom controls • A button to reset the zoom to fill the area available for the preview and/or blueprint • A button to enable “Pan and Zoom” mode (more on this shortly) • An “info” icon indicating if there are any warnings or errors associated with your layout resource 144 BASIC WIDGETS Figure 74: Preview Toolbar, Bottom Level, Right Side The left side of the bottom level of the preview toolbar will change, based upon the selected widget or container, offering options for you to be able to make simple changes to whatever is selected. We will see examples of this over the next few chapters Pan and Zoom Mode The “Pan and Zoom” mode allows you to navigate a zoomed-in version of your preview and/or blueprint. While the main views will be zoomed in, tapping the “Pan and Zoom” toolbar button opens up a floating window showing the entire preview and/or blueprint, with a red box indicating what portion of that you are seeing in the main views: Figure 75: Preview and Blueprint, with Pan and Zoom Enabled You can drag the red frame around the floating window to change what portion of the entire zoomed-in view you can see in the main view. Component Tree Towards the bottom-left corner is the component tree: 145 BASIC WIDGETS Figure 76: Component Tree This gives you a full tree of all of the widgets and containers inside of this layout resource. It corresponds to the tree of XML elements in the layout resource itself. Clicking on any item in the component tree highlights it in both the preview and blueprint views, plus it switches to that widget or container for the attributes pane. Attributes When a widget or container is selected — whether via the component tree, clicking on it in the preview, or clicking on it in the blueprint – the Attributes pane on the right will allow you to manipulate how that widget or container looks and behaves. By default, it will bring up a condensed roster of the most important attributes: Figure 77: Attributes Pane, Showing Condensed Roster 146 BASIC WIDGETS Clicking the “View all attributes” link, or the opposing-arrows toolbar button, switches to a list of all attributes: Figure 78: Attributes Pane, Showing Full Roster You can also click the magnifying glass icon in the toolbar of this pane to search for available attributes by name: Figure 79: Attributes Pane, Showing Search Results We will see what many of these attributes are and how to work with them over the course of the next few chapters. For the attributes in the full roster, you can click the star icon on the left to mark them as “favorites”: 147 BASIC WIDGETS Figure 80: Attributes Pane, Showing One Favorite Attribute Those favorite attributes show up in the condensed roster, in the section labeled “Favorite Attributes”. Text Tab Towards the bottom of the graphical layout tool, you will see that it contains two sub-tabs. One, “Design”, encompasses everything described above. The other, “Text”, allows you to edit the raw XML that is the actual content of the layout resource: Figure 81: Text Sub-Tab in Layout Editor By default, the entire area is devoted to the text editor. However, when the Text subtab is active, a “Preview” tool will appear docked on the right side of the Android Studio window. Clicking that will display the preview from the Design sub-tab: 148 BASIC WIDGETS Figure 82: Text Sub-Tab with Preview Clicking on items in the preview will highlight the corresponding XML element in the text editor. And Now, Some Notes About the Book’s Sample Projects This book profiles hundreds of sample apps, demonstrating everything from how to display text on the screen to how to scan NFC tags or work with the clipboard. These sample apps are housed in a Git repository on GitHub. They are all open source, and the vast majority are licensed under the Apache Software License 2.0, in case you copy any of the code. The Git repo uses tags that match the book version numbers (e.g., the v8.8 tag is for Version 8.8 of the book). Hence, to get the source code that matches your book version, you can: • Clone the repo (e.g., git clone https://github.com/commonsguy/ cw-omnibus.git) and then checkout a particular tag; or 149 BASIC WIDGETS • Download the ZIP archive associated with a particular book version For those projects that you wish to examine in Android Studio, you can use File > New > Import Project to import the project. However, you have to do this on a project-by-project basis, importing each project directory as needed. Roughly speaking, any directory that has settings.gradle in it is a project directory, particularly with respect to this book’s samples. Starting with the next section, the book will be displaying code from these sample projects. Links will point you to a particular sample project or to a specific file in that project, such as a layout resource or Java source file. Those links go to the GitHub repository, but you can use that information to help you identify where the corresponding file is on your development machine, if you elected to download the code. Assigning Labels The simplest widget is the label, referred to in Android as a TextView. Like in most GUI toolkits, labels are bits of text not editable directly by users. Typically, they are used to identify adjacent widgets (e.g., a “Name:” label before a field where one fills in a name). In Java, you can create a label by creating a TextView instance. More commonly, though, you will create labels in XML layout files by adding a TextView element to the layout, with an android:text attribute to set the value of the label itself. If you need to swap labels based on certain criteria, such as internationalization, you may wish to use a string resource reference in android:text instead (e.g., @string/ label). For example, in our last tutorial, we still are using the automatically-generated res/ layout/main.xml file, containing, among other things, a TextView: > (from EmPubLite-AndroidStudio/T4-Resources/EmPubLite/app/src/main/res/layout/main.xml) Android Studio Graphical Layout Editor The TextView widget is available in the “Widgets” category of the Palette in the Android Studio graphical layout editor: Figure 83: Palette, “Plain TextView” in Widgets Category You can drag that TextView from the palette into a layout file in the main editing area to add the widget to the layout. Or, drag it over the top of some container you see in the Component Tree pane of the editor to add it as a child of that specific container. Clicking on the new TextView will set up the Attributes pane with the various attributes of the widget, ready for you to change as needed. Editing the Text The “Text” attribute will allow you to choose or define a string resource to serve as the text to be displayed: 151 BASIC WIDGETS Figure 84: Attributes Pane, Showing TextView “text” Attribute The “text” with a wrench icon allows you to provide a separate piece of text that will show up in the preview, but not be used by your app at runtime. You can either type a literal string right in the Attributes pane row, or you can click the “…” button to the right of the field to pick a string resource: Figure 85: String Resources Dialog You can highlight one of those resources and click “OK” to use it. Or, towards the upper-right of that dialog, there is an “Add new resource” drop-down. When viewing string resources, that drop-down will contain a single command: “New string 152 BASIC WIDGETS Value…”. Choosing it will allow you to define a new string resource via another dialog: Figure 86: New String Resource Dialog You can give your new string resource a name, the actual text of the string itself, the filename in which the string resource should reside (strings.xml by default), and which values/ directory the string should go into (values by default). You will also choose the “source set” — for now, that will just be main. Once you accept the dialog, your new string resource will be applied to your TextView. Editing the ID The “id” attribute will allow you to change the android:id value of the widget: 153 BASIC WIDGETS Figure 87: Attributes Pane, with TextView “id” Attribute Selected The value you fill in here is what goes after the @+id/ portion (e.g., textView2). Notable TextView Attributes TextView has numerous other attributes of relevance for labels, such as: 1. android:typeface to set the typeface to use for the label (e.g., monospace) 2. android:textStyle to indicate that the typeface should be made bold (bold), italic (italic), or bold and italic (bold_italic) 3. android:textColor to set the color of the label’s text, in RGB hex format (e.g., #FF0000 for red) or ARGB hex format (e.g., #88FF0000 for a translucent red) These attributes, like most others, can be modified through the Attributes pane. For example, in the Basic/Label sample project, you will find the following layout file: (from Basic/Label/app/src/main/res/layout/main.xml) Just that layout alone, with the stub Java source provided to your app, along with appropriate string resources, gives you: 154 BASIC WIDGETS Figure 88: The LabelDemo Sample Application A Commanding Button Android has a Button widget, which is your classic push-button “click me and something cool will happen” widget. As it turns out, Button is a subclass of TextView, so everything discussed in the preceding section in terms of formatting the face of the button still holds. For example, in the Basic/Button sample project, you will find the following layout file: > > /> 1080 any widget TESTING WITH ESPRESSO (from Testing/EspressoMatcher/app/src/main/res/layout/main.xml) As it turns out, TextInputLayout has its own internal structure. onView(withParent(withTILHint("URL"))) will fail, indicating that more than one View matches. So, we use Hamcrest’s allOf() method, which creates a matcher that uses a boolean AND operation on all supplied matchers — all have to match for allOf() to consider it a match. So, we also use instanceOf() to constrain us to TextInputEditText widgets. That, finally, gives us our TextInputEditText widget, and makes us glad that we can use android:id in our own code and avoid all of this hassle. To complete our testing, we call perform() to perform some actions on the TextInputEditText. perform() can execute any number of actions, and here we are performing two: 1. typeText(), to type in a URL (identified here as a URL constant) 2. closeSoftKeyboard(), to ensure that the soft keyboard has collapsed after testing If we did not perform() closeSoftKeyboard(), the tests would work in portrait mode, but not in landscape, given the way that the full-screen landscape input method editor works. We then: • Set up to stub the ACTION_VIEW Intent request, with a throwaway response • click() the browse button • Validate that we did invoke an ACTION_VIEW Intent with the proper URL Opting Out of Analytics All of the build.gradle files shown in this chapter have the following line in defaultConfig: testInstrumentationRunnerArguments disableAnalytics: 'true' By default, your Espresso tests send data about your tests to Google. This line passes arguments to the test runner that disable these analytics. 1081 TESTING WITH ESPRESSO Waiting for the World to Change Our activities often trigger asynchronous work: loading data from a database, loading content from a ContentProvider, executing a Web service call, etc. Sometimes, that work is triggered by the start of the activity. Sometimes, that work is triggered by UI events. Usually, our tests need to wait for that work to complete before we can proceed with confirming the results. For example, if tapping an action bar item refreshes the RecyclerView contents via some asynchronous work, we cannot determine whether or not the refresh worked until that asynchronous operation ends. Even simpler things would seem to need more synchronization than we are writing in our tests. Let’s go back to the keyEvents() test from earlier in this chapter: @Test public void keyEvents() { onView(withId(android.R.id.list)) .perform(pressKey(KeyEvent.KEYCODE_DPAD_DOWN), pressKey(KeyEvent.KEYCODE_DPAD_DOWN), pressKey(KeyEvent.KEYCODE_DPAD_DOWN), pressKey(KeyEvent.KEYCODE_DPAD_DOWN)) .check(new new ListSelectionAssertion(3)); } (from Testing/Espresso/app/src/androidTest/java/com/commonsware/android/abf/test/DemoActivityRuleTest.java) We simulate four down-arrow presses, then check to see if the proper list row is selected. However, keyEvents() runs on a background thread, not the main application thread. In theory, there is a race condition here: will the work associated with those four down-arrow events be completed by the time we go to check the selection state of the ListView? It turns out that Espresso handles this automatically. It waits until the work queue for the main application thread shows that there is no more work ready to process. Then, and only then, will the check() logic be applied. Espresso also waits on select other things, notably AsyncTasks. And, through an IdlingResource, we can teach it to wait for other asynchronous work: arbitrary threads, an IntentService, and so on. 1082 TESTING WITH ESPRESSO What’s an IdlingResource? An IdlingResource is an interface. Implementations of it know how to monitor some background work for completion. You can register an IdlingResource with Espresso via Espresso.registerIdlingResources(), later removing it via Espresso.unregisterIdlingResources(). An IdlingResource needs to do two main things: 1. Return whether the resource being monitored is idle at the moment, via an isIdleNow() method 2. Track a ResourceCallback instance and call an onTransitionToIdle() method on it when the resource becomes idle Using an IdlingResource In some cases, you will be able to use a pre-built IdlingResource. Espresso itself comes with a CountingIdlingResource that you can use a bit like a CountDownLatch, calling increment() when work is added and decrement() when work is completed. When the counter falls to zero from a non-zero value, the CountingIdlingResource will call onTransitionToIdle() on its ResourceCallback. And, isIdleNow() is simply based on the counter. Sometimes, you will find existing implementations from third parties. For example, Jake Wharton has written an OkHttp3IdlingResource for use with OkHttp3. The Testing/EspressoIdle sample project demonstrates its use. The activity under test is a variation on the OkHttp3 “show the latest Stack Overflow questions” sample from the chapter on Internet access. That activity (MainActivity) holds an OkHttpClient instance to be used by its fragment, returned via a getOkHttpClient() method: package com.commonsware.android.okhttp; import import import import import android.app.Activity android.app.Activity; android.content.Intent android.content.Intent; android.net.Uri android.net.Uri; android.os.Bundle android.os.Bundle; okhttp3.OkHttpClient okhttp3.OkHttpClient; public class MainActivity extends Activity 1083 TESTING WITH ESPRESSO implements QuestionsFragment.Contract { private final OkHttpClient client= new OkHttpClient.Builder().build(); @Override protected void onCreate(Bundle savedInstanceState) { super super.onCreate(savedInstanceState); if (getFragmentManager().findFragmentById(android.R.id.content) == null null) { getFragmentManager().beginTransaction() .add(android.R.id.content, new QuestionsFragment()).commit(); } } @Override public void onQuestion(Item question) { startActivity(new new Intent(Intent.ACTION_VIEW, Uri.parse(question.link))); } OkHttpClient getOkHttpClient() { return return(client); } } (from Testing/EspressoIdle/app/src/main/java/com/commonsware/android/okhttp/MainActivity.java) QuestionsFragment then uses OkHttp3 to request the latest 100 Stack Overflow questions, parsing the JSON response with Gson, and loading them into the fragment’s ListView. This is handled in the onViewCreated() method: @Override public void onViewCreated(final final View view, Bundle savedInstanceState) { super super.onViewCreated(view, savedInstanceState); OkHttpClient client=((MainActivity)getActivity()).getOkHttpClient(); Request request=new new Request.Builder().url(SO_URL).build(); client.newCall(request).enqueue(new new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(getClass().getSimpleName(), "Exception loading JSON", e); } @Override public void onResponse(Call call, Response response) 1084 TESTING WITH ESPRESSO throws IOException { if (response.isSuccessful()) { Reader in=response.body().charStream(); BufferedReader reader=new new BufferedReader(in); final SOQuestions questions= new Gson().fromJson(reader, SOQuestions.class); reader.close(); view.post(new new Runnable() { @Override public void run() { setListAdapter(new new ItemsAdapter(questions.items)); } }); } else { Log.e(getClass().getSimpleName(), response.toString()); } } }); } (from Testing/EspressoIdle/app/src/main/java/com/commonsware/android/okhttp/QuestionsFragment.java) Note that onViewCreated() uses enqueue(), rather than execute(), so the HTTP request is performed on an OkHttp3-supplied background thread. We do not know if this is an AsyncTask or some other type of thread, and so we do not know for certain if Espresso will know to wait until this request is complete. Hence, in our tests, we really should use an IdlingResource to confirm that the asynchronous work is completed before seeing if the results match our expectations. The OkHttpTests instrumentation test class uses an ActivityRule, named main, to set up our activity under test. The moreReliableAsyncTest() method then uses OkHttp3IdlingResource to help out our test code: @Test public void moreReliableAsyncTest() { IdlingResource idleWild= OkHttp3IdlingResource.create("okhttp3", main.getActivity().getOkHttpClient()); Espresso.registerIdlingResources(idleWild); try { onView(withId(android.R.id.list)) 1085 TESTING WITH ESPRESSO .check(new new AdapterCountAssertion(100)); } finally { Espresso.unregisterIdlingResources(idleWild); } } (from Testing/EspressoIdle/app/src/androidTest/java/com/commonsware/android/okhttp/OkHttpTests.java) An IdlingResource has a name, which needs to be unique among registered IdlingResource instances. So, we use okhttp3. OkHttp3IdlingResource also needs our OkHttpClient, which we can get by retrieving it from the MainActivity, which is available to us courtesy of the main ActivityRule. We then: • Call registerIdlingResources() to register our OkHttp3IdlingResource • Perform our tests, to confirm that we got 100 items in the list • Call unregisterIdlingResource(), as we can no longer use our OkHttp3IdlingResource once the activity is destroyed; any new activity instances will have their own OkHttpClient in our implementation Implementing a Custom IdlingResource A custom IdlingResource can be simple or complex, depending on how difficult it is to determine whether a resource is idling and when it starts idling. In the case of OkHttp3IdlingResource, OkHttp3 itself exposes a API, in the form of a Dispatcher object, that provides an API ideal for an IdlingResource: • A Dispatcher has runningCallsCount() for use by isIdleNow() • A Dispatcher has setIdleCallback(), to be called when the running calls count drops to zero In this case, the reason for the clean integration may be tied to the fact that Jake Wharton works on OkHttp3. Sometimes, you have to use a less elegant approach, because the resource you wish to monitor does not offer an appropriate monitoring API. Chiu-ki Chan wrote an IntentServiceIdlingResource that uses ActivityManager to watch for when a specific IntentService implementation is no longer listed as a running service. There is no way to register a callback with Android to find out when an arbitrary 1086 TESTING WITH ESPRESSO service is destroyed, so she only invokes the ResourceCallback onTransitionToIdle() method as part of isIdleNow() processing. 1087 Testing with UI Automator Yet another approach for testing Android applications is UI Automator. This is designed for integration testing, both how your app components integrate with one another (e.g., activities starting activities) and how your app components integrate with the rest of a device, including other applications. In early 2015, Google released version 2.0 of the UI Automator framework. This update ties UI Automator into the same instrumentation testing engine that is used for JUnit4 testing. This also makes it possible to run UI Automator tests through Android Studio and the Android Gradle Plugin, which previously had been difficult. Prerequisites This chapter assumes that you have read the chapter on JUnit4. What Is UI Automator? UI Automator, as the name suggests, automates UIs. It simulates user input, in the form of tapping on items and the like. It does so without modifying your process’ contents. Tests run by UI Automator are implemented in JUnit, and those tests have limited access to the widgets inside of a UI. Such access not only allows for directing simulated user input (e.g., “click the OK button”), but also for asserting that various test conditions are true (e.g., “does the list have five rows?”). In this respect, UI Automator behaves like traditional Android JUnit testing. 1089 TESTING WITH UI AUTOMATOR Why Choose UI Automator Over Alternatives? In some respects, UI Automator represents the worst of both worlds. You have to use JUnit, making test authoring a challenge for those not skilled with Java. Yet you only have fairly generic access to an activity’s widgets, versus the complete white-box capability of normal instrumentation-based JUnit testing. Hence, why would anyone bother? The big thing that UI Automator offers over classic JUnit testing is greater ability to test an application versus testing individual components. The classic JUnit test cases are organized around testing some specific component, such as using ActivityInstrumentationTestCase2 to exercise some specific activity. Testing the flow of work between activities is difficult from classic JUnit, but is relatively easy with UI Automator. You can also use this for integration testing, as you can exercise and analyze applications other than your own, such as to confirm that you are starting a third-party app correctly. Similarly, classic JUnit testing cooks up activity instances “out of thin air”. Instead, UI Automator executes normal UI operations to create the activities, such as tapping on your app’s icon in the home screen launcher. This more accurately simulates what a user will do — users are far more likely to tap on a launcher than to hack into your Dalvik VM and manually instantiate an activity. You can see a set of UI Automator tests in a suitable project in the Testing/ UiAutomator directory. Note, though, that the UI Automator tests will only work successfully on Android 4.x emulators, and perhaps a few other environments. The tests are testing the integration of the home screen to the app, along with the app’s functionality, and the particular code used to navigate the home screen will only work with the stock Android home screen, not necessarily any manufacturer’s home screen or third-party home screen. Gradle and Android Studio Settings Your project needs to be set up to use the AndroidJUnitRunner as is outlined in the chapter on JUnit4. For UI Automator, you additionally need to have an androidTestImplementation dependency on the uiautomator-v18 artifact: 1090 TESTING WITH UI AUTOMATOR dependencies { androidTestCompile 'com.android.support.test:rules:0.3' androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.0' } (from Testing/UiAutomator/build.gradle) Here the -v18 suffix, as with the regular Android Support package libraries, means that this only works on API Level 18 and higher. If you wish to run the tests from Android Studio, you will also need to set up a run configuration, as outlined in the chapter on JUnit4. Creating a Test Case Your test case classes do not need to inherit from any particular base class, just like regular JUnit4 tests. They do need to be annotated with the @RunWith(AndroidJUnit4.class) annotation: @RunWith(AndroidJUnit4.class) public class ListTests { (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) Your test case is welcome to have @Before, @After, and other setup/teardown methods, in addition to @Test methods, just like a regular JUnit4 test case. In fact, from Android’s standpoint, UI Automator tests are just regular JUnit4 test cases — you are welcome to have UI Automator test cases and regular instrumentation testing JUnit4 test cases in the same androidTest source set. Performing Device-Level Actions The root of most of our work with UI Automator is a UiDevice object. This allows us to perform device-level actions, such as pressing BACK or HOME. To get a UiDevice, call the static getInstance() method on UiDevice, passing in the Instrumentation that you get from InstrumentationRegistry.getInstrumentation(): @Before public void setUp() throws UiObjectNotFoundException { device=UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); openActivity(); } 1091 TESTING WITH UI AUTOMATOR (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) Here, we get the UiDevice and stash it in a data member for the life of this ListTests instance. UiDevice has many methods that allow you to perform device-level actions, such calling pressHome() to press the HOME button (and thereby bring up the home as screen). Similarly, you can call: • • • • pressBack() and pressMenu() for the BACK and MENU buttons pressDPadUp(), pressDPadLeft(), etc. for D-pad events pressRecentApps() to bring up the recent tasks list pressKeyCode() to press an arbitrary key based on the keycode from KeyEvent …and so on. Inspecting and Interacting with the UI Of course, pressing some buttons is not especially useful on its own, only as a means to an end, such as launching your activity. To do more than this, you will need to get your hands on widgets and containers, to perform operations related to them. The key is that you can “get your hands on widgets and containers” from whatever activity is in the foreground. This is not limited to your own app, but rather works for any app, including the home screen itself. The following sections will work through some common UI Automator operations, in the context of the openActivity() from the ListTests class in the sample project. This method, called from setUp(), consolidates the work to bring an instance of our production activity to the foreground, by means of interacting with the home screen: private void openActivity() throws UiObjectNotFoundException { device.pressHome(); UiObject allAppsButton= device.findObject(new new UiSelector().description("Apps")); allAppsButton.clickAndWaitForNewWindow(); UiObject appsTab=device.findObject(new new UiSelector().text("Apps")); appsTab.click(); 1092 TESTING WITH UI AUTOMATOR UiScrollable appViews= new UiScrollable(new new UiSelector().scrollable(true true)); appViews.setAsHorizontalList(); UiObject ourApp= appViews.getChildByText(new new UiSelector().className("android.widget.TextView"), "Action Bar Fragment Demo"); ourApp.clickAndWaitForNewWindow(); UiObject appValidation= device.findObject(new new UiSelector().packageName("com.commonsware.android.abf")); Assert.assertTrue("Could not open test app", appValidation.exists()); } (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) Finding and Interacting with Widgets openActivity() starts by calling pressHome() on the UiDevice, to ensure that the home screen is in the foreground: device.pressHome(); (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) Next, we want to bring up the home screen’s launcher, showing the available launchable activities, so that we can find our app and launch it. What a user would do, on a stock Android environment like an emulator, would be to click on the appropriate button to bring up the launcher. We need to do the same thing, except from our test code. This implies: • Finding that widget • Simulating a click of that widget Web developers are used to finding DOM nodes by CSS queries. Developers using XML are used to using XPath queries to find particular elements. Along the same lines, UI Automator gives us a flexible system to find widgets in the foreground activity, by means of a UiSelector object, typically created using the public zeroargument constructor (i.e., new UiSelector()). In CSS, a “selector” can identify DOM nodes by class, id, or ones with particular properties. A UiSelector can do much the same thing. So, the first UiSelector created in openActivity() will find a widget in the foreground activity whose “description” is Apps (new UiSelector().description("Apps")). Here, “description” 1093 TESTING WITH UI AUTOMATOR will mean either the text of a TextView or the android:contentDescription of other types of widgets. How do we know that this particular button has a “description” of Apps? In this case, we found out using uiautomatorviewer, which will be discussed in a future update to this chapter. By passing our UiSelector to findObject() on the UiDevice, we get a UiObject that, hopefully, knows how to interact with this particular button of the home screen. In particular, we call clickAndWaitForNewWindow() on it, which taps the button and blocks until something else (e.g., a new activity) has taken over the foreground: UiObject allAppsButton= device.findObject(new new UiSelector().description("Apps")); allAppsButton.clickAndWaitForNewWindow(); (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) The stock Android launcher has two tabs, one for apps and one for (app) widgets. We need to ensure that the apps tab is selected. So, once again, we create a UiSelector and use it to create a UiObject to represent the apps tab. This time, we use text() instead of description(). text() will find a widget based solely on its display text (e.g., android:text of a TextView). In truth, we could have used description() here as well, with the same results. Then, we call click() on the UiObject, to simulate a tap on this tab, to ensure that is the selected tab. UiObject appsTab=device.findObject(new new UiSelector().text("Apps")); appsTab.click(); (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) Dealing with Collections Finding widgets by text or description is fairly easy when there is only one possible widget that has that text or description. Things get more complicated when you are dealing with a collection of widgets, such as an AdapterView. 1094 TESTING WITH UI AUTOMATOR For example, the Apps tab of the standard Android launcher uses a GridView to show up to 20 launchable activities. Then, you need to swipe horizontally, courtesy of a ViewPager, to uncover additional GridView collections of launchable activities. A UiCollection helps deal with this, in terms of allowing you to inspect a collection of widgets, including performing the necessary swipe operations to access all of the contents. A UiSelector called with scrollable(true) will return a widget that is scrollable. Creating a UiCollection with that UiSelector will create a UiCollection around the first scrollable widget. In the case of the Apps tab, that will be the ViewPagerand-GridView combination. In our case, to get to other elements in the collection, you need to swipe horizontally. To configure the UiCollection that way, we have to call setAsHorizontalList() on the UiCollection: UiScrollable appViews= new UiScrollable(new new UiSelector().scrollable(true true)); appViews.setAsHorizontalList(); UiObject ourApp= appViews.getChildByText(new new UiSelector().className("android.widget.TextView"), "Action Bar Fragment Demo"); (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) Finding Widgets By Type In that collection, we want to find the item that contains our app’s caption. This test project is designed to test the same sample app that was tested in the JUnit chapter, a slightly modified version of an early action bar sample. Our launcher entry’s name will be “Action Bar Fragment Demo”, as that is what we set up in the production project’s manifest and string resources. So, we need to find the entry in the ViewPager-of-GridViews that has that title. To do that, we will create yet another UiSelector. This time, though, we will find widgets by type, specifying className("android.widget.TextView") to only work with TextView widgets. That UiSelector is passed into the getChildByText() method of UiCollection, which will iterate over the children to find the first one that matches the UiSelector and where the selected widget contains the supplied text: 1095 TESTING WITH UI AUTOMATOR UiObject ourApp= appViews.getChildByText(new new UiSelector().className("android.widget.TextView"), "Action Bar Fragment Demo"); (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) Then, we again call clickAndWaitForNewWindow(), to tap on our launcher entry, triggering our app’s activity to come to the foreground: ourApp.clickAndWaitForNewWindow(); (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) Asserting Conditions UiSelector and UiObject can also be used for some operations that do not fit the normal widgets-and-containers pattern shown above. For example, now that we have opened a window from our app to be tested, it would be nice to confirm that, indeed, this is our app, and that our openActivity() method did not open some other app by mistake. To do this, we can create a UiSelector and apply packageName(), to constrain the selection to widgets coming from an app with our desired package name: UiObject appValidation= device.findObject(new new UiSelector().packageName("com.commonsware.android.abf")); (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) The UiObject we create always exists (i.e., is not null), as we are creating it via the constructor. However, it is entirely possible that our UiSelector cannot match any widget, such as would be the case if we accidentally opened the wrong app and tried to find a widget stemming from our package. The exists() method on a UiObject returns true if the UiObject is pointing at an actual widget, false otherwise. Hence, we can assert that we indeed have a widget coming from our package: Assert.assertTrue("Could not open test app", appValidation.exists()); (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) The net result is that we open our main activity and confirm that, indeed, that is what we opened. 1096 TESTING WITH UI AUTOMATOR And Now… The Real Test Methods All of that was just to get the activity for testing onto the screen. Now the real testing begins. The ListTests class has two test methods, testContents() and testAdd(), designed to (lightly) exercise the UI. testContents() The objective of the testContents() method is to confirm that the 25 words all appear in the ListView. To do that, we: • Create a UiScrollable for a UiSelector that finds the ListView in our activity • Mark that UiScrollable as being a vertical list, where swipes up and down will expose the various children • Iterate over the array of words, finding the TextView for each word and confirming that this widget does indeed exist @Test public void testContents() throws UiObjectNotFoundException { UiScrollable words= new UiScrollable( new UiSelector().className("android.widget.ListView")); words.setAsVerticalList(); for (String s : items) { Assert.assertNotNull("Could not find " + s, words.getChildByText(new new UiSelector().className("android.widget.TextView"), s)); } } (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) testAdd() The objective of the testAdd() method is to add a new word to the list, via the EditText widget in our action bar, then confirm that the new word was actually added to the list. 1097 TESTING WITH UI AUTOMATOR To do that, we: • Retrieve the EditText by finding the widget whose text is “Word” (the hint of our EditText) • Call setText() to fill in snicklefritz into the EditText widget, which UiObject accomplishes by actually typing in the value • Call pressEnter() on the UiDevice to simulate pressing the Enter key of a keyboard, which will trigger our action listener in the test activity and will add the word to the list • Create a UiScrollable for a UiSelector that finds the ListView in our activity • Mark that UiScrollable as being a vertical list, where swipes up and down will expose the various children • Try to find a TextView whose text is snicklefritz and assert that it was found @Test public void testAdd() throws UiObjectNotFoundException { UiObject add=device.findObject(new new UiSelector().text("Word")); add.setText("snicklefritz"); device.pressEnter(); UiScrollable words= new UiScrollable( new UiSelector().className("android.widget.ListView")); words.setAsVerticalList(); Assert.assertNotNull("Could not find snicklefritz", words.getChildByText(new new UiSelector().className("android.widget.TextView"), "snicklefritz")); } (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) Cleaning Up Our ListTests class also has a tearDown() method, invoked by JUnit after each test method courtesy of the @After annotation. Here, we press BACK twice, to return us to the main home screen from our activity, setting things back up for the next test method: @After public void tearDown() { device.pressBack(); device.pressBack(); } 1098 TESTING WITH UI AUTOMATOR (from Testing/UiAutomator/src/androidTest/java/com/commonsware/android/abf/uiautomator/ListTests.java) Running Your Tests You run your UI Automator tests as you would any other instrumentation test: • By running the run configuration that you set up for your tests in Android Studio • By running commands like gradle connectedCheck at the command line • Through integrations into your continuous integration server or similar build infrastructure Finding Your Widgets The key to finding your desired widgets stems in large part from the text() or description() methods on UiSelector. Of those two, the latter is more flexible, as it will use the android:contentDescription from any widget, while text() is limited to TextView and its subclasses. However, this implies that your widgets have android:contentDescription defined. This is also important for accessibility, and therefore is a good idea regardless of its use with UI Automator. For testing your own code, you can also find widgets via their resource IDs. UiSelector has resourceId() and resourceIdMatches() methods to configure the resource ID you want. As the resourceIdMatches() method name suggests, the resource ID here is a string representation of the resource name. It will be of the form your.app.package:id/resource (e.g., com.commonsware.android.hotkey:id/ editor). However: • Note that this requires API Level 18 or higher versions of the two JARs (UI Automator.jar and android.jar) • Note that this requires running the tests on an API Level 18+ device or emulator • Bear in mind that third party apps are welcome to rename their widgets when they wish, so your integration tests may break when third parties do so 1099 TESTING WITH UI AUTOMATOR Using the UI Automator Viewer Identifying widgets can be a bit tricky with UI Automator. Identifying widgets in other apps, for your integration tests, would in theory be next to impossible. After all, while the Android Studio layout inspector and the older Hierarchy View tools can give you widget IDs, that only works with debuggable apps. Your app may be debuggable, but the app you are trying to integrate with probably is not. Fortunately, we have the UI Automator Viewer. This tool basically walks the view hierarchy of whatever activity is in the foreground of a device (or emulator) and gives us access to whatever information is exposed by the accessibility APIs. Nowadays, this includes widget IDs, in addition to more traditional accessibility data like the text in a TextView, the contentDescription of an ImageView, and so on. At the present time, the UI Automator Viewer is not integrated into Android Studio or the Android Device Monitor GUIs. Instead, you will have to launch it the oldfashioned way, by running the uiautomatorviewer command from the command line. This will map to a batch file or shell script in the tools/ directory of your Android SDK installation. When initially launched, the UI Automator Viewer does not look like much: 1100 TESTING WITH UI AUTOMATOR Figure 358: UI Automator Viewer, As Initially Launched Given that you have a device or emulator ready, you can click the second icon from the left in the toolbar, to capture the view hierarchy of the foreground activity. This will give you: • A screenshot of the foreground activity in the main area of the UI Automator Viewer screen • The view hierarchy of that activity, in the upper-right corner of the UI Automator Viewer screen • Properties of a node from the selected view, in the lower-right corner of the UI Automator Viewer screen 1101 TESTING WITH UI AUTOMATOR Figure 359: UI Automator Viewer, Showing View Hierarchy of This Book’s Reader App Clicking either on the preview or on the view hierarchy will change the selected view, which shows up with a red dashed outline on the preview. The properties (“Node Detail”) pane will then update to show the properties of whatever is newly selected. This is not only useful for identifying widgets for testing with UI Automator, but it can also be used to determine how some other developer pulled off some interesting UI approach. While simply examining a widget hierarchy is not going to uncover all the other developer’s secrets, simply knowing what widgets were used, and some basic properties of those widgets, may give you some ideas for avenues of research. 1102 Measuring Test Coverage Test coverage is our way of determining whether or not we have adequately tested our code. Part of the work that has gone into the Android Gradle Plugin has been to make obtaining test coverage reports fairly easy, so ideally it is something that you can incorporate into your regular testing regimen. In this chapter, we will explore the concept of test coverage in general, along with how to generate coverage reports for your Android instrumentation tests. Prerequisites Understanding this chapter requires that you have read the chapter on instrumentation testing with JUnit. Who Tests the Testers? We use tests to determine if our code works. More generally, we use tests as a way of quantifying the quality of our code. Code that fails the tests is of lower quality than is code that does not fail the tests. Right? Suppose we have some Java code that will result in divide-by-zero exception. We have two developers test that code. One developer writes tests and uncovers the exception. The other developer writes tests that bypasses the flawed code, and therefore does not uncover the exception. Here, the code quality is the same, but the test quality differs. 1103 MEASURING TEST COVERAGE If the way we measure code quality is “does it pass the tests”, measuring test coverage asks “do the tests adequately test the code?”. In the preceding example, either: • The second developer would have worse test coverage than the first developer, as the second developer clearly is not testing everything, or • Both developers would have poor test coverage, and it just so happens that one stumbled upon the bug (“Even a blind squirrel finds a nut once in a while”) What you want is to have a test suite that has 100% practical coverage. The “practical” qualifier is because there are certain portions of our code that may be impractical to test, because they depend upon certain environmental factors that are different to arrange to happen on demand (e.g., OutOfMemoryError). There, the objective is to have as little code specifically dependent upon those factors, moving more of it into code that we can test without requiring those conditions. Some Types of Test Coverage Some developers that start in on test coverage think that test coverage is fairly simple to measure: did we run everything? The problem is that “run” has different meanings in different circumstances, and as a result measuring coverage can be done in different ways. Statement Coverage The basic approach to measuring test coverage is: did we execute every line of Java code? Clearly, if we never executed a line of code, we did not test that line and have no idea if that line works or not. Branch Coverage However, just because we execute a line does not mean that we have executed it under all conditions. Imagine a Java method like this: void doSomething(boolean flag) { if (flag) { // do one thing } else { // do something else 1104 MEASURING TEST COVERAGE } } If this method were in our own Java code, we could determine whether we have tested both true and false cases by means of statement coverage. Either we executed the statements in both branches, or we did not. However, suppose the method instead looked like this: void doSomething(boolean flag) { if (flag) { // do one thing } // do something regardless of the flag value } Now, 100% statement coverage tells us that we executed the contents of the if block. However, it does not tell us if we have tested the case where flag is false, since no additional statements are executed for that case. Branch coverage, therefore, measures whether our if and switch statements have covered all scenarios. We might have 100% statement coverage but below 100% branch coverage. Loop Coverage The coverage capability integrated into Android Studio offers statement and branch coverage. This does not mean that it includes all forms of coverage measurement. Another common one is loop coverage. Imagine your typical Java for loop: void doSomething(int count) { for (int i=0;i Package option in the context menu, if you right-click over the java/ directory. As with other JUnit testing, your choice of package dictates what you can and cannot access of classes and objects being tested: 1116 UNIT TESTING Test Package PublicPackage-PrivatePrivate same as class being tested yes yes no different than class being tested yes no no In the sample project, the test code is in the same Java package as is the main application code, so tests can access public and package-private fields, methods, and the like. Writing a Test Case We can have a SillyTest test case, just as in the chapter on JUnit4. However, we do not need the @RunWith annotation on the class: package com.commonsware.android.unittest; import import import import import import junit.framework.Assert junit.framework.Assert; org.junit.After org.junit.After; org.junit.AfterClass org.junit.AfterClass; org.junit.Before org.junit.Before; org.junit.BeforeClass org.junit.BeforeClass; org.junit.Test org.junit.Test; public class SillyTest { @BeforeClass static public void doThisFirstOnlyOnce() { // do initialization here, run once for all SillyTest tests } @Before public void doThisFirst() { // do initialization here, run on every test method } @After public void doThisLast() { // do termination here, run on every test method } @AfterClass static public void doThisLastOnlyOnce() { // do termination here, run once for all SillyTest tests } @Test public void thisIsReallySilly() { 1117 UNIT TESTING Assert.assertEquals("bit got flipped by cosmic rays", 1, 1); } } (from UnitTest/POJO/app/src/test/java/com/commonsware/android/unittest/SillyTest.java) If you created your project through the Android Studio new-project wizard, and it already had a test/ source set for you, it would have created a similarly-silly ExampleUnitTest test case for you: public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2+2); } } Of course, you can start writing your own test cases that are somewhat less silly. Here, we have a test case that confirms the toString() behavior of the Item class: package com.commonsware.android.unittest; import junit.framework.Assert junit.framework.Assert; import org.junit.Test org.junit.Test; public class ItemTests { private static final String TITLE="this is a title"; private static final String URL="https://commonsware.com"; @Test public void iCanHazString() { Item item=new new Item(); item.title=TITLE; item.link=URL; Assert.assertEquals(TITLE, item.toString()); } } (from UnitTest/POJO/app/src/test/java/com/commonsware/android/unittest/ItemTests.java) Testing loading the questions gets a bit tricky, as our StackOverflowInterface is set up for asynchronous operation. When we call questions() to get the questions, we get control back immediately, and we need to wait for the background thread to 1118 UNIT TESTING deliver our results. There are a few patterns for handling this. This particular test case uses a CountDownLatch: package com.commonsware.android.unittest; import import import import import import import import junit.framework.Assert junit.framework.Assert; org.junit.Before org.junit.Before; org.junit.Test org.junit.Test; java.util.concurrent.CountDownLatch java.util.concurrent.CountDownLatch; retrofit.Callback retrofit.Callback; retrofit.RestAdapter retrofit.RestAdapter; retrofit.RetrofitError retrofit.RetrofitError; retrofit.client.Response retrofit.client.Response; public class SOTests { private CountDownLatch responseLatch; private SOQuestions questions; @Before public void setUp() { responseLatch=new new CountDownLatch(1); } @Test(timeout=30000) public void fetchQuestions() throws InterruptedException { RestAdapter restAdapter= new RestAdapter.Builder() .setEndpoint("https://api.stackexchange.com") .build(); StackOverflowInterface so= restAdapter.create(StackOverflowInterface.class); so.questions("android", new Callback() { @Override public void success(SOQuestions soQuestions, Response response) { questions=soQuestions; responseLatch.countDown(); } @Override public void failure(RetrofitError error) { responseLatch.countDown(); } }); responseLatch.await(); 1119 UNIT TESTING Assert.assertNotNull(questions); Assert.assertEquals(30, questions.items.size()); for (Item item : questions.items) { Assert.assertNotNull(item.title); Assert.assertNotNull(item.link); } } } (from UnitTest/POJO/app/src/test/java/com/commonsware/android/unittest/SOTests.java) When the test is setUp(), we initialize the CountDownLatch, to require one countDown() call before the latch is considered to be released. In our fetchQuestions() test method, we go through the same sort of code that QuestionsFragment does, creating our RestAdapter and StackOverflowInterface. When we call questions(), we supply an anonymous inner class instance of the Callback. In both success() and failure(), we countDown() our CountDownLatch. If the call succeeded, we also hold onto the SOQuestions model object. Immediately after calling fetchQuestions(), we await() on the CountDownLatch. The Callback will be called on a background thread, so the await() call means that we are blocking until such time as we are called with success() or failure(). Also, as a fail-safe measure, the @Test annotation for this test method is configured as @Test(timeout=30000), meaning that if we do not get a response in 30 seconds, we fail the test. Once we get control after the success() or failure() call, we confirm and see if we got our 30 questions and that each Item seems to be filled out. Running Unit Tests Once you have one or more unit tests, you can start thinking about running them and seeing if they work. Running unit tests does not require a device or emulator, as these tests are running on your development machine’s OS directly (in a standard Java VM), not on Android. 1120 UNIT TESTING From Android Studio From the project tree, right-clicking over a class or a package will give you a context menu option to run the tests in that class or package: Figure 369: Run Tests Context Menu Item for Test Package You can even right-click over the name of a method in your test class and have an option for running just that method: 1121 UNIT TESTING Figure 370: Run Test Context Menu Item for Test Method While convenient, this will clutter up your run configurations drop-down: Figure 371: Run Configurations, After Running Unit Tests The entries with the faded-out icons represent run configurations that were added dynamically based on your right-click test runs. The most recent of those becomes the current run configuration (shown here as “SOTests”), and you have an option to “save” that and make it a regular run configuration. If you try running the various unit tests for the sample app, SillyTest and ItemTests work, but SOTests does not. Apparently, Retrofit depends too much on Android, since the same test code succeeds when run as an instrumentation test. We will discuss how to deal with that problem later in this chapter. 1122 UNIT TESTING From the Command Line The test task in Gradle runs all of your unit tests for the module in which you run that task. The command line output will show you a summary of the results, in this case demonstrating the failure of SOTests: $ gradle test :app:preBuild UP-TO-DATE :app:preDebugBuild UP-TO-DATE :app:checkDebugManifest :app:prepareDebugDependencies :app:compileDebugAidl :app:compileDebugRenderscript :app:generateDebugBuildConfig :app:generateDebugAssets UP-TO-DATE :app:mergeDebugAssets :app:generateDebugResValues :app:generateDebugResources :app:mergeDebugResources :app:processDebugManifest :app:processDebugResources :app:generateDebugSources :app:compileDebugJavaWithJavac :app:preDebugUnitTestBuild UP-TO-DATE :app:prepareDebugUnitTestDependencies :app:compileDebugUnitTestJavaWithJavac :app:processDebugJavaRes UP-TO-DATE :app:processDebugUnitTestJavaRes UP-TO-DATE :app:compileDebugUnitTestSources :app:mockableAndroidJar :app:assembleDebugUnitTest :app:testDebugUnitTest com.commonsware.android.unittest.SOTests > fetchQuestions FAILED junit.framework.AssertionFailedError at SOTests.java:60 3 tests completed, 1 failed :app:testDebugUnitTest FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:testDebugUnitTest'. > There were failing tests. See the report at: file:///home/mmurphy/stuff/CommonsWare/ books/Omnibus/samples/UnitTest/POJO/app/build/reports/tests/debug/index.html * Try: 1123 UNIT TESTING Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. BUILD FAILED Total time: 14.188 secs We see that three tests completed, but one (SOTests) failed. In build/output/reports/tests/ will be HTML reports showing the results of the tests: Figure 372: Unit Test Report, Summary 1124 UNIT TESTING Figure 373: Unit Test Report, Showing a Failed Test There are XML files in build/output/test-results/ that contain the same basic information. These are mostly designed for use by tools, such as perhaps a CI server. Mocking Android Unit tests that go beyond stuff in common between the JVM and Android are going to have problems, such as the Retrofit example described above. For pure POJOs, this will not be a major limitation. But you might have other code that has little real connection to Android that you would like to test using unit testing, for the faster speed. However, unit testing is fairly unforgiving: “little real connection” is not “no connection”, and so your tests will fail. Hence, to fix unit testing, we need to mock Android. Why Are We Being Mean to Android? In this case, “mock” is not a synonym for “taunt”. Instead, “mock” refers to creating mock objects. Wikipedia describes this as: 1125 UNIT TESTING In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways. A programmer typically creates a mock object to test the behavior of some other object, in much the same way that a car designer uses a crash test dummy to simulate the dynamic behavior of a human in vehicle impacts. (from a February 2016 edition of the page) For example, in many places in Android, we need a Context. Sometimes, we do not really use the Context at all ourselves — it is input to some lower layer of code, and therefore we accept it as input to our layer and pass it along. In those cases, perhaps a mock Context will suffice to allow our tests to run. Or, perhaps endowing the mock Context with some limited amount of test-defined functionality will suffice to allow our tests to run. There are many mock frameworks for programming environments, including a few for Java, and some of those Java ones are Android-friendly. This section will look at one of those, Mockito. This section will also look at Robolectric, a framework specifically for mocking the Android SDK. Mockito Mockito is a general-purpose mocking library for Java that is officially supported by the Android tools team for use with Android unit testing. While there are other mocking libraries for Java (e.g., jMock, EasyMock), you may wish to start with Mockito given its official support status. Why Mockito? The idea behind any Java mocking library is to be able to create objects that, from a compilation standpoint, behave as do the real objects, but have test-controlled responses to methods (a.k.a., “stubs”). The quintessential Java example is mocking a List: List fakeList=mock(List.class); when(fakeList.get(0)).thenReturn(1337); Here, we use an imported static mock() method to create a mock implementation of the List interface. when() captures a particular invocation that we wish to stub 1126 UNIT TESTING out (in this case, getting the 0th item in the list), and thenReturn() indicates what the return value should be for that invocation (in this case, 1337). Later on, we can test our behavior: Assert.assertEquals(1337, fakeList.get(0)); // succeeds Assert.assertEquals(1337, fakeList.get(1)); // fails, as get(1) returns null Since we taught the mock how to respond to get(0), it returns 1337. Anything else we try doing with the mock will result in some default behavior; in this case, calling get() for any other index will return null, since we have not defined values for any other indexes. For limited tests like this, we are not really testing much in the way of actual app functionality. If anything, we are testing that Mockito is capable of mocking things. However, suppose instead that we did this: OurClass sumthin=new new OurClass(); Assert.assertEquals(1787569, sumthin.squareTheFirst(fakeList)); Here, we have a squareTheFirst() method implemented on some class of ours OurClass. As it turns out, the implementation of squareTheFirst() is to grab the 0th element out of the supplied List and return the square of that integer value. Now we are testing actual application logic, confirming that our square is being computed properly. Of course, in this case, it would be just as easy to create an ArrayList, rather than mess with a mock. However, there are plenty of cases where it would be too much work to create an instance of the class, including cases where it is nearly impossible. For example, we cannot create our own instances of system services, like AlarmManager or NotificationManager. If we want to test code that works with those, we are far better served using a mocking library like Mockito. Setting Up Mockito The UnitTest/Mockito sample application is based on the POJO one from earlier in the chapter. However, this version adds Mockito, specifically to help us play around with a mock version of Retrofit. The Android tools team seems to be endorsing Mockito 1.x, as at the present time (February 2016), Mockito 2.0 is still in beta. Adding Mockito, therefore, is a matter of 1127 UNIT TESTING adding a testImplementation statement to pull in an appropriate version of mockito-core: dependencies { implementation 'com.squareup.retrofit:retrofit:1.6.1' implementation 'de.greenrobot:eventbus:2.2.1' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:1.10.19' androidTestImplementation 'com.android.support.test:rules:0.4.1' } (from UnitTest/Mockito/app/build.gradle) Using Mockito in Unit Tests Let’s now use Mockito to create an SOTests that works, albeit using a fake Retrofit. To use Mockito in a JUnit4 test class, you need to add the @RunWith(MockitoJUnitRunner.class) annotation to the class, to have the class run using a dedicated JUnit4 test runner that is Mockito-enabled. So, SOTests needs that annotation: @RunWith(MockitoJUnitRunner.class) public class SOTests { (from UnitTest/Mockito/app/src/test/java/com/commonsware/android/unittest/SOTests.java) We want a mock StackOverflowInterface object that we can use to call our questions() method and retrieve mock questions. There are two main ways in Mockito to create mock objects: • the mock() method cited earlier • the @Mock annotation SOTests applies the latter, so StackOverflowInterface: one of the fields in the test class is a @Mock of @RunWith(MockitoJUnitRunner.class) public class SOTests { private CountDownLatch responseLatch; private SOQuestions questions; @Mock StackOverflowInterface mockSO; (from UnitTest/Mockito/app/src/test/java/com/commonsware/android/unittest/SOTests.java) 1128 UNIT TESTING We then need to teach our mock StackOverflowInterface how to return questions as needed. If we were using Retrofit’s synchronous API, the questions() method on StackOverflowInterface would return the SOQuestions object representing the results of our REST API call. In that case, mocking StackOverflowInterface could be (comparatively) simple, something like: SOQuestions fakeQuestions=new new SOQuestions(); fakeQuestions.items=new new ArrayList(); Item fakeItem=new new Item(); fakeItem.link="https://commonsware.com"; fakeItem.title="How Do I Fake It to Make It?"; fakeQuestions.items.add(fakeItem); when(mockSO.questions()).thenReturn(fakeQuestions); Here, we build up an SOQuestions instance containing a single Item, and we teach the mockSO object to return that in response to a call to questions(). However, we are using Retrofit’s asynchronous API, where we supply a Callback as a parameter. The questions() method is declared as void, so it does not return a response, and we will eventually be called with success() on our Callback. We can mock that with Mockito, but it is more complicated: doAnswer(new new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { SOQuestions fakeQuestions=new new SOQuestions(); fakeQuestions.items=new new ArrayList(); Item fakeItem=new new Item(); fakeItem.link="https://commonsware.com"; fakeItem.title="How Do I Fake It to Make It?"; fakeQuestions.items.add(fakeItem); Callback realCB= (Callback)invocation.getArguments()[1]; 1129 UNIT TESTING realCB.success(fakeQuestions, null null); return return(null null); } }).when(mockSO).questions(eq("android"), any(Callback.class)); (from UnitTest/Mockito/app/src/test/java/com/commonsware/android/unittest/SOTests.java) Let’s trim this back to the essence of what we are doing: doAnswer(...).when(mockSO).questions(...) The doAnswer() flow is a way of handling void methods, as thenReturn() does not work, since a void method does not return anything. doAnswer() is where we do the “work” that the mock needs to do, in this case to call our Callback, as we will see shortly. Chaining questions() onto the result of when() is another way of indicating a call that we are stubbing. However, in this case, our parameters are not simple primitives, like the 0 in get(0) from the List example depicted earlier in this section. We can provide information to questions() to indicate which questions() calls will get the answer provided by doAnswer(). doAnswer(...).when(mockSO).questions(eq("android"), any(Callback.class)) The real questions() method takes a String representing the Stack Overflow tag of interest, plus the Callback. The particular invocation of questions() that we are stubbing will be used when questions() is called on our mock StackOverflowInterface, where the first parameter equals (eq()) "android", and where the second parameter is any() instance of Callback.class. In principle, we could provide other stubs for other tags (e.g., questions(eq("ios"), any(Callback.class)))), but that is beyond the scope of what we are doing here. The value passed into doAnswer() is an anonymous inner class implementation of Answer. That object’s answer() method will be called when our mock is called with a matching questions() call. It is our job, in answer(), to do whatever the mock needs to do to satisfy our tests. Most of what is here builds up the same fake SOQuestions object as illustrated earlier. To actually pass that to the Callback, though, we need to: 1130 UNIT TESTING • Get the Callback object in question, by calling getArguments() on the supplied InvocationOnMock object (which collects all the parameters passed into questions()) and gets the second entry from that array of objects • Casts that to the correct type • Calls success(), passing in the fake SOQuestions, plus a null value for the Retrofit Response object, as we are not using that At that point, we can run our test, adjusting it to expect one Item instead of 30 as we were originally expecting: mockSO.questions("android", new Callback() { @Override public void success(SOQuestions soQuestions, Response response) { questions=soQuestions; responseLatch.countDown(); } @Override public void failure(RetrofitError error) { responseLatch.countDown(); } }); responseLatch.await(); Assert.assertNotNull(questions); Assert.assertEquals(1, questions.items.size()); for (Item item : questions.items) { Assert.assertNotNull(item.title); Assert.assertNotNull(item.link); } (from UnitTest/Mockito/app/src/test/java/com/commonsware/android/unittest/SOTests.java) In this case, everything should be happening on the same thread, and so it is likely that the CountDownLatch is superfluous. However, it does not cause us any particular harm here, and it keeps the code more closely aligned with the implementation in the instrumentation tests. The whole test class, therefore, looks like this: package com.commonsware.android.unittest; 1131 UNIT TESTING import import import import import import import import import import import import import import import import junit.framework.Assert junit.framework.Assert; org.junit.Before org.junit.Before; org.junit.Test org.junit.Test; org.junit.runner.RunWith org.junit.runner.RunWith; org.mockito.Mock org.mockito.Mock; org.mockito.invocation.InvocationOnMock org.mockito.invocation.InvocationOnMock; org.mockito.runners.MockitoJUnitRunner org.mockito.runners.MockitoJUnitRunner; org.mockito.stubbing.Answer org.mockito.stubbing.Answer; java.util.ArrayList java.util.ArrayList; java.util.concurrent.CountDownLatch java.util.concurrent.CountDownLatch; retrofit.Callback retrofit.Callback; retrofit.RetrofitError retrofit.RetrofitError; retrofit.client.Response retrofit.client.Response; static org.mockito.Matchers.any; static org.mockito.Matchers.eq; static org.mockito.Mockito.doAnswer; @RunWith(MockitoJUnitRunner.class) public class SOTests { private CountDownLatch responseLatch; private SOQuestions questions; @Mock StackOverflowInterface mockSO; @Before public void setUp() { responseLatch=new new CountDownLatch(1); } @Test(timeout=30000) public void fetchQuestions() throws InterruptedException { doAnswer(new new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { SOQuestions fakeQuestions=new new SOQuestions(); fakeQuestions.items=new new ArrayList(); Item fakeItem=new new Item(); fakeItem.link="https://commonsware.com"; fakeItem.title="How Do I Fake It to Make It?"; fakeQuestions.items.add(fakeItem); Callback realCB= (Callback)invocation.getArguments()[1]; realCB.success(fakeQuestions, null null); 1132 UNIT TESTING return return(null null); } }).when(mockSO).questions(eq("android"), any(Callback.class)); mockSO.questions("android", new Callback() { @Override public void success(SOQuestions soQuestions, Response response) { questions=soQuestions; responseLatch.countDown(); } @Override public void failure(RetrofitError error) { responseLatch.countDown(); } }); responseLatch.await(); Assert.assertNotNull(questions); Assert.assertEquals(1, questions.items.size()); for (Item item : questions.items) { Assert.assertNotNull(item.title); Assert.assertNotNull(item.link); } } } (from UnitTest/Mockito/app/src/test/java/com/commonsware/android/unittest/SOTests.java) If you run the fetchQuestions() test, it works. Of course, it is not really testing anything other than Mockito itself. In this particular app, the only thing we are using Retrofit for is to obtain a list of model objects to put in an ArrayAdapter to display in a ListView. Mockito cannot readily help us test whether our ArrayAdapter is inflating layouts properly, or whether ListView is using the ArrayAdapter properly. At best, we would wind up creating massive mocks that, once again, mostly just have us testing whether our mocks work, not our actual business logic. This is not to say that Mockito is useless, but rather that its utility is for lightly extending the scope of what we can test of our POJOs in unit testing. 1133 UNIT TESTING Mockito is a fairly large and complex library. There are multiple books available covering Mockito, should you need more than the project documentation and similar online sources. Just remember that Mockito is for general Java development and is not Android-specific. Robolectric Mockito mocks anything you want, so long as you are the one doing the mocking. Robolectric mocks a part of the Android SDK for you. In particular, it mocks the setup and teardown of activities and services, so you can confirm that they are initialized properly through unit tests, instead of instrumentation tests. Robolectric also supports a limited amount of user input testing — mostly limited to click events — so you can determine whether or not your activity is reacting as expected. On the one hand, Robolectric lets you set up some Android-specific unit tests “out of the box”. On the other hand, the depth and breadth of its mocking is fairly limited, which will steer more of your tests back to instrumentation testing, where you have a full Android SDK at your disposal. The UnitTest/Robolectric sample application is based on the one shown in the chapter on JUnit4, where we have 25 Latin words that we are showing in a list, and we want to test that the activity is coming up as expected. Setting up Robolectric You will need to add a testImplementation directive to your build.gradle file to pull in Robolectric: dependencies { testImplementation 'junit:junit:4.12' testImplementation 'org.robolectric:robolectric:3.0' androidTestImplementation 'com.android.support.test:rules:0.4.1' } (from UnitTest/Robolectric/app/build.gradle) You will also need to make a change to how Android Studio runs your unit tests, so it has the proper working directory for Robolectric’s use: 1. In the main Android Studio toolbar, click the run configurations drop-down and choose “Edit Configurations” 1134 UNIT TESTING 2. In the “Run/Debug Configurations” dialog, click on the wrench toolbar button, which will allow you to edit default settings for run configurations: Figure 374: Run/Debug Configurations, JUnit Defaults, Unmodified 1. The “Working directory” field will be filled in with the fully-qualified path to your project directory. Change that to $MODULE_DIR$: 1135 UNIT TESTING Figure 375: Run/Debug Configurations, JUnit Defaults, Modified 1. Click Apply. 2. If you have existing run configurations for unit testing that you now want to start using with Robolectric, click on those run configurations in the tree on the left and change the working directory for those to $MODULE_DIR$ as well. 3. Click OK to close up the dialog. Changing the defaults will affect future run configurations. But, if you already have run configurations that you created earlier, changing the defaults will not affect those, which is why you need to change them separately. This change sets the working directory to be the root directory of your module, rather than the project. Choosing an API Level A key decision that you will need to make, before writing any tests, is what API level you want Robolectric to mock. Robolectric does not have mocks for all API levels, as creating their roster of mocks takes work. Unfortunately, the roster of supported API levels does not appear to be documented. 1136 UNIT TESTING The Roboletric SdkConfig class class is the closest that we have to documentation, as it has a static block that sets up the supported SDKs. The following is from Robolectric 3.0: static { SUPPORTED_APIS = new HashMap<>(); addSdk(Build.VERSION_CODES.JELLY_BEAN, "4.1.2_r1", "0"); addSdk(Build.VERSION_CODES.JELLY_BEAN_MR1, "4.2.2_r1.2", "0"); addSdk(Build.VERSION_CODES.JELLY_BEAN_MR2, "4.3_r2", "0"); addSdk(Build.VERSION_CODES.KITKAT, "4.4_r1", "1"); addSdk(Build.VERSION_CODES.LOLLIPOP, "5.0.0_r2", "1"); ROBOLECTRIC_VERSION = getRobolectricVersion(); } This translates to support for API Level 16-19 and 21. You will need to choose a suitable API level for your use. By default, Robolectric will use your targetSdkVersion, which may or may not be one of the supported API levels. You will need to know what Robolectric API level to use when you start setting up your tests. Writing Robolectric Tests At this point, you can start writing tests that use Robolectric. As with the Mockito tests and other unit tests, these will go in your test/ source set. The sample project has a DemoActivityTest that, in theory, would mimic the DemoActivityTest from the instrumentation tests in the androidTest/ source set: package com.commonsware.android.abf.test; import import import import import import import import import import import android.view.KeyEvent android.view.KeyEvent; android.widget.ListView android.widget.ListView; com.commonsware.android.abf.ActionBarFragmentActivity com.commonsware.android.abf.ActionBarFragmentActivity; com.commonsware.android.abf.BuildConfig com.commonsware.android.abf.BuildConfig; junit.framework.Assert junit.framework.Assert; org.junit.Before org.junit.Before; org.junit.Test org.junit.Test; org.junit.runner.RunWith org.junit.runner.RunWith; org.robolectric.Robolectric org.robolectric.Robolectric; org.robolectric.RobolectricGradleTestRunner org.robolectric.RobolectricGradleTestRunner; org.robolectric.annotation.Config org.robolectric.annotation.Config; @RunWith(RobolectricGradleTestRunner.class) 1137 UNIT TESTING @Config(constants=BuildConfig.class, sdk=16) public class DemoActivityTest { private ListView list=null null; @Before public void setUp() throws Exception { ActionBarFragmentActivity activity= Robolectric.setupActivity(ActionBarFragmentActivity.class); list=(ListView)activity.findViewById(android.R.id.list); } @Test public void listCount() { Assert.assertEquals(25, list.getAdapter().getCount()); } } (from UnitTest/Robolectric/app/src/test/java/com/commonsware/android/abf/test/DemoActivityTest.java) Your test case classes need two annotations. One is @RunWith(RobolectricGradleTestRunner.class), to tell the unit test system to use Robolectric’s test runner rather than the stock JUnit one. If you also plan on using Mockito, since you cannot use two test runners, use the Robolectric one and add MockitoAnnotations.initMocks(this); to a @Before method of your test case, to initialize Mockito. The other annotation that you need is @Config, which, as the name suggests, configures the Robolectric test runner. The @Config annotation will need at least two properties: • constants=BuildConfig.class, to point Robolectric to your BuildConfig class, so Robolectric can learn what build variant is being run, so it can grab data out of your generated manifest and such • sdk=... where ... is replaced by a Robolectric-supported API level, where the sample app uses 16 Technically, the sdk property is not required, if your targetSdkVersion is a supported value. However, you may wish to still specify it on the tests, so your tests are isolated from changes that you might make to the targetSdkVersion. To get a fully-initialized mock activity, call Robolectric.setupActivity(), providing the Java class object for the activity in question (e.g., ActionBarFragmentActivity.class). This works similarly to calling getActivity() 1138 UNIT TESTING on an ActivityTestRule in a JUnit4 instrumentation test: you get an activity, with the appropriate data type, ready for testing. In this case, we retrieve the ListView and, in a @Test method, ensure that the adapter in the ListView has 25 entries. The instrumentation test edition of DemoActivityTest also tests key and touch events. While Robolectric supports performClick() calls on views to simulate click events, simulating key and touch events does not appear to be well-supported, which is why the Robolectric test case skips them. Running Robolectric Tests You run the Robolectric tests the same way as any other unit tests, such as by rightclicking over the test case class and choosing the run option. The first time that you run the tests for your module, Robolectric will download a bunch of stuff: /usr/lib/jvm/java-8-oracle/bin/java -ea -Didea.launcher.port=7535 -Didea.launcher.bin.path=/home/mmurphy/android-studio/bin -Dfile.encoding=UTF-8 -classpath /home/mmurphy/android-studio/lib/idea_rt.jar:/home/mmurphy/android-studio/ plugins/junit/lib/junit-rt.jar:/opt/android-sdk-linux/platforms/android-19/data/ res:/home/mmurphy/stuff/CommonsWare/books/Omnibus/samples/UnitTest/Robolectric/app/ build/intermediates/classes/test/debug:/home/mmurphy/stuff/CommonsWare/books/Omnibus/ samples/UnitTest/Robolectric/app/build/intermediates/classes/debug:/home/ mmurphy/.gradle/caches/modules-2/files-2.1/org.apache.maven/maven-ant-tasks/2.1.3/ b09be554228d66d208e5fef5266844aacf443abc/maven-ant-tasks-2.1.3.jar:/home/ mmurphy/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant/1.8.0/ 7b456ca6b93900f96e58cc8371f03d90a9c1c8d1/ant-1.8.0.jar:/home/mmurphy/.gradle/caches/ modules-2/files-2.1/com.ibm.icu/icu4j/53.1/786d9055d4ca8c1aab4a7d4ac8283f973fd7e41f/ icu4j-53.1.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ com.google.android.apps.common.testing.accessibility.framework/ accessibility-test-framework/1.0/28162aae36f8ba5903adadfb570313e1f1be852e/ accessibility-test-framework-1.0.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ org.robolectric/robolectric-resources/3.0/1ab609054aab67cd13a434567467f4b4774f2465/ robolectric-resources-3.0.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ org.ow2.asm/asm-commons/5.0.1/7b7147a390a93a14d2edfdcf3f7b0e87a0939c3e/ asm-commons-5.0.1.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/org.apache.ant/ ant-launcher/1.8.0/8b53ba16fa62fb1034da8f1de200ddc407c8381/ ant-launcher-1.8.0.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ org.robolectric/robolectric-annotations/3.0/2a6cfc072d7680694c1ff893c5dc8fec33163110/ robolectric-annotations-3.0.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ com.almworks.sqlite4java/sqlite4java/0.282/745a7e2f35fdbe6336922e0d492c979dbbfa74fb/ sqlite4java-0.282.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/org.ow2.asm/ asm-tree/5.0.1/1b1e6e9d869acd704056d0a4223071a511c619e6/asm-tree-5.0.1.jar:/home/ mmurphy/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm/5.0.1/ 1139 UNIT TESTING 2fd56467a018aafe6ec6a73ccba520be4a7e1565/asm-5.0.1.jar:/home/mmurphy/.gradle/caches/ modules-2/files-2.1/org.robolectric/shadows-core/3.0/ 9dfa881bfd1796afa28204ef1a5ed7e3de992612/shadows-core-3.0.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/org.ow2.asm/asm-analysis/5.0.1/ e286fbee48efacb4e7c175f7948d9d8b2ab52352/asm-analysis-5.0.1.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/org.robolectric/robolectric-utils/3.0/ 4bcecd8115fe7296088bb1636e6cbd7ae8927392/robolectric-utils-3.0.jar:/home/ mmurphy/.gradle/caches/modules-2/files-2.1/com.ximpleware/vtd-xml/2.11/ ee5bcf62c1acf76434ee9f1c67a840bafef72a6d/vtd-xml-2.11.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/ 42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/org.ow2.asm/asm-util/5.0.1/ 7c8caddfbd0b2d7b844f8fcc75175b9cb9cf4724/asm-util-5.0.1.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/org.bouncycastle/bcprov-jdk16/1.46/ ce091790943599535cbb4de8ede84535b0c1260c/bcprov-jdk16-1.46.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/junit/junit/4.12/2973d150c0dc1fefe998f834810d68f278ea58ec/ junit-4.12.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/org.mockito/ mockito-core/1.10.19/e8546f5bef4e061d8dd73895b4e8f40e3fe6effe/ mockito-core-1.10.19.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ org.robolectric/robolectric/3.0/f888cea3bc1a24110e315eb9827ab593610ea62f/ robolectric-3.0.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/org.objenesis/ objenesis/2.1/87c0ea803b69252868d09308b4618f766f135a96/objenesis-2.1.jar:/home/ mmurphy/stuff/CommonsWare/books/Omnibus/samples/UnitTest/Robolectric/app/build/ intermediates/sourceFolderJavaResources/test/debug:/home/mmurphy/stuff/CommonsWare/ books/Omnibus/samples/UnitTest/Robolectric/app/build/intermediates/ sourceFolderJavaResources/debug:/home/mmurphy/stuff/CommonsWare/books/Omnibus/samples/ UnitTest/Robolectric/build/generated/mockable-android-19.jar com.intellij.rt.execution.application.AppMain com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 com.commonsware.android.abf.test.DemoActivityTest Downloading: org/robolectric/shadows-core/3.0/shadows-core-3.0.pom from repository sonatype at https://oss.sonatype.org/content/groups/public/ Transferring 14K from sonatype Downloading: org/robolectric/robolectric-shadows/3.0/robolectric-shadows-3.0.pom from repository sonatype at https://oss.sonatype.org/content/groups/public/ Transferring 1K from sonatype Downloading: org/robolectric/robolectric-parent/3.0/robolectric-parent-3.0.pom from repository sonatype at https://oss.sonatype.org/content/groups/public/ Transferring 12K from sonatype Downloading: org/robolectric/robolectric-annotations/3.0/ robolectric-annotations-3.0.pom from repository sonatype at https://oss.sonatype.org/ content/groups/public/ Transferring 1K from sonatype Downloading: org/robolectric/robolectric-utils/3.0/robolectric-utils-3.0.pom from repository sonatype at https://oss.sonatype.org/content/groups/public/ Transferring 2K from sonatype Downloading: org/robolectric/robolectric-resources/3.0/robolectric-resources-3.0.pom from repository sonatype at https://oss.sonatype.org/content/groups/public/ 1140 UNIT TESTING Transferring 2K from sonatype Downloading: org/robolectric/shadows-core/3.0/shadows-core-3.0-16.jar from repository sonatype at https://oss.sonatype.org/content/groups/public/ Transferring 2587K from sonatype Downloading: org/robolectric/robolectric-annotations/3.0/ robolectric-annotations-3.0.jar from repository sonatype at https://oss.sonatype.org/ content/groups/public/ Transferring 10K from sonatype Downloading: org/robolectric/robolectric-utils/3.0/robolectric-utils-3.0.jar from repository sonatype at https://oss.sonatype.org/content/groups/public/ Transferring 40K from sonatype Downloading: org/robolectric/robolectric-resources/3.0/robolectric-resources-3.0.jar from repository sonatype at https://oss.sonatype.org/content/groups/public/ Transferring 146K from sonatype Process finished with exit code 0 This material is cached, so future runs will skip it. If you get a crash akin to this: /usr/lib/jvm/java-8-oracle/bin/java -ea -Didea.launcher.port=7533 -Didea.launcher.bin.path=/home/mmurphy/android-studio/bin -Dfile.encoding=UTF-8 -classpath /home/mmurphy/android-studio/lib/idea_rt.jar:/home/mmurphy/android-studio/ plugins/junit/lib/junit-rt.jar:/opt/android-sdk-linux/platforms/android-19/data/ res:/home/mmurphy/stuff/CommonsWare/books/Omnibus/samples/UnitTest/Robolectric/app/ build/intermediates/classes/test/debug:/home/mmurphy/stuff/CommonsWare/books/Omnibus/ samples/UnitTest/Robolectric/app/build/intermediates/classes/debug:/home/ mmurphy/.gradle/caches/modules-2/files-2.1/org.apache.maven/maven-ant-tasks/2.1.3/ b09be554228d66d208e5fef5266844aacf443abc/maven-ant-tasks-2.1.3.jar:/home/ mmurphy/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant/1.8.0/ 7b456ca6b93900f96e58cc8371f03d90a9c1c8d1/ant-1.8.0.jar:/home/mmurphy/.gradle/caches/ modules-2/files-2.1/com.ibm.icu/icu4j/53.1/786d9055d4ca8c1aab4a7d4ac8283f973fd7e41f/ icu4j-53.1.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ com.google.android.apps.common.testing.accessibility.framework/ accessibility-test-framework/1.0/28162aae36f8ba5903adadfb570313e1f1be852e/ accessibility-test-framework-1.0.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ org.robolectric/robolectric-resources/3.0/1ab609054aab67cd13a434567467f4b4774f2465/ robolectric-resources-3.0.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ org.ow2.asm/asm-commons/5.0.1/7b7147a390a93a14d2edfdcf3f7b0e87a0939c3e/ asm-commons-5.0.1.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/org.apache.ant/ ant-launcher/1.8.0/8b53ba16fa62fb1034da8f1de200ddc407c8381/ ant-launcher-1.8.0.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ org.robolectric/robolectric-annotations/3.0/2a6cfc072d7680694c1ff893c5dc8fec33163110/ robolectric-annotations-3.0.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ com.almworks.sqlite4java/sqlite4java/0.282/745a7e2f35fdbe6336922e0d492c979dbbfa74fb/ sqlite4java-0.282.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/org.ow2.asm/ 1141 UNIT TESTING asm-tree/5.0.1/1b1e6e9d869acd704056d0a4223071a511c619e6/asm-tree-5.0.1.jar:/home/ mmurphy/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm/5.0.1/ 2fd56467a018aafe6ec6a73ccba520be4a7e1565/asm-5.0.1.jar:/home/mmurphy/.gradle/caches/ modules-2/files-2.1/org.robolectric/shadows-core/3.0/ 9dfa881bfd1796afa28204ef1a5ed7e3de992612/shadows-core-3.0.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/org.ow2.asm/asm-analysis/5.0.1/ e286fbee48efacb4e7c175f7948d9d8b2ab52352/asm-analysis-5.0.1.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/org.robolectric/robolectric-utils/3.0/ 4bcecd8115fe7296088bb1636e6cbd7ae8927392/robolectric-utils-3.0.jar:/home/ mmurphy/.gradle/caches/modules-2/files-2.1/com.ximpleware/vtd-xml/2.11/ ee5bcf62c1acf76434ee9f1c67a840bafef72a6d/vtd-xml-2.11.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/ 42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/org.ow2.asm/asm-util/5.0.1/ 7c8caddfbd0b2d7b844f8fcc75175b9cb9cf4724/asm-util-5.0.1.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/org.bouncycastle/bcprov-jdk16/1.46/ ce091790943599535cbb4de8ede84535b0c1260c/bcprov-jdk16-1.46.jar:/home/mmurphy/.gradle/ caches/modules-2/files-2.1/junit/junit/4.12/2973d150c0dc1fefe998f834810d68f278ea58ec/ junit-4.12.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/org.mockito/ mockito-core/1.10.19/e8546f5bef4e061d8dd73895b4e8f40e3fe6effe/ mockito-core-1.10.19.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/ org.robolectric/robolectric/3.0/f888cea3bc1a24110e315eb9827ab593610ea62f/ robolectric-3.0.jar:/home/mmurphy/.gradle/caches/modules-2/files-2.1/org.objenesis/ objenesis/2.1/87c0ea803b69252868d09308b4618f766f135a96/objenesis-2.1.jar:/home/ mmurphy/stuff/CommonsWare/books/Omnibus/samples/UnitTest/Robolectric/app/build/ intermediates/sourceFolderJavaResources/test/debug:/home/mmurphy/stuff/CommonsWare/ books/Omnibus/samples/UnitTest/Robolectric/app/build/intermediates/ sourceFolderJavaResources/debug:/home/mmurphy/stuff/CommonsWare/books/Omnibus/samples/ UnitTest/Robolectric/build/generated/mockable-android-19.jar com.intellij.rt.execution.application.AppMain com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 com.commonsware.android.abf.test.DemoActivityTest java.io.FileNotFoundException: build/intermediates/bundles/debug/AndroidManifest.xml (No such file or directory) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.(FileInputStream.java:138) at org.robolectric.res.FileFsFile.getInputStream(FileFsFile.java:78) at org.robolectric.manifest.AndroidManifest.parseAndroidManifest(AndroidManifest.java:132) at org.robolectric.manifest.AndroidManifest.getTargetSdkVersion(AndroidManifest.java:446) at org.robolectric.RobolectricTestRunner.pickSdkVersion(RobolectricTestRunner.java:442) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:187) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 1142 UNIT TESTING at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) java.lang.UnsupportedOperationException: Robolectric does not support API level 1. at org.robolectric.internal.SdkConfig.(SdkConfig.java:42) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:187) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) Process finished with exit code 255 …then you failed to set your working directory as is described earlier in this chapter. If you get a crash akin to this: 1143 UNIT TESTING java.lang.UnsupportedOperationException: Robolectric does not support API level 14. at org.robolectric.internal.SdkConfig.(SdkConfig.java:42) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:187) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) …then you failed to set the sdk property to a valid API level in your @Config annotation, as is described earlier in this chapter. You may also crash due to gaps in what the mocks support. For example, some online sources suggest that to test key input that you should call onKeyDown() or onKeyUp() on the widget in question, sending along your desired KeyEvent information: @Test public void keyEvents() { for (int i=0;i<4;i++) { list.onKeyDown(KeyEvent.KEYCODE_DPAD_DOWN, null null); } Assert.assertEquals(4, list.getSelectedItemPosition()); } While that may have worked for earlier versions of Robolectric, it does not appear to work with the current one: java.lang.NullPointerException at android.widget.ListView.commonKey(ListView.java:2064) at android.widget.ListView.onKeyDown(ListView.java:2041) at com.commonsware.android.abf.test.DemoActivityTest.keyEvents(DemoActivityTest.java:50) 1144 UNIT TESTING at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) As the saying goes, “your mileage may vary”. OK, So, Why Bother? If input is limited and mocks are incomplete, why are we using Robolectric? Robolectric can be useful in cases where you wish to run a quick subset of tests frequently to determine whether there are egregious problems. So-called “smoke tests” might be run on every commit to a version control system by a build server, for example. In this case, while Roboletric may not help you with test breadth or depth, it can help you with test frequency, since unit tests run so much faster. Running your full test suite on every commit might be too much; running the subset that you can implement as unit tests may be far more practical. 1145 MonkeyRunner and the Test Monkey Many GUI environments have some means or another of “fuzz” or “bash” testing, where some test driver executes a bunch of random input, in hopes of catching errors (e.g., missing validation logic). Android offers the Test Monkey for this. Many GUI environments have some means or another of scripting GUI events from outside the application itself, to simulate button clicks or touch events. Android offers MonkeyRunner for this. As the names suggest, there is a bit of commonality in their implementation. And, as you might expect, there is a bit of commonality in their coverage in this book — we will examine both MonkeyRunner and the Test Monkey in this chapter. Prerequisites Understanding this chapter requires that you have read the core chapters of this book. MonkeyRunner MonkeyRunner is a means of creating test suites for Android applications based on scripted UI input. Rather than write a series of JUnit test cases or the like, you create Jython (JVM implementation of Python) scripts that run commands to install apps, execute GUI events, and take screenshots of results. 1147 MONKEYRUNNER AND THE TEST MONKEY Writing a MonkeyRunner Script The primary object you will work with in a MonkeyRunner script is a MonkeyDevice, which represents your connection to the device or emulator that you are testing. You obtain a MonkeyDevice by calling waitForConnection() on MonkeyRunner; this will return once it has established a connection. From there, MonkeyDevice lets you send events to the device or emulator: • installPackage() allows you to install an APK from your development machine, and removePackage() allows you to get rid of it • startActivity() and broadcastIntent() allow you to start up components of your app • press() to simulate key events, including QWERTY keys, standard device keys like BACK, D-pad/trackball events, and anything else represented by a standard Android KeyEvent • type() to simulate entering a whole string, as a simplification over calling press() once per letter • touch() and drag() let you simulate touch events • and so on The biggest limitation is in getting data out of the device, to determine if your test worked successfully. Your options are: • takeSnapshot(), which will capture a screenshot that you can save to disk, compare with other screenshots, etc. • shell() executes adb shell commands, returning any results • …and that’s about it Unlike JUnit-based testing, you have no visibility into the activity beyond what appears on the screen — you cannot inspect widgets, call methods, or the like. For example, here is a script that installs an app, runs an activity from it, and presses the down button on the D-pad three times: from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice device = MonkeyRunner.waitForConnection() device.installPackage('bin/JUnitDemo.apk') device.startActivity(component='com.commonsware.android.abf/ com.commonsware.android.abf.ActionBarFragmentActivity') device.press('KEYCODE_DPAD_DOWN', MonkeyDevice.DOWN_AND_UP) device.press('KEYCODE_DPAD_DOWN', MonkeyDevice.DOWN_AND_UP) device.press('KEYCODE_DPAD_DOWN', MonkeyDevice.DOWN_AND_UP) 1148 MONKEYRUNNER AND THE TEST MONKEY # result = device.takeSnapshot() # result.writeToFile('tests/monkey_sample_shots/test1.png', 'png') (from Testing/monkey_sample.py) Executing MonkeyRunner To execute your MonkeyRunner script, have your device or emulator set up at a likely starting point (e.g., home screen), then execute the monkeyrunner command, passing it the path to your script (e.g., monkeyrunner monkey_sample.py). You will see the script executing on the screen of your device or emulator, and your console will contain whatever output you might emit from your test script itself. For example, you might take screenshots, compare them against a master copy (using methods on MonkeyImage to help with this), and emit warnings if they differ unexpectedly. Monkeying Around Independent from the JUnit system and MonkeyRunner is the Test Monkey (referred to here as “the Monkey” for short). The Monkey is a test program that simulates random user input. It is designed for “bash testing”, confirming that no matter what the user does, the application will not crash. The application may have odd results — random input entered into a Twitter client may, indeed, post that random input to Twitter. The Monkey does not test to make sure that results of random input make sense; it only tests to make sure random input does not blow up the program. You can run the Monkey by setting up your initial starting point (e.g., the main activity in your application) on your device or emulator, then running a command like this: adb shell monkey -p your.package.here -v --throttle 100 600 (substituting the application ID of a project on your device or emulator for your.package.here) Working from right to left, we are asking for 600 simulated events, throttled to add 100 millisecond delays. We want to see a list of the invoked events (-v) and we want to throw out any event that might cause the Monkey to leave our application, as determined by the application ID (-p your.package.here). 1149 MONKEYRUNNER AND THE TEST MONKEY Note that this truly is the application ID, not the package name. In simple apps — such as most of this book’s samples — the package name is the application ID. But if you have modified the application ID in your build.gradle file (e.g., replaced the application ID for a product flavor), you will need to use the actual application ID here, not the package name. In general, despite any legacy documentation to the contrary, “package name” only affects code-generated classes like R and BuildConfig. Any other use of the term “package name” really is referring to the application ID. The Monkey will simulate keypresses (both QWERTY and specialized hardware keys, like the volume controls), D-pad/trackball moves, and sliding the keyboard open or closed. Note that the latter may cause your emulator some confusion, as the emulator itself does not itself actually rotate, so you may end up with your screen appearing in landscape while the emulator is still, itself, portrait. Just rotate the emulator a couple of times (e.g., -) to clear up the problem. Also note that the throttle time is only used in between batches of related events. So, a batch of several touch events, or a pair of up/down events for a hardware key, will not be throttled. You can see this if you pass -v -v -v for “ultimate verbose mode” and look at the output, such as this snippet: :Sending :Sending Sleeping :Sending :Sending :Sending :Sending :Sending :Sending :Sending Sleeping :Sending :Sending Sleeping :Sending :Sending Sleeping Key (ACTION_DOWN): 134 // KEYCODE_F4 Key (ACTION_UP): 134 // KEYCODE_F4 for 100 milliseconds Touch (ACTION_DOWN): 0:(1302.0,842.0) Touch (ACTION_MOVE): 0:(1295.3395,838.0863) Touch (ACTION_MOVE): 0:(1290.1539,827.0493) Touch (ACTION_MOVE): 0:(1280.0454,826.9068) Touch (ACTION_MOVE): 0:(1272.0161,816.8062) Touch (ACTION_MOVE): 0:(1260.7244,810.8302) Touch (ACTION_UP): 0:(1250.5455,801.67444) for 100 milliseconds Key (ACTION_DOWN): 19 // KEYCODE_DPAD_UP Key (ACTION_UP): 19 // KEYCODE_DPAD_UP for 100 milliseconds Key (ACTION_DOWN): 68 // KEYCODE_GRAVE Key (ACTION_UP): 68 // KEYCODE_GRAVE for 100 milliseconds Here, we see actual messages where the throttling is applied (“Sleeping for 100 milliseconds”). Hence, the time it takes the Test Monkey to run a test will be at most the number of events times the throttle time, but due to event batching, it is usually substantially less than that. 25-30% of the maximum time seems typical. 1150 MONKEYRUNNER AND THE TEST MONKEY For playing with a Monkey, the above command works fine. However, if you want to regularly test your application this way, you may need some measure of repeatability. After all, the particular set of input events that trigger your crash may not come up all that often, and without that repeatable scenario, it will be difficult to repair the bug, let alone test that the repair worked. To deal with this, the Monkey offers the -s switch, where you provide a seed for the random number generator. By default, the Monkey creates its own seed, giving totally random results. If you supply the seed, while the sequence of events is random, it is random for that seed — repeatedly using the same seed will give you the same events. If you can arrange to detect a crash and know what seed was used to create that crash, you may well be able to reproduce the crash. 1151 Trail: Rx Java 8 Lambda Expressions In 2016, Android app development gained some ability to use Java 8 programming constructs. One of those changes was the release of Android 7.0, which introduced some Java 8-compatible classes, such as those in the java.util.stream package. These are new to API Level 24. Most likely, you will only start to use them once you raise your minSdkVersion to 24 or higher. However, some features can be used on older devices. Notable among these are lambda expressions, the Java 8 equivalent of blocks or closures that you find in other programming languages. Lambda expressions can make your code a bit less verbose, particularly in places where you are making heavy use of listener interfaces or other forms of callback objects. Getting all this to work requires some Gradle changes (to request Java 8 support in the build process), plus using the new lambda expression syntax. This chapter will show you all of this. Prerequisites Understanding this chapter requires that you have read the core chapters of the book. It does not require that you have prior experience with Java 8 lambda expressions. However, having read the chapter on RecyclerView is a good idea, as the sample app in this chapter was originally shown there. Also, you should now be using Android Studio 3.0, and its related build tools. 1155 JAVA 8 LAMBDA EXPRESSIONS The Basic Idea In Java programming prior to Java 8, we needed to create a lot of classes for minor roles, whether those classes were traditional Java classes, nested classes, or anonymous inner classes. For example, suppose that you have an ArrayList of Video objects: package com.commonsware.android.recyclerview.videolist; import import import import android.content.ContentUris android.content.ContentUris; android.database.Cursor android.database.Cursor; android.net.Uri android.net.Uri; android.provider.MediaStore android.provider.MediaStore; class Video implements Comparable

> > It is derived from a similar example found in the blog post outlining the security flaw. In an SOP-compliant browser, clicking the button will have no effect. In the AOSP Browser app, clicking the button shows the domain name of the document in the iframe. And, loading this HTML into a WebView has the same effect. Part of the WebView overhaul in Android 4.4 — replacing the original implementation with a new one backed by Chromium — had the effect of fixing this bug, whether intentionally or inadvertently. 1705 ADVANCED USES OF WEBVIEW There is no obvious mitigation approach for this bug, insofar as for the attack shown above, none of the callbacks on WebViewClient or WebChromeClient seem to allow us to intercept this URL before its JavaScript is executed. If you are loading HTML yourself from a third party, you might consider scanning that HTML for obvious signs of the attack (e.g., regular expression check for \u0000javascript), but that will be limited at best. Beyond that, try to limit the content in a WebView to be from only one origin, so that there is nothing for attackers to obtain via this bug. Also note that the security researcher who found this bug has also found another SOP violation, suggesting that mitigation strategies may be impractical. Android 8.0 WebView Changes WebView, as Android developers use it, is really a facade API, as of Android 5.0. Previously, the WebView implementation was part of the Android framework. Nowadays, the implementation is delegated to the Android System WebView, which allows Google to update the WebView implementation without relying upon manufacturers to distribute firmware updates. Hence, to some extent, WebView continuously changes, as the Android System WebView app gets updated a few times per year. However, it is only in a new version of Android that Google changes the API or the general approach taken by a WebView implementation. In Android 8.0, two significant changes arrived: multi-process mode and support for banning of cleartext traffic. Multi-Process Mode Historically, WebView code ran in your app’s regular process. Because we often load JavaScript into a WebView, having the WebView in our process would raise the risks of WebView bugs. If JavaScript could cause arbitrary code to execute in our own process, it would have whatever rights our own application code does, including everything for which we have runtime permissions. Android 7.0 added a developer option for moving the WebView execution to a separate process, and that is now standard on Android 8.0. As the documentation describes it, “Web content is handled in a separate, isolated process from the containing app’s process for enhanced security.” 1706 ADVANCED USES OF WEBVIEW In principle, this should not require code changes. However, this is a significant architectural change, and so it is worthwhile to fully test your WebView usage on Android 8.0+, to make sure nothing breaks compared with that same code running on Android 7.1 or older devices. Honors Cleartext Traffic Setting If your app has a targetSdkVersion over 25, and in your network security configuration you banned cleartext traffic, WebView will honor that setting on Android 8.0+. On older devices, WebView ignores the network security configuration, and it appears that it still ignores the rest of the configuration (e.g., certificate pinning). However, this allows you to block the accidental transmission of data over unencrypted channels. Most apps doing network I/O should ban cleartext traffic, at least for debug builds, to identify where they are accidentally using a plain http URL. Apps for which security is a priority might also ban cleartext traffic for release builds. The WebKit/BrowserSecure sample project demonstrates this. It has a network security configuration XML file that bands cleartext traffic: > (from WebKit/BrowserSecure/app/src/main/res/xml/net_security_config.xml) It applies that configuration in the manifest via the android:networkSecurityConfig attribute on the element: > > 1707 ADVANCED USES OF WEBVIEW (from WebKit/BrowserSecure/app/src/main/AndroidManifest.xml) The activity just loads up a plain HTTP-served Web page: package com.commonsware.android.browser1; import android.app.Activity android.app.Activity; import android.os.Bundle android.os.Bundle; import android.webkit.WebView android.webkit.WebView; public class BrowserDemo1 extends Activity { WebView browser; @Override public void onCreate(Bundle state) { super super.onCreate(state); setContentView(R.layout.main); browser=(WebView)findViewById(R.id.webkit); browser.loadUrl("http://www.andglobe.com"); } } (from WebKit/BrowserSecure/app/src/main/java/com/commonsware/android/browser1/BrowserDemo1.java) The project is set up to target 26: apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion '26.0.2' defaultConfig { minSdkVersion 25 targetSdkVersion 26 applicationId 'com.commonsware.android.browser.secure' } } (from WebKit/BrowserSecure/app/build.gradle) 1708 ADVANCED USES OF WEBVIEW If you change that to have it target 25, the app will run “normally” on Android 8.0, showing the designated Web page. But, with a targetSdkVersion set at 26, the WebView will not show that page, as it would be loaded over a cleartext (HTTP) connection: Figure 555: BrowserSecure Sample, Showing Banned Cleartext Traffic Chrome Custom Tabs Chrome custom tabs serve as middle ground between using a WebView in your own app and launching a URL into a separate Web browser. With a WebView, you have complete control over the overall user experience within your app. However, your WebView is decoupled from any other browser the user may be using on the device. Conversely, launching URLs into the user’s chosen browser gives the user their normal browsing experience, but you have no control over the user experience, as the user is now in the browser app, not your app. With Chrome custom tabs, while Chrome is handling the URL, it will allow you limited control over the action bar (color and custom actions). It also simplifies some things that you might otherwise have had to handle yourself, such as pre1709 ADVANCED USES OF WEBVIEW fetching a Web page to be able to quickly switch to it. Basic integration is also fairly easy, coming in the form of extras on the same sort of ACTION_VIEW Intent that you might have used for launching the URL in a standalone browser. At the same time, there are some concerns: • The documentation states that there is a “Shared Cookie Jar and permissions model so users don’t have to log in to sites they are already connected to, or re-grant permissions they have already granted”, which would require significant testing to ensure that you are not leaking information into Chrome that might be somehow delivered to other sites (including Google). • While it uses an ACTION_VIEW Intent, and so the user can choose to view the URL in a different browser, you will not get the custom integration in that case. This may be fine, but you will need to make sure that from a marketing and documentation standpoint you handle both the case where the user chooses Chrome (and you get the “custom tab”) and the case where the user chooses something else. • Since any app could handle the ACTION_VIEW Intent, you need to take into account that any information in the custom extras, like the PendingIntent to use for an custom action bar item, is stuff that you are willing for arbitrary apps to get their hands on. Do not assume that your communications will solely be with Chrome. 1710 THE INPUT METHOD FRAMEWORK The Input Method Framework We think of Android devices as having “soft keyboards”. The official term for this is that Android devices offer one or more “input method editors” (or “input methods” for short). These input methods allow for text entry on a touchscreen, avoiding the need for a physical keyboard. Note, though, that “text entry” does not necessarily imply an on-screen keyboard equivalent — for example, the old PalmOS Graffiti text entry system is available as an app on the Play Store. While it is possible to create custom input method editors — as the authors of Graffiti Pro did — this chapter is focused more on how ordinary app developers are affected by input methods, and how an app can help steer the behavior of the input method to benefit the user. Prerequisites Understanding this chapter requires that you have read the core chapters, particularly the section covering the EditText widget. Keyboards, Hard and Soft Some Android devices have a hardware keyboard that is visible some of the time (when it is slid out). A few Android devices have a hardware keyboard that is always visible (so-called “bar” or “slab” phones). Most Android devices, though, have no hardware keyboard at all. The IMF handles all of these scenarios. In short, if there is no hardware keyboard, an input method editor (IME) will be available to the user when they tap on an enabled EditText. This requires no code changes to your application… if the default functionality of the IME is what you want. Fortunately, Android is fairly smart about guessing what you want, so it may be you can just test with the IME but otherwise make no specific code changes. 1711 THE INPUT METHOD FRAMEWORK Of course, the keyboard may not quite behave how you would like. For example, in the Basic/Field sample project, the FieldDemo activity has the IME overlaying the multiple-line EditText: Figure 556: The input method editor, as seen in the FieldDemo sample application It would be nice to have more control over how this appears, and for other behavior of the IME. Fortunately, the framework as a whole gives you many options for this, as is described over the bulk of this chapter. Tailored To Your Needs Android 1.1 and earlier offered many attributes on EditText widgets to control their style of input, such as android:password to indicate a field should be for password entry (shrouding the password keystrokes from prying eyes). Starting in Android 1.5, with the IMF, many of these have been combined into a single android:inputType attribute. The android:inputType attribute takes a class plus modifiers, in a pipe-delimited list (where | is the pipe character). The class generally describes what the user is 1712 THE INPUT METHOD FRAMEWORK allowed to input, and this determines the basic set of keys available on the soft keyboard. The available classes are: 1. 2. 3. 4. 5. 6. text (the number phone datetime date time default) Many of these classes offer one or more modifiers, to further refine what the user will be entering. To help explain those, take a look at the res/layout/main.xml file from the InputMethod/IMEDemo1 project: (from InputMethod/IMEDemo1/app/src/main/res/layout/main.xml) Here, you will see a TableLayout containing five rows, each demonstrating a slightly different flavor of EditText: • One has no attributes at all on the EditText, meaning you get a plain text entry field • One has android:inputType = "text|textEmailAddress", meaning it is text entry, but specifically seeks an email address • One allows for signed decimal numeric input, via android:inputType = "number|numberSigned|numberDecimal" • One is set up to allow for data entry of a date (android:inputType = "date") • The last allows for multi-line input with auto-correction of probable spelling errors (android:inputType = "text|textMultiLine|textAutoCorrect") The class and modifiers tailor the keyboard. So, a plain text entry field results in a plain soft keyboard: 1714 THE INPUT METHOD FRAMEWORK Figure 557: A standard input method editor (a.k.a., soft keyboard) An email address field might put the @ symbol on the soft keyboard, perhaps at the cost of a smaller spacebar, depending on the keyboard implementation: 1715 THE INPUT METHOD FRAMEWORK Figure 558: The input method editor for email addresses Note, though, that this behavior is specific to the input method editor. Some editors might put an @ sign on the primary keyboard for an email field. Some might put a “.com” button on the primary keyboard. Some might not react at all. It is up to the implementation of the input method editor — all you can do is supply the hint. Numbers and dates restrict the keys to numeric keys, plus a set of symbols that may or may not be valid on a given field: 1716 THE INPUT METHOD FRAMEWORK Figure 559: The input method editor for signed decimal numbers And so on. By choosing the appropriate android:inputType, you can give the user a soft keyboard that best suits what it is they should be entering. Tell Android Where It Can Go You may have noticed a subtle difference between the first and second input method editors, beyond the addition of the @ key. If you look in the lower-right corner of the soft keyboard, the second field’s editor has a “Next” button, while the first field’s editor has a newline button. This points out two things: • EditText widgets are multi-line by default if you do not specify android:inputType • You can control what goes on with that lower-right-hand button, called the action key 1717 THE INPUT METHOD FRAMEWORK By default, on an EditText where you have specified android:inputType, the action key will be “Next”, moving you to the next EditText in sequence, or “Done”, if you are on the last EditText on the screen. You can manually stipulate what the action key will be labeled via the android:imeOptions attribute. For example, in the res/ layout/main.xml from the InputMethod/IMEDemo2 sample project, you will see an augmented version of the previous example, where two input fields specify what their action key should look like: (from InputMethod/IMEDemo2/app/src/main/res/layout/main.xml) Here, we attach a “Send” action to the action key for the email address (android:imeOptions = "actionSend"), and the “Done” action on the middle field (android:imeOptions = "actionDone"). By default, “Next” will move the focus to the next EditText and “Done” will close up the input method editor. However, for those, or for any other ones like “Send”, you can use setOnEditorActionListener() on EditText (technically, on the TextView superclass) to get control when the action key is clicked or the user presses the key. You are provided with a flag indicating the desired action (e.g., IME_ACTION_SEND), and you can then do something to handle that request (e.g., send an email to the supplied email address). If you need more control over the action button, you can set: • android:imeActionId, which provides a custom value for the actionId that is passed to onEditorAction() of your OnEditorActionListener • android:imeActionLabel, where you provide your own caption for the button (bearing in mind that your desired caption may or may not fit) Fitting In You will notice that the IMEDemo2 layout shown above has another difference from its IMEDemo1 predecessor: the use of a ScrollView container wrapping the TableLayout. 1719 THE INPUT METHOD FRAMEWORK This ties into another level of control you have over the input method editors: what happens to your activity’s own layout when the input method editor appears? There are three possibilities, depending on circumstances: 1. Android can “pan” your activity, effectively sliding the whole layout up to accommodate the input method editor, or overlaying your layout, depending on whether the EditText being edited is at the top or bottom. This has the effect of hiding some portion of your UI. 2. Android can resize your activity, effectively causing it to shrink to a smaller screen dimension, allowing the input method editor to sit below the activity itself. This is great when the layout can readily be shrunk (e.g., it is dominated by a list or multi-line input field that does not need the whole screen to be functional). 3. In landscape mode, Android may display the input method editor fullscreen, obscuring your entire activity. This allows for a bigger keyboard and generally easier data entry. Android controls the full-screen option purely on its own. And, by default, Android will choose between pan and resize modes depending on what your layout looks like. If you want to specifically choose between pan and resize, you can do so via an android:windowSoftInputMode attribute on the element in your AndroidManifest.xml file. For example, here is the manifest from IMEDemo2: > /> /> > > /> /> (from InputMethod/IMEDemo2/app/src/main/AndroidManifest.xml) Because we specified resize, Android will shrink our layout to accommodate the input method editor. With the ScrollView in place, this means the scrollbar will appear as needed when the user is scrolling: Figure 560: The shrunken, scrollable layout 1721 THE INPUT METHOD FRAMEWORK Jane, Stop This Crazy Thing! Sometimes, you need the input method editor to just go away. For example, if you make the action button be “Search”, the user tapping that button will not automatically hide the editor. To hide the editor, you will need to make a call to the InputMethodManager, a system service that controls these input method editors: InputMethodManager mgr=(InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); mgr.hideSoftInputFromWindow(fld.getWindowToken(), 0); (where fld is the EditText whose input method editor you want to hide) 1722 Fonts and Text Inevitably, you’ll get the question “hey, can we change this font?” when doing application development. The answer depends on what fonts come with the platform, whether you can add other fonts, and how to apply them to the widget or whatever needs the font change. Android is no different. It comes with some fonts plus a means for adding new fonts. Though, as with any new environment, there are a few idiosyncrasies to deal with. Prerequisites Understanding this chapter requires that you have read the core chapters, particularly the one on files. Love The One You’re With Android natively knows three fonts, by the shorthand names of “sans”, “serif”, and “monospace”. For Android 1.x, 2.x, and 3.x, these fonts are actually the Droid series of fonts, created for the Open Handset Alliance by Ascender. A new font set, Roboto, is used in Android 4.x and beyond, though the look of the font changed somewhat in Android 5.0. For those fonts, you can just reference them in your layout XML, if you choose, such as the following layout from the Fonts/FontSampler sample project: > > (from Fonts/FontSampler/app/src/main/res/layout/main.xml) This layout builds a table showing short samples of five fonts. Notice how the first three have the android:typeface attribute, whose value is one of the three built-in font faces (e.g., “sans”). The three built-in fonts are very nice. However, it may be that a designer, or a manager, or a customer wants a different font than one of those three. Or perhaps you want to use a font for specialized purposes, such as an image font instead of a series of PNG graphics. The easiest way to accomplish this is to package the desired font(s) with your application. To do this, simply create an assets/ folder in the project root, and put your TrueType (TTF) fonts in the assets. You might, for example, create assets/ fonts/ and put your TTF files in there. Note that Android has some support for OpenType (OTF) fonts, as well. Then, you need to tell your widgets to use that font. Unfortunately, you can no longer use layout XML for this, since the XML does not know about any fonts you may have tucked away as an application asset. Instead, you need to make the change in Java code: 1725 FONTS AND TEXT package com.commonsware.android.fonts; import import import import import import import android.app.Activity android.app.Activity; android.graphics.Typeface android.graphics.Typeface; android.os.Bundle android.os.Bundle; android.os.Environment android.os.Environment; android.view.View android.view.View; android.widget.TextView android.widget.TextView; java.io.File java.io.File; public class FontSampler extends Activity { @Override public void onCreate(Bundle state) { super super.onCreate(state); setContentView(R.layout.main); TextView tv=(TextView)findViewById(R.id.custom); Typeface face= Typeface.createFromAsset(getAssets(), "fonts/HandmadeTypewriter.ttf"); tv.setTypeface(face); File font= new File(Environment.getExternalStorageDirectory(), "MgOpenCosmeticaBold.ttf"); if (font.exists()) { tv=(TextView)findViewById(R.id.file); face=Typeface.createFromFile(font); tv.setTypeface(face); } else { findViewById(R.id.filerow).setVisibility(View.GONE); } } } (from Fonts/FontSampler/app/src/main/java/com/commonsware/android/fonts/FontSampler.java) Here we grab the TextView for our “custom” sample, then create a Typeface object via the static createFromAsset() builder method. This takes the application’s AssetManager (from getAssets()) and a path within your assets/ directory to the font you want. Then, it is just a matter of telling the TextView to setTypeface(), providing the Typeface you just created. In this case, we are using the Handmade Typewriter font. You can also load a font out of a local file and use it. The benefit is that you can customize your fonts after your application has been distributed. On the other hand, you have to somehow arrange to get the font onto the device. But just as you can get a Typeface via createFromAsset(), you can get a Typeface via createFromFile(). In our FontSampler, we look in the root of “external storage” (typically the SD card) for 1726 FONTS AND TEXT the MgOpenCosmeticaBold TrueType font file, and if it is found, we use it for the fifth row of the table. Otherwise, we hide that row. The results? Figure 561: The FontSampler application Note that Android does not seem to like all TrueType fonts. When Android dislikes a custom font, rather than raise an Exception, it seems to substitute Droid Sans (“sans”) quietly. So, if you try to use a different font and it does not seem to be working, it may be that the font in question is incompatible with Android, for whatever reason. Yeah, But Do We Really Have To Do This in Java? One common complaint with font handling in Android is that you have to apply a custom font on a per-widget basis in Java code. This gets old quickly. 1727 FONTS AND TEXT It is not too bad with just a single TextView. But for a whole activity, or a whole application, changing all of the relevant TextView widgets (and descendents, like Button) gets to be a bit tedious. While there are “traverse the widget hierarchy and fix up the fonts” code snippets available, you are probably better served using a third-party library, like Christoper Jenkins’ Calligraphy, which lets you define custom fonts in layout XML files or style resources. Here a Glyph, There a Glyph TrueType fonts can be rather pudgy, particularly if they support an extensive subset of the available Unicode characters. The Handmade Typewriter font used above runs over 70KB; the DejaVu free fonts can run upwards of 500KB apiece. Even compressed, these add bulk to your application, so be careful not to go overboard with custom fonts, lest your application take up too much room on your users’ phones. Conversely, bear in mind that fonts may not have all of the glyphs that you need. As an example, let us talk about the ellipsis. Android’s TextView class has the built-in ability to “ellipsize” text, truncating it and adding an ellipsis if the text is longer than the available space. You can use this via the android:ellipsize attribute, for example. This works fairly well, at least for single-line text. The ellipsis that Android uses is not three periods. Rather it uses an actual ellipsis character, where the three dots are contained in a single glyph. Hence, any font that you use in a TextView where you also use the “ellipsizing” feature will need the ellipsis glyph. Beyond that, though, Android pads out the string that gets rendered on-screen, such that the length (in characters) is the same before and after “ellipsizing”. To make this work, Android replaces one character with the ellipsis, and replaces all other removed characters with the Unicode character ‘ZERO WIDTH NO-BREAK SPACE’ (U+FEFF). This means the “extra” characters after the ellipsis do not take up any visible space on screen, yet they can be part of the string. However, this means any custom fonts you use for TextView widgets that you use with android:ellipsize must also support this special Unicode character. Not all 1728 FONTS AND TEXT fonts do, and you will get artifacts in the on-screen representation of your shortened strings if your font lacks this character (e.g., rogue X’s appear at the end of the line). And, of course, Android’s international deployment means your font must handle any language your users might be looking to enter, perhaps through a languagespecific input method editor. Hence, while using custom fonts in Android is very possible, there are many potential problems, and so you must weigh carefully the benefits of the custom fonts versus their potential costs. Auto-Sizing TextView Text comes in all lengths. Sometimes, when showing text in a TextView, we can allow that text to word-wrap and extend vertically. Other times, though, that proves to be impractical, such as when using a TextView as a label for another widget. However, even in those times, the text to be shown may vary in length by a significant amount. Translations of the label’s text might range from a couple of kanji in Japanese to a 20-letter word in German or Icelandic. One long-standing solution to that problem has been to use an auto-sizing TextView. Here, what is being “auto-sized” is the size of the font used for the text, to keep the TextView at a fixed dimension regardless of translation. It is up to the developer to ensure that for a given screen size and translation that the font does not wind up being too small to be read. However, Android itself never had a widget for this, so developers would rely instead upon third-party or home-grown implementations. Android 8.0 adds this sort of auto-sizing capability to TextView itself (and, by extension, subclasses like Button). You have two main approaches for implementing this: • Set android:autoSizeTextType="uniform" on the TextView to engage autosize capability. Then, use android:autoSizeMinTextSize and android:autoSizeMaxTextSize to set the lower and upper bounds for the text size, where Android can choose any size in between those. If you also add android:autoSizeStepGranularity, you can choose the increments in 1729 FONTS AND TEXT which Android will move between the ends of the text size range (the default is 1px). • Set android:autoSizeTextType="uniform" on the TextView, as in the above option. Then, instead of providing the starting and ending values of a range, use an resource to define specific sizes that you want to support, then use android:autoSizePresetSizes to point to that resource. This is a bit more difficult to set up, as you need to define the array resource, but it may simplify testing, as you are in complete control over the possible sizes. To make this work, you need to constrain the size of the TextView, so that it does not expand to fill all available space. That might be through having both axes set to wrap_content, but have the container holding the TextView limit how big the TextView can get. It might be through TextView-specific configuration, such as android:maxLines. Or, it might be through setting the size of the axes to be some specific dimension or match_parent. The Basic/AutoSize sample project illustrates the use of both forms of android:autoSizeTextType. The activity’s layout consists of an EditText, a pair of TextView widgets, and a pair of divider lines (horizontal View widgets with background and margin), all inside of a vertical LinearLayout: > 1730 FONTS AND TEXT (from Basic/AutoSize/app/src/main/res/layout/activity_main.xml) Both TextView widgets have android:autoSizeTextType set to uniform. The top one uses android:autoSizeMinTextSize, android:autoSizeMaxTextSize, and android:autoSizeStepGranularity to allow the text size to float between 5sp and 40sp in 5sp increments. The bottom one uses android:autoSizePresetSizes to tie in an array resource for the valid sizes to use: > 10sp 12sp 14sp 16sp 18sp 20sp 1731 FONTS AND TEXT (from Basic/AutoSize/app/src/main/res/values/arrays.xml) Here, the size can float between 10sp and 20sp in 2sp increments. However, there is no requirement that the sizes increment in a uniform fashion when using the array approach. The MainActivity that uses the layout sets up a TextWatcher on the EditText and copies what you enter into the two TextView widgets, to allow you to experiment in real time with changes in the text size: EditText input=(EditText)findViewById(R.id.input); final TextView granular=(TextView)findViewById(R.id.granular); final TextView steps=(TextView)findViewById(R.id.steps); input.addTextChangedListener(new new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { // unused } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { // unused } @Override public void afterTextChanged(Editable editable) { granular.setText(editable.toString()); steps.setText(editable.toString()); } }); } } (from Basic/AutoSize/app/src/main/java/com/commonsware/android/autosize/MainActivity.java) When you run the app, initially the EditText and corresponding TextView widgets have no text. If you start typing, you will see your text appear in the TextView widgets: 1732 FONTS AND TEXT Figure 562: Auto-Sizing TextViews, with Some Text As you continue typing, the text size decreases: 1733 FONTS AND TEXT Figure 563: Auto-Sizing TextViews, with Some More Text If you are using appcompat-v7, there are equivalent capabilities added to its wrapper backport of TextView. Justified Text If you are reading the PDF edition of this book, its paragraphs do not use justified text. If you are reading the Kindle edition of this book — at least when using the Amazon Kindle app for Android — its paragraphs do use justified text. Justified text is when text (e.g., in the middle of a paragraph) fills the entire line, usually with bits of extra space added between the words to get them to neatly fill the available horizontal space. For years, TextView never supported justified text, though you could get it through third-party libraries. In Android 8.0+, you can now enable justified text on a TextView via setJustify(). At the present time, the documentation does not show an android:justify attribute, though, with luck, it will be added in a future update. 1734 Rich Text Plain text is so, well, plain. Fortunately, Android has fairly extensive support for formatted text, before you need to break out something as heavy-weight as WebView. However, some of this rich text support has been shrouded in mystery, particularly how you would allow users to edit formatted text. This chapter will explain how the rich text support in Android works and how you can take advantage of it, with particular emphasis on some open source projects to help you do just that. Prerequisites Understanding this chapter requires that you have read the core chapters, particularly the ones on basic widgets and the input method framework. The Span Concept You may have noticed that many methods in Android accept or return a CharSequence. The CharSequence interface is little used in traditional Java, if for no other reason than there are relatively few implementations of it outside of String. However, in Android, CharSequence becomes much more important, because of a sub-interface named Spanned. Spanned defines sequences of characters (CharSequence) that contain inline markup rules. These rules — mostly instances of CharacterStyle and ParagraphStyle subclasses – indicate whether the “spanned” portion of the characters should be 1735 RICH TEXT rendered in an alternate font, or be turned into a hyperlink, or have other effects applied to them. Methods that take a CharSequence as a parameter, therefore, can work equally well with String objects as well as objects that implement Spanned. Implementations The base interface for rich-text CharSequence objects is Spanned. This is used for any CharSequence that has inline markup rules, and it defines methods for retrieving markup rules applied to portions of the underlying text. The primary concrete implementation of Spanned is SpannedString. SpannedString, like String, is immutable — you cannot change either the text or the formatting of a SpannedString. There is also the Spannable sub-interface of Spanned. Spannable is used for any CharSequence with inline markup rules that can be modified, and it defines the methods for modifying the formatting. There is a corresponding SpannableString implementation. Finally, there is a related Editable interface, which is for a CharSequence that can have its text modified in-place. SpannableStringBuilder implements both Editable and Spannable, for modifying text and formatting at the same time. TextView and Spanned One of the most important uses of Spanned objects is with TextView. TextView is capable of rendering a Spanned, complete with all of the specified formatting. So, if you have a Spanned that indicates that the third word should be rendered in italics, TextView will faithfully italicize that word. TextView, of course, is an ancestor of many other widgets, from EditText to Button to CheckBox. Each of those, therefore, can use and render Spannable objects. The fact that EditText has the ability to render Spanned objects — and even allow them to be edited — is key for allowing users to enter rich text themselves as part of your UI. 1736 RICH TEXT Available Spans As noted above, the markup rules come in the form of instances of base classes known as CharacterStyle and ParagraphStyle. Despite those names, most of the SDK-supplied subclasses of CharacterStyle and ParagraphStyle end in Span (not Style), and so you will likely see references to these as “spans” as often as “styles”. That also helps minimize confusion between character styles and style resources. There are well over a dozen supplied CharacterStyle subclasses, including: 1. ForegroundColorSpan and BackgroundColorSpan for coloring text 2. StyleSpan, TextAppearanceSpan, TypefaceSpan, UnderlineSpan, and StrikethroughSpan for affecting the true “style” of text 3. AbsoluteSizeSpan, RelativeSizeSpan, SuperscriptSpan, and SubscriptSpan for affecting the size (and, in some cases, vertical position) of the text And so on. Similarly, ParagraphStyle has subclasses like BulletSpan for bulleted lists. You can implement your own custom subclasses of CharacterStyle and ParagraphStyle, though the book does not cover this subject at this time. Loading Rich Text Spanned objects do not appear by magic. Plenty of things in Java will give you ordinary strings, from XML and JSON parsers to loading data out of a database to simply hard-coding string constants. However, there are only a few ways that you as a developer will get a Spanned complete with formatting, and that includes you creating such a Spanned yourself by hand. String Resource The primary way most developers get a Spanned object into their application is via a string resource. String resources support inline markup in the form of HTML tags. Bold (), italics (), and underline () are officially supported, such as: >Welcome to Android ! 1737 RICH TEXT When you retrieve the string resource via getText(), you get back a CharSequence that represents a Spanned object with the markup rules in place. HTML The next-most common way to get a Spanned object is to use Html.fromHtml(). This parses an HTML string and returns a Spanned object, with all recognized tags converted into corresponding spans. You might use this for text loaded from a database, retrieved from a Web service call, extracted from an RSS feed, etc. Unfortunately, the list of tags that fromHtml() understands is undocumented. Based upon the source code to fromHtml(), the following seem safe: • • • • • • • • • • • • • • • • • • • • • • • • •

1738 RICH TEXT However, do bear in mind that these are undocumented and therefore are subject to change. Also note that fromHtml() is perhaps slower than you might think, particularly for longer strings. You might also wind up using some other support code to get your HTML. For example, some data sources might publish text formatted as Markdown — Stack Overflow, GitHub, etc. use this extensively. Markdown can be converted to HTML, through any number of available Java libraries or via CWAC-AndDown, which wraps the native hoedown Markdown-to-HTML converter for maximum speed. CWACAndDown will be explored in a bit more detail in the chapter on the NDK. From EditText The reason why so much sample code calls getText() followed by toString() on an EditText widget is because EditText is going to return an Editable object from getText(), not a simple string. That’s because, in theory, EditText could be returning something with formatting applied. The call to toString() simply strips out any potential formatting as part of giving you back a String. However, you could elect to use the Editable object (presumably a SpannableStringBuilder) if you wanted, such as for pouring the entered text into a TextView, complete with any formatting that might have wound up on the entered text. Actually getting formatting applied to the contents of an EditText is covered later in this chapter. Manually You are welcome to create a SpannableString via its constructor, supplying the text that you wish to display, then calling various methods on SpannableString to format it. We will see an example of this later in this chapter. Or, you are welcome to create a SpannableStringBuilder via its constructor. In some respects, SpannableStringBuilder works like the classic StringBuilder — you call append() to add more text. However, SpannableStringBuilder also offers delete(), insert(), and replace() methods to modify portions of the existing content. It also supports the same methods that SpannableString does, via the Spannable interface, for applying formatting rules to portions of text. 1739 RICH TEXT Editing Rich Text If the Spannable you wound up with is a SpannedString, it is what it is — you cannot change it. If, however, you have a SpannableString, that can be modified by you, or by the user. Of course, allowing the user to modify a Spannable gets a wee bit tricky, and is why the RichEditText project was born. RichEditText If you load a Spannable into an EditText, the formatting will not only be displayed, but it will be part of the editing experience. For example, if the phrase “the fox jumped” is in bold, and the user adds in more words to make it “the quick brown fox jumped”, the additional words will also be in boldface. That is because the user is modifying text in the middle of a defined span, and so therefore the adjusted text is rendered according to that span. The biggest problem is that EditText alone has no mechanism to allow users to change formatting. Perhaps someday it will have options for that. In the meantime, though, RichEditText is designed to fill that gap. RichEditText is a CWAC project that offers a reasonably convenient API for applying, toggling, or removing effects applied to the current selected text. You have your choice of creating your own UI for this (e.g., implementing a toolbar) or enabling an extension to the EditText action modes to allow the users to format the text. More information on using RichEditText can be found on the project site. Manually Spannable offers two methods for modifying its formatting: setSpan() to apply formatting, and removeSpan() to get rid of an existing span. And, since Spannable extends Spanned, a Spannable also has getSpans(), to return existing spans of a current type within a certain range of characters in the text. These methods, along with others on Spanned, allow you to get and set whatever formatting you wish to apply on a Spannable object, such as a SpannableString. For example, let’s take a look at the RichText/Search sample project. Here, we are going to load some text into a TextView, then allow the user to enter a search string 1740 RICH TEXT in an EditText, and we will use the Spannable methods to highlight the search string occurrences inside the text in the TextView. Our layout is simply an EditText atop a TextView (wrapped in a ScrollView): > > > /> (from RichText/Search/app/src/main/res/layout/main.xml) We pre-fill the TextView with a string resource (@string/address), which in this project is the text of Lincoln’s Gettysburg Address, with a bit of inline markup (e.g., “Four score and seven years ago” italicized). So, when we fire up the project at the outset, we see the formatted prose from the string resource: 1741 RICH TEXT Figure 564: The RichTextSearch sample, as initially launched In onCreate() of our activity, we find the EditText widget and designate the activity itself as being an OnEditorActionListener for the EditText: @Override public void onCreate(Bundle savedInstanceState) { super super.onCreate(savedInstanceState); setContentView(R.layout.main); search=(EditText)findViewById(R.id.search); search.setOnEditorActionListener(this this); } (from RichText/Search/app/src/main/java/com/commonsware/android/rich/search/RichTextSearchActivity.java) That means when the user presses , we will get control in an onEditorAction() method. There, we pass the search text to a private searchFor() method, plus ensure that the input method editor is hidden (if one was used to fill in the search text): @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (event == null || event.getAction() == KeyEvent.ACTION_UP) { 1742 RICH TEXT searchFor(search.getText().toString()); InputMethodManager imm= (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); } return return(true true); } (from RichText/Search/app/src/main/java/com/commonsware/android/rich/search/RichTextSearchActivity.java) The searchFor() method is where the formatting is applied to our search text: private void searchFor(String text) { TextView prose=(TextView)findViewById(R.id.prose); Spannable raw=new new SpannableString(prose.getText()); BackgroundColorSpan[] spans=raw.getSpans(0, raw.length(), BackgroundColorSpan.class); for (BackgroundColorSpan span : spans) { raw.removeSpan(span); } int index=TextUtils.indexOf(raw, text); while (index >= 0) { raw.setSpan(new new BackgroundColorSpan(0xFF8B008B), index, index + text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); index=TextUtils.indexOf(raw, text, index + text.length()); } prose.setText(raw); } (from RichText/Search/app/src/main/java/com/commonsware/android/rich/search/RichTextSearchActivity.java) First, we get a Spannable object out of the TextView. While an EditText returns an Editable from getText(), getText() on a TextView returns a CharSequence. In particular, the first time we execute searchFor(), getText() will return a SpannedString, as that is what a string resource turns into. However, that is not modifiable, so we convert it into a SpannableString so we can apply formatting to it. An optimization would be to see if getText() returns something implementing Spannable and then just using it directly. 1743 RICH TEXT We want to highlight the search terms using a BackgroundColorSpan. However, that means we first need to get rid of any existing BackgroundColorSpan objects applied to the prose from a previous search — otherwise, we would keep highlighting more and more of the prose. So, we use getSpans() to find all BackgroundColorSpan objects anywhere in the prose (from index 0 through the length of the text). For each that we find, we call removeSpan() to get rid of it from our Spannable. Then, we use indexOf() on TextUtils to find the first occurrence of whatever the user typed into the EditText. If we find it, we create a new BackgroundColorSpan and apply it to the matching portion of the prose using setSpan(). The last parameter to setSpan() is a flag, indicating what should happen if text is inserted at either the starting or ending point. In our case, the text itself is remaining constant, so the flag does not matter much – here, we use SPAN_EXCLUSIVE_EXCLUSIVE, which would mean that the span would not cover any text inserted at the starting or ending point of the span. We then continue using indexOf() to find any remaining occurrences of the search text. Once we are done modifying our Spannable, we put it into the TextView via setText(). The result is that all matching substrings are highlighted in a purple/magenta shade: 1744 RICH TEXT Figure 565: The RichTextSearch sample, after searching on “can” Saving Rich Text SpannableString and SpannedString are not Serializable. There is no built-in way to persist them directly. However, Html.toHtml() will convert a Spanned object into corresponding HTML, for all CharacterStyle and ParagraphStyle objects that can be readily converted into HTML. You can then persist the resulting HTML any place you would persist a String (e.g., database column). In principle, you could create other similar conversion code, such as something to take a Spanned and return the corresponding Markdown source. Manipulating Rich Text The TextUtils class has many utility methods that manipulate a CharSequence, to allow you to do things that you might ordinarily have done just with methods on String. These utility methods will work with any CharSequence, including SpannedString and SpannableString. 1745 RICH TEXT Some are specifically aimed at Spanned objects, such as copySpansFrom() (to apply formatting from one CharSequence onto another). Some are clones of String equivalents, such as split(), join(), and substring(). Yet others are designed for developers using the Canvas 2D drawing API, such as ellipsize() and commaEllipsize() for intelligently truncating messages. 1746 Animators Users like things that move. Or fade, spin, or otherwise offer a dynamic experience. Much of the time, such animations are handled for us by the framework. We do not have to worry about sliding rows in a ListView when the user scrolls, or as the user pans around a ViewPager, and so forth. However, sometimes, we will need to add our own animations, where we want effects that either are not provided by the framework innately or are simply different (e.g., want something to slide off the bottom of the screen, rather than off the left edge). Android had an animation framework back in the beginning, one that is still available for you today. However, Android 3.0 introduced a new animator framework that is going to be Android’s primary focus for animated effects going forward. Many, but not all, of the animator framework capabilities are available to us as developers via a backport. Prerequisites Understanding this chapter requires that you have read the core chapters of this book. Also, you should read the chapter on custom views, to be able to make sense of one of the samples. ViewPropertyAnimator Let’s say that you want to fade out a widget, instead of simply setting its visibility to INVISIBLE or GONE. 1747 ANIMATORS For a widget whose name is v, on API Level 11 or higher, that is as simple as: v.animate().alpha(0); Here, “alpha” refers to the “alpha channel”. An alpha of 1 is normal opacity, while an alpha of 0 is completely transparent, with values in between representing various levels of translucence. That may seem rather simple. The good news is, it really is that easy. Of course, there is a lot more you can do here, and you might have to worry about supporting older Android versions, and we need to think about things other than fading widgets in and out, and so forth. First, though, let’s consider what is really going on when we call animate() on a widget on API Level 11+. Native Implementation The call to animate() returns an instance of ViewPropertyAnimator. This object allows us to build up a description of an animation to be performed, such as calling alpha() to change the alpha channel value. ViewPropertyAnimator uses a so-called fluent interface, much like the various builder classes (e.g., Notification.Builder) — calling a method on a ViewPropertyAnimator() usually returns the ViewPropertyAnimator itself. This allows you to build up an animation via a chained series of method calls, starting with that call to animate() on the widget. You will note that we do not end the chain of method calls with something like a start() method. ViewPropertyAnimator will automatically arrange to start the animation once we return control of the main application thread back to the framework. Hence, we do not have to explicitly start the animation. You will also notice that we did not indicate any particulars about how the animation should be accomplished, beyond stating the ending alpha channel value of 0. ViewPropertyAnimator will use some standard defaults for the animation, such as a default duration, to determine how quickly Android changes the alpha value from its starting point to 0. Most of those particulars can be overridden from their defaults via additional methods called on our ViewPropertyAnimator, such as setDuration() to provide a duration in milliseconds. There are four standard animations that ViewPropertyAnimator can perform: 1748 ANIMATORS 1. Changes in alpha channel values, for fading widgets in and out 2. Changes in widget position, by altering the X and Y values of the upper-left corner of the widget, from wherever on the screen it used to be to some new value 3. Changes in the widget’s rotation, around any of the three axes 4. Changes in the widget’s size, where Android can scale the widget by some percentage to expand or shrink it We will see an example of changing a widget’s position, using the translationXBy() method, later in this chapter. You are welcome to use more than one animation effect simultaneously, such as using both alpha() and translationXBy() to slide a widget horizontally and have it fade in or out. There are other aspects of the animation that you can control. By default, the animation happens linearly — if we are sliding 500 pixels in 500ms, the widget will move evenly at 1 pixel/ms. However, you can specify a different “interpolator” to override that default linear behavior (e.g., start slow and accelerate as the animation proceeds). You can attach a listener object to find out about when the animation starts and ends. And, you can specify withLayer() to indicate that Android should try to more aggressively use hardware acceleration for an animation, a concept that we will get into in greater detail later in this chapter. To see this in action, take a look at the Animation/AnimatorFade sample app. The app consists of a single activity (MainActivity). It uses a layout that is dominated by a single TextView widget, whose ID is fadee: > /> 1749 ANIMATORS (from Animation/AnimatorFade/app/src/main/res/layout/activity_main.xml) In onCreate(), we load up the layout and get our hands on the fadee widget: @Override public void onCreate(Bundle savedInstanceState) { super super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fadee=(TextView)findViewById(R.id.fadee); } (from Animation/AnimatorFade/app/src/main/java/com/commonsware/android/animator/fade/MainActivity.java) MainActivity itself implements Runnable, and our run() method will perform some animated effects: @Override public void run() { if (fadingOut) { fadee.animate().alpha(0).setDuration(PERIOD); fadee.setText(R.string.fading_out); } else { fadee.animate().alpha(1).setDuration(PERIOD); fadee.setText(R.string.coming_back); } fadingOut=!fadingOut; fadee.postDelayed(this this, PERIOD); } (from Animation/AnimatorFade/app/src/main/java/com/commonsware/android/animator/fade/MainActivity.java) Specifically, we use ViewPropertyAnimator to fade out the TextView over a certain period (fadee.animate().alpha(0).setDuration(PERIOD);) and set its caption to a value indicating that we are fading out. If we are to be fading back in, we perform the opposite animation and set the caption to a different value. We then flip the fadingOut boolean for the next pass and use postDelayed() to reschedule ourselves to run after the period has elapsed. 1750 ANIMATORS To complete the process, we run() our code initially in onStop() and cancel the postDelayed() loop in onStart(): @Override public void onStart() { super super.onStart(); run(); } @Override public void onStop() { fadee.removeCallbacks(this this); super super.onStop(); } (from Animation/AnimatorFade/app/src/main/java/com/commonsware/android/animator/fade/MainActivity.java) The result is that the TextView smoothly fades out and in, alternating captions as it goes. However, it would be really unpleasant if all this animator goodness worked only on API Level 11+. Fortunately for us, somebody wrote a backport. Backport Via NineOldAndroids Jake Wharton wrote NineOldAndroids. This is, in effect, a backport of ViewPropertyAnimator and its underpinnings. There are some slight changes in how you use it, because NineOldAndroids is simply a library. It cannot add methods to existing classes (like adding animate() to View), nor can it add capabilities that the underlying firmware simply lacks. But, it may cover many of your animator needs, even if the name is somewhat inexplicable, and it works going all the way back to API Level 1, ensuring that it will cover any Android release that you care about. NineOldAndroids is an Android library project. Android Studio users can add a implementation statement to their dependencies closure in build.gradle to pull in com.nineoldandroids:library:... (for some version indicated by ...). Since NineOldAndroids cannot add animate() to View, the recommended approach is to use a somewhat obscure feature of Java: imported static methods. An import static statement, referencing a particular static method of a class, makes that method available as if it were a static method on the class that you are writing, or as 1751 ANIMATORS some sort of global function. NineOldAndroids has an animate() method that you can import this way, so instead of v.animate(), you use animate(v) to accomplish the same end. Everything else is the same, except perhaps some imports, to reference NineOldAndroids instead of the native classes. You can see this in the Animation/AnimatorFadeBC sample app. In addition to having the NineOldAndroids JAR in libs/, the only difference between this edition and the previous sample is in how the animation is set up. Instead of lines like: fadee.animate().alpha(0).setDuration(PERIOD); we have: animate(fadee).alpha(0).setDuration(PERIOD); This takes advantage of our static import: import static com.nineoldandroids.view.ViewPropertyAnimator.animate; If the static import makes you queasy, you are welcome to simply import the com.nineoldandroids.view.ViewPropertyAnimator class, rather than the static method, and call the animate() method on ViewPropertyAnimator: ViewPropertyAnimator.animate(fadee).alpha(0).setDuration(PERIOD); The Foundation: Value and Object Animators ViewPropertyAnimator itself is a layer atop of a more primitive set of animators, known as value and object animators. A ValueAnimator handles the core logic of transitioning some value, from an old to a new value, over a period of time. ValueAnimator offers replaceable “interpolators”, which will determine how the values change from start to finish over the animation period (e.g., start slowly, accelerate, then end slowly). ValueAnimator also handles the concept of a “repeat mode”, to indicate if the animation should simply happen once, a fixed number of times, or should infinitely repeat (and, in the latter cases, whether it does so always transitioning from start to finish or if it reverses direction on alternate passes, going from finish back to start). 1752 ANIMATORS What ValueAnimator does not do is actually change anything. It is merely computing the different values based on time. You can call getAnimatedValue() to find out the value at any point in time, or you can call addUpdateListener() to register a listener object that will be notified of each change in the value, so that change can be applied somewhere. Hence, what tends to be a bit more popular is ObjectAnimator, a subclass of ValueAnimator that automatically applies the new values. ObjectAnimator does this by calling a setter method on some object, where you supply the object and the “property name” used to derive the getter and setter method names. For example, if you request a property name of foo, ObjectAnimator will try to call getFoo() and setFoo() methods on your supplied object. As with ViewPropertyAnimator, ValueAnimator and ObjectAnimator are implemented natively in API Level 11 and are available via the NineOldAndroids backport as well. To see what ObjectAnimator looks like in practice, let us examine the Animation/ ObjectAnimator sample app. Once again, our activity’s layout is pretty much just a centered TextView, here named word: > /> (from Animation/ObjectAnimator/app/src/main/res/layout/activity_main.xml) The objective of our activity is to iterate through 25 words, showing one at a time in the TextView: 1753 ANIMATORS package com.commonsware.android.animator.obj; import import import import import android.app.Activity android.app.Activity; android.os.Bundle android.os.Bundle; android.widget.TextView android.widget.TextView; com.nineoldandroids.animation.ObjectAnimator com.nineoldandroids.animation.ObjectAnimator; com.nineoldandroids.animation.ValueAnimator com.nineoldandroids.animation.ValueAnimator; public class MainActivity extends Activity { private static final String[] items= { "lorem", "ipsum", "dolor", "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi", "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel", "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque", "augue", "purus" }; private TextView word=null null; int position=0; @Override public void onCreate(Bundle savedInstanceState) { super super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); word=(TextView)findViewById(R.id.word); ValueAnimator positionAnim = ObjectAnimator.ofInt(this this, "wordPosition", 0, 24); positionAnim.setDuration(12500); positionAnim.setRepeatCount(ValueAnimator.INFINITE); positionAnim.setRepeatMode(ValueAnimator.RESTART); positionAnim.start(); } public void setWordPosition(int position) { this this.position=position; word.setText(items[position]); } public int getWordPosition() { return return(position); } } (from Animation/ObjectAnimator/app/src/main/java/com/commonsware/android/animator/obj/MainActivity.java) To accomplish this, we use NineOldAndroids version of ObjectAnimator, saying that we wish to “animate” the wordPosition property of the activity itself, from 0 to 24. We configure the animation to run for 12.5 seconds (i.e., 500ms per word) and to repeat indefinitely by restarting the animation from the beginning on each pass. We then call start() to kick off the animation. For this to work, though, we need getWordPosition() and setWordPosition() accessor methods for the theoretical wordPosition property. In our case, the “word position” is simply an integer data member of the activity, which we return in getWordPosition() and update in setWordPosition(). However, we also update the TextView in setWordPosition(), to display the word at that position. 1754 ANIMATORS The net effect is that words appear in our TextView, changing on average every 500ms. Animating Custom Types In the previous section, we animated an int property of an Activity. That works, because Android knows how to compute int values between the start and end position, through simple math. But, what if we wanted to animate something that is not a simple number? For example, what if we want to animate a Color, or a LatLng from Maps V2, or a TastyTreat class of our own design? So long as we can perform the calculations, we can animate a type of anything we want, using TypeEvaluator and ofObject() on ObjectAnimator. A TypeEvaluator is a simple interface, containing a single method that we need to override: evaluate(). However, TypeEvaluator uses generics, and so our implementation will actually be of some concrete class (e.g., a TypeEvaluator of TastyTreat). Our job in evaluate() is to return a value of our designated type (e.g., TastyTreat) given three inputs: 1. The initial value for our animation range, in the form of our designated type 2. The end value for our animation range, in the form of our designated type 3. The fraction along that range that represents how much we have moved from the initial value to the end value Note that the fraction is not limited to being between 0 and 1, as certain interpolators (e.g., an overshoot interpolator) might result in a fraction being negative (e.g., we overshot past the initial value) or greater than one (e.g., we overshot past the end value). For example, to have a TypeEvaluator of Color, we might have evaluate() generate a new Color instance based upon applying the fraction to the initial and end red, green, blue, and alpha channels. To use a TypeEvaluator, instead of ofInt(), ofFloat(), or similar simple factory methods on ObjectAnimator, we use ofObject(). ofObject() takes the object to be animated, the property to be animated, the TypeEvaluator to assist in the actual 1755 ANIMATORS animation, and the final value of the animation (or, optionally, a series of waypoints to be animated along). A flavor of ofObject() that takes the property name — akin to the wordPosition ofInt() used in the previous section — has been around since API Level 11. API Level 14 added an ofObject() method that takes a Property value instead of the name of the property. This version has the added benefit of type-safety, as it can ensure that your object to be animated, TypeEvaluator, and final position are all of the same type. You can see an example of using TypeEvaluator this way in the chapter on Maps V2, as we animate the movement of a map marker from a starting point to an ending point. Hardware Acceleration Animated effects operate much more smoothly with hardware acceleration. There are two facets to employing hardware acceleration for animations: enabling it overall and directing its use for the animations themselves. Hardware acceleration is enabled overall on Android devices running Android 4.0 or higher (API Level 14). On Android 3.x, hardware acceleration is available but is disabled by default — use android:hardwareAccelerated="true" in your or element in the manifest to enable it on those versions. Hardware acceleration for 2D graphics operations like widget animations is not available on older versions of Android. While this will provide some benefit across the board, you may also wish to consider rendering animated widgets or containers in an off-screen buffer, or “hardware layer”, that then gets applied to the screen via the GPU. In particular, the GPU can apply certain animated transformations to a hardware layer without forcing software to redraw the widgets or containers (e.g., what happens when you invalidate() them). As it turns out, these GPU-enhanced transformations match the ones supported by ViewPropertyAnimator: 1. Changes in alpha channel values, for fading widgets in and out 2. Changes in widget position, by altering the X and Y values of the upper-left corner of the widget, from wherever on the screen it used to be to some new value 3. Changes in the widget’s rotation, around any of the three axes 1756 ANIMATORS 4. Changes in the widget’s size, where Android can scale the widget by some percentage to expand or shrink it By having the widget be rendered in a hardware layer, these ViewPropertyAnimator operations are significantly more efficient than before. However, since hardware layers take up video memory, generally you do not want to keep a widget or container in a hardware layer indefinitely. Instead, the recommended approach is to have the widget or container be rendered in a hardware layer only while the animation is ongoing, by calling setLayerType() for LAYER_TYPE_HARDWARE before the animation begins, then calling setLayerType() for LAYER_TYPE_NONE (i.e., return to default behavior) when the animation completes. Or, for ViewPropertyAnimator on API Level 16 and higher, use withLayer() in the fluent interface to have it apply the hardware layer automatically just for the animation duration. We will see examples of using hardware acceleration this way in the next section. The Three-Fragment Problem The original tablet implementation of Gmail organized its landscape main activity into two panes, one on the left taking up ~30% of the screen, and one on the right taking up the remainder: Figure 566: Gmail Fragments (image courtesy of Google and AOSP) Gmail had a very specific navigation mode in its main activity when viewed in landscape on a tablet, where upon some UI event (e.g., tapping on something in the right-hand area): • The original left-hand fragment (Fragment A) slid off the screen to the left 1757 ANIMATORS • The original right-hand fragment (Fragment B) slid to the left edge of the screen and shrunk to take up the spot vacated by Fragment A • Another fragment (Fragment C) slid in from the right side of the screen and expanded to take up the spot vacated by Fragment B And a BACK button press reversed this operation. This is a bit tricky to set up, leading to the author of this book posting a question on Stack Overflow to get input. Here, we will examine one of the results of that discussion, based in large part on the implementation of the AOSP Email app, which has a similar navigation flow. The other answers on that question may have merit in other scenarios as well. You can see one approach for implementing the three-pane solution in the Animation/ThreePane sample app. The ThreePaneLayout The logic to handle the animated effects is encapsulated in a ThreePaneLayout class. It is designed to be used in a layout XML resource where you supply the contents of the three panes, sizing the first two as you want, with the third “pane” having zero width at the outset: > /> />