Android
Android
#android
Table of Contents
About 1
Remarks 2
Versions 2
Examples 3
Change/add theme 4
Compiling Apps 4
Basic Configuration 4
Add an activity 9
Declaring a resource 19
See also 20
Application Fundamentals 20
App Components 20
Context 21
Remarks 28
Examples 28
Basic spinner 29
Examples 31
Inserting data 31
Updating data 31
Examples 32
Chapter 5: ACRA 35
Syntax 35
Parameters 35
Remarks 35
Examples 35
ACRAHandler 35
Example manifest 36
Installation 36
Chapter 6: Activity 37
Introduction 37
Syntax 37
Parameters 38
Remarks 38
Examples 38
Activity launchMode 42
Standard: 43
SingleTop: 43
SingleTask: 43
SingleInstance: 43
Examples 44
Introduction 48
Examples 48
Introduction 53
Remarks 53
Examples 53
Example Output 53
Rooted device 58
When you have a rooted device but don't have access to a USB cable 58
Avoid timeout 59
Reboot device 59
Connect device by IP 60
Start/stop adb 61
View logcat 61
Taking a screenshot and video (for kitkat only) from a device display 63
Video 64
Sending broadcast 64
Backup 66
List all permissions that require runtime grant from users on Android 6.0 67
Introduction 69
Syntax 69
Parameters 69
Examples 69
Send text, key pressed and touch events to Android Device via ADB 69
List packages 71
Introduction 77
Examples 77
Syntax 86
Parameters 86
Remarks 86
Examples 86
Implementing 86
Manifest 86
XML 87
Java 87
Introduction 89
Examples 89
AIDL Service 89
Examples 91
Introduction 94
Examples 94
Room peristence 96
Custom LiveData 98
Examples 101
Introduction 104
Remarks 104
Examples 104
Introduction 111
Examples 111
How to call functions in a native library via the JNI interface 111
Examples 114
Examples 118
Remarks 121
Examples 121
Examples 123
Introduction 129
Remarks 129
Examples 129
Examples 135
Examples 138
Examples 150
Remarks 152
Examples 153
Examples 155
Introduction 157
Examples 157
Introduction 164
Examples 164
Examples 167
ValueAnimator 169
ObjectAnimator 170
ViewPropertyAnimator 171
Introduction 173
Examples 173
Parameters 176
Examples 176
Example 176
Usage: 177
Note 177
Note 179
THREAD_POOL_EXECUTOR 185
SERIAL_EXECUTOR 185
Examples 188
Examples 189
Remarks 190
Examples 190
[Link] 191
[Link] 191
Introduction 195
Examples 195
Granularity 195
Remarks 197
Examples 197
Introduction 199
Syntax 199
Parameters 199
Examples 199
Remarks 201
Examples 201
Permissions 201
Introduction 210
Examples 210
Introduction 216
Remarks 216
Examples 216
Introduction 227
Remarks 227
Links: 227
Examples 227
Introduction 231
Examples 231
Examples 239
Introduction 242
Remarks 242
ButterKnife 242
Examples 242
Configuring ButterKnife in your project 242
Syntax 250
Examples 250
Using the same click event for one or more Views in the XML 251
Examples 258
Parameters 259
Remarks 259
Examples 260
Preview the main camera in a TextureView 260
Examples 269
[Link] 269
How to start camera or gallery and save camera result to storage 274
Decode bitmap correctly rotated from the uri fetched with the intent 277
Remarks 281
Examples 281
Examples 287
Introduction 290
Parameters 290
Remarks 291
Examples 291
Introduction 298
Syntax 298
Parameters 298
Remarks 298
Examples 298
Introduction 303
Remarks 303
Examples 303
Examples 304
Introduction 305
Syntax 305
Parameters 305
Remarks 306
Examples 306
Chains 307
Chapter 58: ConstraintSet 309
Introduction 309
Examples 309
Remarks 310
Examples 310
Introduction 314
Syntax 314
Remarks 314
Examples 314
Examples 316
example: 316
Introduction 317
Remarks 317
Examples 317
Parameters 321
Remarks 321
Examples 321
Remarks 324
Examples 324
Examples 333
Introduction 335
Syntax 335
Parameters 335
Remarks 335
Examples 336
Examples 338
[Link] 347
Examples 351
Remarks 353
Examples 353
Chapter 70: Creating your own libraries for Android applications 358
Examples 358
Examples 361
Syntax 366
Remarks 366
Examples 366
Remarks 373
Examples 373
Introduction 385
Examples 385
Examples 387
Examples 393
Examples 397
Chapter 78: Define step value (increment) for custom RangeSeekBar 399
Introduction 399
Remarks 399
Examples 400
Introduction 401
Examples 401
Examples 403
Installation 404
Examples 405
Parameters 406
Remarks 406
Examples 406
DatePickerDialog 409
DatePicker 410
Examples 417
Remarks 420
Examples 422
Examples 424
Examples 428
Icon or button inside Custom Edit Text and its action and click listeners. 433
Examples 436
Remarks 437
Examples 437
Introduction 443
Examples 443
Remarks 444
Examples 444
Examples 449
NetworkOnMainThreadException 449
ActivityNotFoundException 450
OutOfMemoryError 450
DexException 451
UncaughtException 451
Examples 454
Main steps to play video & audio using the standard TrackRenderer implementations 455
Syntax 456
Parameters 456
Examples 456
Introduction 462
Examples 462
Introduction 464
Syntax 464
Examples 464
Remarks 467
Examples 467
Fastfile lane to build and install all flavors for given build type to a device 469
Introduction 471
Remarks 471
Examples 471
Examples 475
Specify the directories in which the files you want to share are placed 475
Remarks 477
Examples 477
Introduction 488
Remarks 488
Firebase - Extended documentation: 488
Examples 488
Remarks 516
Examples 518
Introduction 522
Examples 522
This code that i have implemnted in my app for pushing image,message and also link for ope 523
Examples 526
Remarks 528
Examples 528
Designing and understanding how to retrieve realtime data from the Firebase Database 529
Example 532
Introduction 539
Parameters 539
Remarks 539
Examples 540
Introduction 547
Examples 547
Examples 548
Introduction 549
Syntax 549
Remarks 550
Constructor 550
Examples 550
Navigation between fragments using backstack and static fabric pattern 551
Example 553
Introduction 560
Remarks 560
Examples 560
Introduction 563
Examples 563
Remarks 565
Examples 565
Remarks 568
Examples 568
Introduction 570
Examples 570
Chapter 114: Getting system font names and using the fonts 573
Introduction 573
Examples 573
Remarks 574
Examples 574
ImageView 575
Remarks 581
Examples 581
Get changes for location within a certain range using Fence API 584
Introduction 586
Remarks 586
Examples 586
Parameters 600
Remarks 600
Examples 600
Do not launch Google Maps when the map is clicked (lite mode) 621
UISettings 621
Examples 626
Open Google Play Store with the list of all applications from your publisher account 626
Introduction 628
Examples 628
Introduction 630
Syntax 630
Remarks 630
Examples 631
Plugins 632
Dependencies 632
signingConfig 633
BuildConfigField 636
ResValue 637
Why are there two [Link] files in an Android Studio project? 640
Specifying different application IDs for build types and product flavors 642
Enable experimental NDK plugin support for Gradle and AndroidStudio 647
Introduction 656
Examples 656
Creating an Entity with GreenDAO 3.X that has a Composite Primary Key 658
Syntax 662
Parameters 662
Examples 662
Introduction 665
Syntax 665
Examples 666
Remarks 678
Examples 678
Introduction 682
Parameters 682
Remarks 682
Resources 683
Examples 683
Introduction 687
Parameters 687
Examples 687
Buttons 687
Surface 688
Introduction 691
Examples 691
PTT_KEY 691
YELLOW_KEY 691
SOS_KEY 691
GREEN_KEY 691
Examples 693
Introduction 697
Remarks 697
Examples 698
Syntax 700
Remarks 700
Examples 700
Usage 710
Examples 711
Introduction 714
Syntax 714
Parameters 714
Examples 714
[Link] 723
Syntax 725
Parameters 725
Remarks 725
Examples 725
Examples 727
Consumable In-app Purchases 727
Step 1: 727
Step 2: 727
Step 3: 727
Step 4: 727
Step 5: 728
Step 6: 731
Examples 734
Remarks 735
Examples 735
Syntax 739
Parameters 739
Examples 739
Remarks 742
Examples 742
Instructions 742
Introduction 751
Syntax 751
Parameters 752
Remarks 752
Examples 753
OriginActivity 753
DestinationActivity 754
MainActivity: 756
DetailActivity: 757
Parcelable 768
Serializable 770
Syntax 773
Remarks 773
Examples 773
Syntax 776
Remarks 776
Examples 776
Prepare your project and write the first UIAutomator test 776
Examples 779
Introduction 783
Remarks 783
Examples 783
Introduction 788
Examples 788
Introduction 790
Examples 790
Examples 793
Examples 794
Part III: Create a Jenkins Job for your Android project 795
Remarks 797
Examples 797
Syntax 800
Remarks 800
Examples 800
Examples 809
Hide keyboard when user taps anywhere else on the screen 809
Introduction 811
Syntax 811
Remarks 811
Performance impact from using RelativeLayouts near the top of your view hierarchy 812
Examples 813
LinearLayout 813
RelativeLayout 814
GridLayout 819
FrameLayout 822
CoordinatorLayout 823
LayoutParams 829
Introduction 833
Remarks 833
Examples 833
Introduction 834
Remarks 834
Examples 835
Remarks 837
Examples 837
Introduction 841
Remarks 841
Examples 841
Introduction 845
Parameters 845
Remarks 845
Examples 846
Reloading 848
Introduction 850
Syntax 850
Examples 850
Load the Image from Resource from Android Device. Using Intents. 850
Examples 853
Currency 853
Configuration types and qualifier names for each folder under the "res" directory 855
Exhaustive list of all different configuration types and their qualifier values for androi 855
Examples 863
Introduction 865
Remarks 865
LocationManager 865
FusedLocationProviderApi 866
TroubleShooting 868
Examples 875
Syntax 888
Parameters 888
Remarks 888
Definition 888
Examples 889
Logging 891
Performance: 893
Security: 893
Conclusion: 893
Introduction 899
Examples 899
Remarks 900
Examples 900
Introduction 902
Remarks 902
Examples 902
RippleDrawable 910
Syntax 923
Remarks 923
Examples 925
Syntax 932
Remarks 932
Examples 932
Examples 935
Fetch Audio/MP3 files from specific folder of device or fetch all files 935
Avoid memory leaks with Anonymous Class, Handler, Timer Task, Thread 948
Syntax 950
Parameters 950
Remarks 950
Examples 950
Step 1: 951
Step 2: 952
Introduction 955
Remarks 955
Examples 955
JSON into Java 955
Introduction 957
Remarks 957
Examples 958
Introduction 962
Remarks 962
Examples 962
Notes: 966
[Link] 970
[Link] 970
[Link] 971
[Link] 972
MVP 972
Remarks 974
Examples 975
Remarks 983
Examples 983
Introduction 992
Syntax 992
Parameters 992
Examples 992
Examples 998
Here is what it looks like on Android Marshmallow with the Heads Up Notification: 999
Here is what it looks like on Android KitKat with the Ticker: 1000
Dynamically getting the correct pixel size for the large icon 1006
Examples 1008
Examples 1012
Introduction 1014
Examples 1014
Remarks 1026
Examples 1026
Problem: 1030
Solution: 1030
Example: 1030
MainActivity: 1030
AsyncTaskLoader: 1031
Note: 1031
Examples 1033
Remarks 1038
Examples 1038
Examples 1040
Retrieve application version 1040
Introduction 1043
Examples 1043
[Link] 1043
Introduction 1048
Examples 1048
Introduction 1051
Remarks 1051
Examples 1051
Introduction 1055
Examples 1055
Introduction 1056
Remarks 1056
Examples 1056
Adding Picasso Library to your Android Project 1056
Gradle. 1056
Maven: 1056
Try offline disk cache first, then go online and fetch the image 1062
Introduction 1064
Examples 1064
Examples 1065
Introduction 1067
Remarks 1067
Examples 1068
Remarks 1070
Examples 1070
Indeterminate 1077
Determinate 1077
Buffer 1078
Examples 1081
Introduction 1087
Parameters 1087
Remarks 1087
Examples 1087
Chapter 196: Publish .aar file to Apache Archiva with Gradle 1089
Examples 1089
Examples 1091
Examples 1093
Introduction 1095
Remarks 1095
Examples 1095
try-with-resources 1098
Models 1101
Introduction 1104
Parameters 1104
Remarks 1104
Examples 1105
Show default view till items load or when data is not available 1121
Examples 1126
Connect the RecyclerView with the PlaceListAdapter and the dataset 1133
Done! 1134
StaggeredGridLayoutManager 1134
Syntax 1137
Parameters 1137
Remarks 1137
Examples 1137
Examples 1144
Introduction 1155
Examples 1155
Kernels 1158
Basics 1160
Conclusion 1163
Blur an image 1163
[Link] 1165
Usage: 1167
Examples 1168
9 Patches 1179
Introduction 1186
Remarks 1186
Examples 1186
Examples 1204
Examples 1209
Introduction 1213
Examples 1213
Configuration 1213
Introduction 1215
Remarks 1215
Examples 1216
Android 6.0 multiple permissions 1216
Include all permission-related code to an abstract base class and extend the activity of t 1221
Examples 1224
Introduction 1230
Syntax 1230
Parameters 1230
Remarks 1230
Examples 1230
Introduction 1232
Syntax 1232
Parameters 1232
Remarks 1232
Examples 1232
Examples 1234
Examples 1235
Introduction 1238
Remarks 1238
Examples 1238
Introduction 1246
Syntax 1246
Examples 1246
Introduction 1249
Syntax 1249
Parameters 1250
Remarks 1250
Examples 1250
Examples 1265
Introduction 1266
Examples 1266
Examples 1269
Syntax 1272
Parameters 1272
Remarks 1272
Examples 1272
Syntax 1277
Examples 1277
Examples 1282
Examples 1285
Examples 1288
Introduction 1290
Remarks 1290
Examples 1290
Syntax 1307
Parameters 1307
Examples 1307
Using Internal Storage 1307
Chapter 229: Strict Mode Policy : A tool to catch the bug in the Compile Time. 1317
Introduction 1317
Remarks 1317
Examples 1317
The below Code Snippet is to setup the StrictMode for Thread Policies. This Code is to be 1317
The below code deals with leaks of memory, like it detects when in SQLLite finalize is cal 1317
Remarks 1318
Orientation 1318
Units 1318
px 1319
in 1319
mm 1319
pt 1319
dp or dip 1319
sp 1319
Examples 1320
Syntax 1323
Examples 1323
Introduction 1325
Examples 1325
Sync adapter with every min requesting value from server. 1325
Examples 1335
Introduction 1336
Remarks 1336
Examples 1336
Remarks 1338
Espresso 1338
Troubleshooting 1338
Examples 1338
Up Navigation 1345
Examples 1351
Introduction 1356
Remarks 1356
Examples 1356
TextInputEditText 1358
Introduction 1360
Syntax 1360
Remarks 1360
Examples 1360
Introduction 1373
Examples 1373
Examples 1375
Examples 1381
Examples 1383
GetCurrentRealTime 1384
Introduction 1386
Syntax 1386
Parameters 1386
Remarks 1386
Examples 1387
Remarks 1391
Examples 1391
Examples 1393
How to vary between child and parent view group touch events 1393
Examples 1397
Step 2: Add code for ImageView in your XML layout to display the above drawable. 1397
Step 3: Access the XML transition drawable in onCreate() method of your Activity and start 1397
Examples 1399
Remarks 1401
Examples 1401
Examples 1403
Remarks 1404
Examples 1404
Breakdown 1404
Setup 1408
Exceptions 1411
Remarks 1414
Examples 1414
Examples 1416
Introduction 1417
Parameters 1417
Remarks 1417
Examples 1418
VectorDrawable Usage Example 1418
Examples 1422
Using 1422
tags 1423
Examples 1429
Examples 1431
Introduction 1433
Examples 1433
Introduction 1435
Remarks 1435
Examples 1435
selected_dot.xml 1442
default_dot.xml 1442
tab_selector.xml 1443
Introduction 1445
Syntax 1445
Remarks 1445
Installation 1445
Examples 1446
Adding custom headers to your requests [e.g. for basic auth] 1448
Boolean variable response from server with json request in volley 1454
Introduction 1457
Remarks 1457
Examples 1457
Introduction 1462
Examples 1462
Remarks 1464
Examples 1464
Metadata 1464
Right on your Application ==> New ==> Widget ==> App Widget 1466
Examples 1468
Introduction 1472
Syntax 1472
Remarks 1472
Appium 1472
Parameters 1472
Examples 1473
IdlingResource 1475
Implementation 1475
NOTES 1476
Example 1476
Usage 1477
Chapter 265: XMPP register login and chat simple example 1479
Examples 1479
Examples 1488
Remarks 1491
Examples 1491
Examples 1501
Credits 1503
About
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: android
It is an unofficial and free Android ebook created for educational purposes. All the content is
extracted from Stack Overflow Documentation, which is written by many hardworking individuals at
Stack Overflow. It is neither affiliated with Stack Overflow nor official Android.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to info@[Link]
[Link] 1
Chapter 1: Getting started with Android
Remarks
If you want to learn more about the Android Gradle Plugin setting check out the android-gradle
Documentation.
If you are interested in alternative emulators, you could look at Genymotion. It provides a free plan
and requires smaller amount of RAM.
Versions
[Link] 2
Version API Level Version Code Release Date
Examples
Setting up Android Studio
Android Studio is the Android development IDE that is officially supported and recommended by
Google. Android Studio comes bundled with the Android SDK Manager, which is a tool to
download the Android SDK components required to start developing apps.
If you need to work on old projects that were built using older SDK versions, you may
need to download these versions as well
Since Android Studio 2.2, a copy of the latest OpenJDK comes bundled with the install and is the
recommended JDK (Java Development Kit) for all Android Studio projects. This removes the
requirement of having Oracle's JDK package installed. To use the bundled SDK, proceed as
follows;
1. Open your project in Android Studio and select File > Project Structure in the menu bar.
2. In the SDK Location page and under JDK location, check the Use embedded JDK
checkbox.
3. Click OK.
[Link] 3
Configure Android Studio
Android Studio provides access to two configuration files through the Help menu:
• [Link]: Customize options for Studio's Java Virtual Machine (JVM), such as heap
size and cache size. Note that on Linux machines this file may be named
[Link], depending on your version of Android Studio.
• [Link]: Customize Android Studio properties, such as the plugins folder path or
maximum supported file size.
Change/add theme
You can change it as your [Link]->Settings->Editor->Colors & Fonts-> and select a
[Link] you can download new themes from [Link] Once you have
downloaded the .[Link] file, go to File -> Import Settings... and choose the file downloaded.
Compiling Apps
Create a new project or open an existing project in Android Studio and press the green Play button
on the top toolbar to run it. If it is gray you need to wait a second to allow Android Studio to
properly index some files, the progress of which can be seen in the bottom status bar.
If you want to create a project from the shell make sure that you have a [Link] file,
which is created by Android Studio automatically. If you need to create the project without Android
Studio you need a line starting with [Link]= followed by the path to your SDK installation.
Open a shell and go into the project's directory. Enter ./gradlew aR and press enter. aR is a shortcut
for assembleRelease, which will download all dependencies for you and build the app. The final APK
file will be in ProjectName/ModuleName/build/outputs/apk and will been called [Link].
Note: this guide is based on Android Studio 2.2, but the process on other versions is
mainly the same.
[Link] 4
You can start a new project in two ways:
• Click Start a New Android Studio Project from the welcome screen.
• Navigate to File → New Project if you already have a project open.
Next, you need to describe your application by filling out some fields:
Example: Hello World. You can always change it later in [Link] file.
2. Company Domain - This is the qualifier for your project's package name.
Example: [Link].
3. Package Name (aka applicationId) - This is the fully qualified project package name.
It should follow Reverse Domain Name Notation (aka Reverse DNS): Top Level Domain .
Company Domain . [Company Segment .] Application Name.
Don't use the default prefix "[Link]" unless you don't intend to submit your
application to the Google Play Store. The package name will be your unique
applicationId in Google Play.
4. Project Location - This is the directory where your project will be stored.
[Link] 5
[Link] 6
Chart of the current Android version distributions, shown when you click Help me choose.
The Android Platform Distribution window shows the distribution of mobile devices running each
version of Android, as shown in Figure 2. Click on an API level to see a list of features introduced
in the corresponding version of Android. This helps you choose the minimum API Level that has all
the features that your apps needs, so you can reach as many devices as possible. Then click OK.
Now, choose what platforms and version of Android SDK the application will support.
[Link] 7
[Link] 8
uses to determine which devices an app can be installed on. For example, Stack Exchange's app
supports Android 4.1+.
Android Studio will tell you (approximately) what percentage of devices will be supported given the
specified minimum SDK.
Lower API levels target more devices but have fewer features available.
When deciding on the Minimum SDK, you should consider the Dashboards stats, which will give
you version information about the devices that visited the Google Play Store globally in the last
week.
Add an activity
Now we are going to select a default activity for our application. In Android, an Activity is a single
screen that will be presented to the user. An application can house multiple activities and navigate
between them. For this example, choose Empty Activity and click next.
Here, if you wish, you can change the name of the activity and layout. A good practice is to keep
Activity as a suffix for the activity name, and activity_ as a prefix for the layout name. If we leave
[Link] 9
these as the default, Android Studio will generate an activity for us called MainActivity, and a
layout file called activity_main. Now click Finish.
Android Studio will create and configure our project, which can take some time depending on the
system.
On the left pane of Android Studio, we can see the structure of our Android application.
First, let's open [Link] by double clicking it. The Android manifest file describes some
of the basic information about an Android application. It contains the declaration of our activities,
as well as some more advanced components.
[Link] 10
permissions defined by Android (listed in [Link]) or declared by other
applications. Or it can define its own.
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="[Link]" />
Next, let's open activity_main.xml which is located in app/src/main/res/layout/. This file contains
declarations for the visual components of our MainActivity. You will see visual designer. This
allows you to drag and drop elements onto the selected layout.
You can also switch to the xml layout designer by clicking "Text" at the bottom of Android Studio,
as seen here:
[Link] 11
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="[Link]">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</RelativeLayout>
You will see a widget called a TextView inside of this layout, with the android:text property set to
"Hello World!". This is a block of text that will be shown to the user when they run the application.
Next, let's take a look at MainActivity. This is the Java code that has been generated for
MainActivity.
As defined in our Android manifest, MainActivity will launch by default when a user starts the
HelloWorld app.
android {
signingConfigs {
applicationName {
keyAlias 'applicationName'
keyPassword 'password'
storeFile file('../key/[Link]')
storePassword 'anotherPassword'
}
}
compileSdkVersion 26
buildToolsVersion "26.0.0"
[Link] 12
defaultConfig {
applicationId "[Link]"
minSdkVersion 16
targetSdkVersion 26
versionCode 1
versionName "1.0"
signingConfig [Link]
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('[Link]'), '[Link]'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile '[Link]:appcompat-v7:26.0.0'
}
This file contains information about the build and your app version, and you can also use it to add
dependencies to external libraries. For now, let's not make any changes.
It is advisable to always select the latest version available for the dependencies:
• buildToolsVersion: 26.0.0
• [Link]:appcompat-v7: 26.0.0 (July 2017)
• firebase: 11.0.4 (August 2017)
compileSdkVersion
compileSdkVersion is your way to tell Gradle what version of the Android SDK to compile your app
with. Using the new Android SDK is a requirement to use any of the new APIs added in that level.
It should be emphasized that changing your compileSdkVersion does not change runtime behavior.
While new compiler warnings/errors may be present when changing your compileSdkVersion, your
compileSdkVersion is not included in your APK: it is purely used at compile time.
Therefore it is strongly recommended that you always compile with the latest SDK. You’ll get all
the benefits of new compilation checks on existing code, avoid newly deprecated APIs, and be
ready to use new APIs.
minSdkVersion
If compileSdkVersion sets the newest APIs available to you, minSdkVersion is the lower bound for
your app. The minSdkVersion is one of the signals the Google Play Store uses to determine which
of a user’s devices an app can be installed on.
It also plays an important role during development: by default lint runs against your project,
warning you when you use any APIs above your minSdkVersion, helping you avoid the runtime
issue of attempting to call an API that doesn’t exist. Checking the system version at runtime is a
[Link] 13
common technique when using APIs only on newer platform versions.
targetSdkVersion
targetSdkVersionis the main way Android provides forward compatibility by not applying behavior
changes unless the targetSdkVersion is updated. This allows you to use new APIs prior to working
through the behavior changes. Updating to target the latest SDK should be a high priority for every
app. That doesn’t mean you have to use every new feature introduced nor should you blindly
update your targetSdkVersion without testing.
targetSDKVersion is the version of Android which is the upper-limit for the available tools. If
targetSDKVersion is less than 23, the app does not need to request permissions at runtime for an
instance, even if the app is being run on API 23+. TargetSDKVersion does not prevent android
versions above the picked Android version from running the app.
• A basic example
• Introduction to the Gradle plugin for android and the wrapper
• Introduction to the configuration of the [Link] and the DSL methods
If Developer Options is not visible in the settings, navigate to About Phone and tap on the Build
Number seven times. This will enable Developer Options to show up in your settings.
You also might need to change [Link] configuration to build on a version that your device
has.
[Link] 14
click OK.
On devices running Android 4.4 (KitKat) and possibly higher, a pop-up will be shown to authorize
USB debugging. Click OK to accept.
The application will now install and run on your Android device or emulator.
Android Studio
Since in the above examples Gradle is used, the location of the generated APK file is: <Your
Project Location>/app/build/outputs/apk/[Link]
IntelliJ
If you are a user of IntelliJ before switching to Studio, and are importing your IntelliJ project
directly, then nothing changed. The location of the output will be the same under:
out/production/...
Eclipse
If you are importing Android Eclipse project directly, do not do this! As soon as you have
dependencies in your project (jars or Library Projects), this will not work and your project will not
be properly setup. If you have no dependencies, then the apk would be under the same location
as you'd find it in Eclipse:
bin/...
[Link] 15
This is a minimalist Hello World example that uses only the most basic Android tools.
This example assumes Linux. You may have to adjust the syntax for your own platform.
1. Install additional packages using the SDK manager. Don't use android update sdk --no-ui as
instructed in the bundled [Link]; it downloads some 30 GB of unnecessary files.
Instead use the interactive SDK manager android sdk to get the recommended minimum of
packages.
2. Append the following JDK and SDK directories to your execution PATH. This is optional, but
the instructions below assume it.
• JDK/bin
• SDK/platform-tools
• SDK/tools
• SDK/build-tools/LATEST (as installed in step 1)
3. Create an Android virtual device. Use the interactive AVD Manager (android avd). You might
have to fiddle a bit and search for advice; the on-site instructions aren't always helpful.
[Link] 16
mkdir --parents src/dom/domain
touch src/dom/domain/[Link]
Content:
package [Link];
import [Link];
8. Add a manifest:
touch [Link]
Content:
<?xml version='1.0'?>
<manifest xmlns:a='[Link]
package='[Link]' a:versionCode='0' a:versionName='0'>
<application a:label='Saying hello'>
<activity a:name='[Link]'>
<intent-filter>
<category a:name='[Link]'/>
<action a:name='[Link]'/>
</intent-filter>
</activity>
</application>
</manifest>
mkdir res
aapt package -f \
-I SDK/platforms/android-API/[Link] \
[Link] 17
-J src -m \
-M [Link] -S res -v
Resource declarations (described further below) are actually optional. Meantime the above
call does nothing if res/ is still empty.
javac \
-bootclasspath SDK/platforms/android-API/[Link] \
-classpath src -source 1.7 -target 1.7 \
src/dom/domain/*.java
You could replace steps 11 and 12 with a single call to Jack if you like; it can compile directly
from Java source (.java → .dex). But there are advantages to compiling with javac. It's a
better known, better documented and more widely applicable tool.
aapt package -f \
-F [Link] \
-I SDK/platforms/android-API/[Link] \
-M [Link] -S res -v
It warns, "THIS TOOL IS DEPRECATED. See --help for more information." If --help fails with
an ArrayIndexOutOfBoundsException, then instead pass no arguments:
[Link] 18
java -classpath SDK/tools/lib/[Link] \
[Link]
It explains that the CLI (ApkBuilderMain) is deprecated in favour of directly calling the Java
API (ApkBuilder). (If you know how to do that from the command line, please update this
example.)
That's all. That's what it takes to say hello using the basic Android tools.
Declaring a resource
This section is optional. Resource declarations aren't required for a simple "hello world" app. If
they aren't required for your app either, then you could streamline the build somewhat by omitting
step 10, and removing the reference to the res/ directory from step 13.
Otherwise, here's a brief example of how to declare a resource, and how to reference it.
mkdir res/values
touch res/values/[Link]
Content:
<?xml version='1.0'?>
<resources>
<string name='appLabel'>Saying hello</string>
</resources>
19. Reference the resource from the XML manifest. This is a declarative style of reference:
[Link] 19
<!-- <application a:label='Saying hello'> -->
<application a:label='@string/appLabel'>
20. Reference the same resource from the Java source. This is an imperative reference:
21. Test the above modifications by rebuilding, reinstalling and re-running the app (steps 10-17).
See also
• original question - The original question that prompted this example
• working example - A working build script that uses the above commands
Application Fundamentals
Android Apps are written in Java. The Android SDK tools compile the code, data and resource
files into an APK (Android package). Generally, one APK file contains all the content of the app.
Each app runs on its own virtual machine(VM) so that app can run isolated from other apps.
Android system works with the principle of least privilege. Each app only has access to the
components which it requires to do its work, and no more. However, there are ways for an app to
share data with other apps, such as by sharing Linux user id between app, or apps can request
permission to access device data like SD card, contacts etc.
App Components
App components are the building blocks of an Android app. Each components plays a specific role
in an Android app which serves a distinct purpose and has distinct life-cycles(the flow of how and
when the component is created and destroyed). Here are the four types of app components:
1. Activities: An activity represents a single screen with a User Interface(UI). An Android app
may have more than one activity. (e.g. an email app might have one activity to list all the
emails, another to show the contents of each email, and another to compose new email.) All
the activities in an App work together to create a User eXperience (UX).
2. Services: A service runs in the background to perform long-running operations or to perform
work for a remote processes. A service does not provide any UI, it runs only in the
[Link] 20
background with the User's input. (e.g. a service can play music in the background while the
user is in a different App, or it might download data from the internet without blocking user's
interaction with the Android device.)
3. Content Providers: A content provider manages shared app data. There are four ways to
store data in an app: it can be written to a file and stored in the file system, inserted or
updated to a SQLite database, posted to the web, or saved in any other persistent storage
location the App can access. Through content providers, other Apps can query or even
modify the data. (e.g. Android system provides a content provider that manages the user's
contact information so that any app which has permission can query the contacts.) Content
providers can also be used to save the data which is private to the app for better data
integrity.
4. Broadcast receivers: A broadcast receiver responds to the system-wide broadcasts of
announcements (e.g. a broadcast announcing that the screen has turned off, the battery is
low, etc.) or from Apps (e.g. to let other apps know that some data has been downloaded to
the device and is available for them to use). Broadcast receivers don't have UIs but they can
show notification in the status bar to alert the user. Usually broadcast receivers are used as
a gateway to other components of the app, consisting mostly of activities and services.
One unique aspect of the Android system is that any app can start another app's component (e.g.
if you want to make call, send SMS, open a web page, or view a photo, there is an app which
already does that and your app can make use of it, instead of developing a new activity for the
same task).
When the system starts a component, it starts the process for that app (if it isn't already running,
i.e. only one foreground process per app can run at any given time on an Android system) and
instantiates the classes needed for that component. Thus the component runs on the process of
that App that it belongs to. Therefore, unlike apps on other systems, Android apps don't have a
single entry point(there is no main() method).
Because the system runs each app in a separate process, one app cannot directly activate
another app's components, however the Android system can. Thus to start another app's
component, one app must send a message to the system that specifies an intent to start that
component, then the system will start that component.
Context
Instances of the class [Link] provide the connection to the Android system which
executes the application. Instance of Context is required to get access to the resources of the
project and the global information about the app's environment.
Let's have an easy to digest example: Consider you are in a hotel, and you want to eat something.
You call room-service and ask them to bring you things or clean up things for you. Now think of
this hotel as an Android app, yourself as an activity, and the room-service person is then your
context, which provides you access to the hotel resources like room-service, food items etc.
Yet an other example, You are in a restaurant sitting on a table, each table has an attendant,
when ever you want to order food items you ask the attendant to do so. The attendant then places
[Link] 21
your order and your food items gets served on your table. Again in this example, the restaurant is
an Android App, the tables or the customers are App components, the food items are your App
resources and the attendant is your context thus giving you a way to access the resources like
food items.
Activating any of the above components requires the context's instance. Not just only the above,
but almost every system resource: creation of the UI using views(discussed later), creating
instance of system services, starting new activities or services -- all require context.
TL;DR It basically allows us to simulate real devices and test our apps without a real device.
an Android Virtual Device (AVD) definition lets you define the characteristics of an
Android Phone, Tablet, Android Wear, or Android TV device that you want to simulate
in the Android Emulator. The AVD Manager helps you easily create and manage
AVDs.
[Link] 22
3. Now click the + Create Virtual Device... button. This will bring up Virtual Device Configuration
Dialog:
[Link] 23
4. Select any device you want, then click Next:
[Link] 24
5. Here you need to choose an Android version for your emulator. You might also need to
download it first by clicking Download. After you've chosen a version, click Next.
[Link] 25
6. Here, enter a name for your emulator, initial orientation, and whether you want to display a
frame around it. After you chosen all these, click Finish.
7. Now you got a new AVD ready for launching your apps on it.
[Link] 26
Read Getting started with Android online: [Link]
with-android
[Link] 27
Chapter 2: 9-Patch Images
Remarks
A 9-patch image file is a specially formatted file so that Android knows which areas/portions of the
image can or cannot be scaled. It breaks your image into a 3x3 grid. The corners remain unscaled,
the sides are scaled in one direction and the center is scaled in both dimensions.
A Nine Patch (9-Patch) image is a bitmap that has a single pixel wide border around the entire
image. Ignoring the 4 pixels in the corners of the image. This border provides metadata for the
bitmap itself. Bounds are marked by solid black line(s).
The top border indicates areas that stretch horizontally. The left border indicates areas that stretch
vertically.
The bottom border indicates padding horizontally. The right border indicates padding vertically.
The padding borders are usually used to determine where text is to be drawn.
There is an excellent tool provided by Google that greatly simplifies the creation of these files.
Examples
Basic rounded corners
The top border controls horizontal stretching and the left border controls vertical stretching.
[Link] 28
The parts of the image that are below the top border and to the right of the left border will expand
to fill all unused space.
Basic spinner
The Spinner can be reskinned according to your own style requirements using a Nine Patch.
The top border has only left of the icon marked. That indicates that I want the left side (complete
transparency) of the drawable to fill the Spinner view until the icon is reached.
The left border has marked transparent segments at the top and bottom of the icon marked. That
indicates that both the top and the bottom will expand to the size of the Spinner view. This will
leave the icon itself centered vertically.
[Link] 29
Nine-patch images allow optional definition of the padding lines in the image. The padding lines
are the lines on the right and at the bottom.
If a View sets the 9-patch image as its background, the padding lines are used to define the space
for the View's content (e.g. the text input in an EditText). If the padding lines are not defined, the
left and top lines are used instead.
The content area of the stretched image then looks like this:
[Link] 30
Chapter 3: Accessing SQLite databases
using the ContentValues class
Examples
Inserting and updating rows in a SQLite database
First, you need to open your SQLite database, which can be done as follows:
SQLiteDatabase myDataBase;
String mPath = dbhelper.DATABASE_PATH + dbhelper.DATABASE_NAME;
myDataBase = [Link](mPath, null, SQLiteDatabase.OPEN_READWRITE);
After opening the database, you can easily insert or update rows by using the ContentValues class.
The following examples assume that a first name is given by str_edtfname and a last nameby
str_edtlname. You also need to replace table_name by the name of your table that you want to
modify.
Inserting data
ContentValues values = new ContentValues();
[Link]("First_Name", str_edtfname);
[Link]("Last_Name", str_edtlname);
[Link]("table_name", null, values);
Updating data
ContentValues values = new ContentValues();
[Link]("First_Name", str_edtfname);
[Link]("Last_Name", str_edtlname);
[Link]("table_name", values, "id" + " = ?", new String[] {id});
[Link] 31
Chapter 4: Accounts and AccountManager
Examples
Understanding custom accounts/authentication
The following example is high level coverage of the key concepts and basic skeletal setup:-
1. Collects credentials from the user (Usually from a login screen you've created)
2. Authenticates the credentials with the server (stores custom authentication)
3. Stores the credentials on the device
@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
String authTokenType, String[] requiredFeatures, Bundle options) {
//intent to start the login activity
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,
Bundle options) {
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String
authTokenType,
Bundle options) throws NetworkErrorException {
//retrieve authentication tokens from account manager storage or custom storage or re-
authenticate old tokens and return new ones
}
@Override
public String getAuthTokenLabel(String authTokenType) {
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[]
features)
throws NetworkErrorException {
//check whether the account supports certain features
}
[Link] 32
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
String authTokenType,
Bundle options) {
//when the user's session has expired or requires their previously available credentials
to be updated, here is the function to do it.
}
}
@Override
public void onCreate(){
authenticator = new AccountAuthenticator(this);
}
@Override
public IBinder onBind(Intent intent) {
return [Link]();
}
}
Authenticator XML configuration (The account manager framework requires. This is what you'll
see inside Settings -> Accounts in Android)
<account-authenticator xmlns:android="[Link]
android:accountType="[Link]"
android:icon="@drawable/app_icon"
android:label="@string/app_name"
android:smallIcon="@drawable/app_icon" />
Changes to the [Link] (Bring all the above concepts together to make it usable
programmatically through the AccountManager)
<application
...>
<service
android:name=".[Link]"
android:exported="false"
android:process=":authentication">
<intent-filter>
<action android:name="[Link]"/>
</intent-filter>
<meta-data
[Link] 33
android:name="[Link]"
android:resource="@xml/authenticator"/>
</service>
</application>
The next example will contain how to make use of this setup.
[Link] 34
Chapter 5: ACRA
Syntax
• android:name=".ACRAHandler"
• [Link](this, config);
• public class ACRAHandler extends Application {
Parameters
Parameter Description
Remarks
• ACRA no longer supports Google forms, so you need a backend:
[Link]
Examples
ACRAHandler
@ReportsCrashes(
)
public class ACRAHandler extends Application {
@Override
protected void attachBaseContext(Context base) {
[Link](base);
.build();
// Initialise ACRA
[Link] 35
[Link](this, config);
Example manifest
>
<!-- Internet is required. READ_LOGS are to ensure that the Logcat is transmitted-->
<uses-permission android:name="[Link]"/>
<uses-permission android:name="[Link].READ_LOGS"/>
<application
android:allowBackup="true"
android:name=".ACRAHandler"<!-- Activates ACRA on startup -->
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
</manifest>
Installation
Maven
<dependency>
<groupId>[Link]</groupId>
<artifactId>acra</artifactId>
<version>4.9.2</version>
<type>aar</type>
</dependency>
Gradle
compile '[Link]:acra:4.9.2'
[Link] 36
Chapter 6: Activity
Introduction
An Activity represents a single screen with a user interface(UI). An Android App may have more
than one Activity, for example, An email App can have one activity to list all the emails, another
activity to show email contents, yet another activity to compose new email. All the activities in an
App work together to create perfect user experience.
Syntax
• void onCreate(Bundle savedInstanceState) // Called when the activity is starting.
• void onStart() // Called after onCreate(Bundle) — or after onRestart() when the activity had
been stopped, but is now again being displayed to the user.
• void onPostResume() // Called when activity resume is complete (after onResume() has
been called).
• void onRestart() // Called after onStop() when the current activity is being re-displayed to the
user (the user has navigated back to it).
• void onPause() // Called as part of the activity lifecycle when an activity is going into the
background, but has not (yet) been killed.
• void onStop() // Called when you are no longer visible to the user.
• void onNewIntent(Intent intent) // This is called for activities that set launchMode to
"singleTop" in their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag
when calling startActivity(Intent).
[Link] 37
Parameters
Parameter Details
Remarks
An Activity is an application component that provides a screen with which users can interact in
order to do something, such as dial the phone, take a photo, send an email, or view a map. Each
activity is given a window in which to draw its user interface. The window typically fills the screen,
but may be smaller than the screen and float on top of other windows.
Examples
Exclude an activity from back-stack history
Let there be Activity B that can be opened, and can further start more Activities. But, user should
not encounter it when navigating back in task activities.
[Link] 38
The simplest solution is to set the attribute noHistory to true for that <activity> tag in
[Link]:
<activity
android:name=".B"
android:noHistory="true">
This same behavior is also possible from code if B calls finish() before starting the next activity:
finish();
startActivity(new Intent(context, [Link]));
Assume an application with a MainActivity which can call the Next Activity using a button click.
[Link] 39
public class MainActivity extends AppCompatActivity {
@Override
protected void onPause() {
[Link]();
Log.d(LOG_TAG, "calling onPause from MainActivity");
}
@Override
protected void onStop() {
[Link]();
Log.d(LOG_TAG, "calling onStop from MainActivity");
}
@Override
protected void onDestroy() {
[Link]();
Log.d(LOG_TAG, "calling onDestroy from MainActivity");
}
@Override
protected void onRestart() {
[Link]();
Log.d(LOG_TAG, "calling onRestart from MainActivity");
}
public void toNextActivity(){
Log.d(LOG_TAG, "calling Next Activity");
Intent intent = new Intent(this, [Link]);
startActivity(intent);
} }
and
[Link] 40
protected void onStart() {
[Link]();
Log.d(LOG_TAG, "calling onStart from Next Activity");
}
@Override
protected void onResume() {
[Link]();
Log.d(LOG_TAG, "calling onResume from Next Activity");
}
@Override
protected void onPause() {
[Link]();
Log.d(LOG_TAG, "calling onPause from Next Activity");
}
@Override
protected void onStop() {
[Link]();
Log.d(LOG_TAG, "calling onStop from Next Activity");
}
@Override
protected void onDestroy() {
[Link]();
Log.d(LOG_TAG, "calling onDestroy from Next Activity");
}
@Override
protected void onRestart() {
[Link]();
Log.d(LOG_TAG, "calling onRestart from Next Activity");
} }
[Link] 41
D/MainActivity: calling onStop from MainActivity
When Returning back to the Main Activity from Next Activity using back button
D/NextActivity: calling onPause from Next Activity
D/MainActivity: calling onRestart from MainActivity
D/MainActivity: calling onStart from MainActivity
D/MainActivity: calling onResume from MainActivity
D/NextActivity: calling onStop from Next Activity
D/NextActivity: calling onDestroy from Next Activity
Case2: When Activity is partially obscured (When overview button is pressed) or When app goes
to background and another app completely obscures it
D/MainActivity: calling onPause from MainActivity
D/MainActivity: calling onStop from MainActivity
and when the app is back in the foreground ready to accept User inputs,
D/MainActivity: calling onRestart from MainActivity
D/MainActivity: calling onStart from MainActivity
D/MainActivity: calling onResume from MainActivity
are called
Case3: When an activity is called to fulfill implicit intent and user has make a selection. For eg.,
when share button is pressed and user has to select an app from the list of applications shown
D/MainActivity: calling onPause from MainActivity
The activity is visible but not active now. When the selection is done and app is active
D/MainActivity: calling onResume from MainActivity
is called
Case4:
When the app is killed in the background(to free resources for another foreground app), onPause
(for pre-honeycomb device) or onStop(for since honeycomb device) will be the last to be called
before the app is terminated.
onCreate and onDestroy will be called utmost once each time the application is run. But the
onPause, onStop, onRestart, onStart, onResume maybe called many times during the lifecycle.
Activity launchMode
Launch mode defines the behaviour of new or existing activity in the task.
There are possible launch modes:
• standard
• singleTop
• singleTask
• singleInstance
[Link] 42
<activity
android:launchMode=["standard" | "singleTop" | "singleTask" | "singleInstance"] />
Standard:
Default value. If this mode set, new activity will always be created for each new intent. So it's
possible to get many activities of same type. New activity will be placed on the top of the task.
There is some difference for different android version: if activity is starting from another
application, on androids <= 4.4 it will be placed on same task as starter application, but on >= 5.0
new task will be created.
SingleTop:
This mode is almost the same as standard. Many instances of singleTop activity could be created.
The difference is, if an instance of activity already exists on the top of the current stack,
onNewIntent() will be called instead of creating new instance.
SingleTask:
Activity with this launch mode can have only one instance in the system. New task for activity will
be created, if it doesn't exist. Otherwise, task with activity will be moved to front and onNewIntent
will be called.
SingleInstance:
This mode is similar to singleTask. The difference is task that holds an activity with singleInstance
could have only this activity and nothing more. When singleInstance activity create another
activity, new task will be created to place that activity.
Activity class takes care of creating a window for you in which you can place your UI with
setContentView.
There are three setContentView methods:
When setContentView is called, this view is placed directly into the activity's view hierarchy. It can
[Link] 43
itself be a complex view hierarchy.
Examples
Set content from resource file:
Add resource file ([Link] in this example) with view hierarchy:
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello" />
</FrameLayout>
@Override
public void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
@Override
public void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
[Link] 44
Clear your current Activity stack and launch a new Activity
If you want to clear your current Activity stack and launch a new Activity (for example, logging out
of the app and launching a log in Activity), there appears to be two approaches.
<activity
android:name="com.your_example_app.[Link]"
android:autoRemoveFromRecents="true"
android:theme="@android:style/[Link]" />
/**
* Activity to exit Application without staying in the stack of last opened applications
*/
public class ExitActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
if ([Link]()) {
finishAndRemoveTask();
} else if ([Link]()) {
finishAffinity();
} else {
finish();
}
}
/**
* Exit Application and Exclude from Recents
*
* @param context Context to use
*/
public static void exitApplication(ApplicationContext context) {
Intent intent = new Intent(context, [Link]);
[Link](Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
[Link](intent);
[Link] 45
}
}
How is it done?
<application
android:name=".SkillSchoolApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".[Link]"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="[Link]" />
Now when i will click on the arrow inside the toolbar of HomeActivity it will take me back to the
parent activity.
Java Code
Here i will write the appropriate java code required for this functionality.
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_home);
[Link](this);
//Since i am using custom tool bar i am setting refernce of that toolbar to Actionbar.
If you are not using custom then you can simple leave this and move to next line
setSupportActionBar(toolbar);
[Link](true); // this will show the back arrow
in the tool bar.
}
[Link] 46
}
If you run this code you will see when you press back button it will take you back to MainActivity.
For futher understanding of Up Navigation i would recommend reading docs
You can more customize this behaviour upon your needs by overriding
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch ([Link]()) {
// Respond to the action bar's Up/Home button
case [Link]:
[Link](this); // Here you will write your logic for handling
up navigation
return true;
}
return [Link](item);
}
Simple Hack
This is simple hack which is mostly used to navigate to parent activity if parent is in backstack. By
calling onBackPressed() if id is equal to [Link]
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = [Link]();
switch (id) {
case [Link]:
onBackPressed();
return true;
}
return [Link](item);
}
[Link] 47
Chapter 7: Activity Recognition
Introduction
Activity recognition is the detection of a user's physical activity in order to perform certain actions
on the device, such as taking points when a drive is detected, turn wifi off when a phone is still, or
putting the ring volume to max when the user is walking.
Examples
Google Play ActivityRecognitionAPI
Manifest
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="[Link]" />
[Link]
[Link] 48
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
apiClient = new [Link](this)
.addApi([Link])
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
//This just gets the activity intent from the ActivityReceiver class
localBroadcastManager = [Link](this);
localActivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ActivityRecognitionResult recognitionResult =
[Link](intent);
TextView textView = (TextView) findViewById([Link]);
//This is just to get the activity name. Use at your own risk.
[Link]([Link]([Link]().getType()));
}
};
}
@Override
protected void onResume() {
[Link]();
@Override
protected void onPause() {
[Link]();
@Override
public void onConnected(@Nullable Bundle bundle) {
//Only register for activity recognition if google api client has connected
[Link](apiClient, 0,
[Link](this, 0, new Intent(this, [Link]),
PendingIntent.FLAG_UPDATE_CURRENT));
[Link] 49
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
}
ActivityReceiver
@Override
public void onReceive(Context context, Intent intent) {
[Link](context).sendBroadcast([Link]("activity"));
}
}
PathSense activity recognition is another good library for devices which don't have Google Play
Services, as they have built their own activity recognition model, but requires developers register
at [Link] to get an API key and Client ID.
Manifest
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="[Link]" />
<!-- You need to acquire these from their website ([Link] -->
<meta-data
android:name="[Link].CLIENT_ID"
android:value="YOUR_CLIENT_ID" />
<meta-data
android:name="[Link].API_KEY"
android:value="YOUR_API_KEY" />
</application>
[Link] 50
[Link]
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
pathsenseLocationProviderApi = [Link](this);
//This just gets the activity intent from the ActivityReceiver class
localBroadcastManager = [Link](this);
localActivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//The detectedActivities object is passed as a serializable
PathsenseDetectedActivities detectedActivities = (PathsenseDetectedActivities)
[Link]("ps");
TextView textView = (TextView) findViewById([Link]);
[Link]([Link]().getDetectedActivity().name());
}
};
}
@Override
protected void onResume() {
[Link]();
//This gives an update everytime it receives one, even if it was the same as the last
update
[Link]([Link]);
// This gives updates only when it changes (ON_FOOT -> IN_VEHICLE for example)
// [Link]([Link]);
}
@Override
protected void onPause() {
[Link]();
[Link]();
// [Link]();
[Link]
[Link] 51
// You don't have to use their broadcastreceiver, but it's best to do so, and just pass the
result
// as needed to another class.
public class ActivityReceiver extends PathsenseActivityRecognitionReceiver {
@Override
protected void onDetectedActivities(Context context, PathsenseDetectedActivities
pathsenseDetectedActivities) {
Intent intent = new Intent("activity").putExtra("ps", pathsenseDetectedActivities);
[Link](context).sendBroadcast(intent);
}
}
[Link] 52
Chapter 8: ADB (Android Debug Bridge)
Introduction
ADB (Android Debug Bridge) is a command line tool that used to communicate with an emulator
instance or connected Android device.
Overview of ADB
Remarks
List of examples moved to adb shell:
Examples
Print verbose list of connected devices
To get a verbose list of all devices connected to adb, write the following command in your terminal:
adb devices -l
Example Output
[Link] 53
• The first column is the serial number of the device. If it starts with emulator-, this device is an
emulator.
• usb: the path of the device in the USB subsystem.
• product: the product code of the device. This is very manufacturer-specific, and as you can
see in the case of the Archos device A50PL above, it can be blank.
• model: the device model. Like product, can be empty.
• device: the device code. This is also very manufacturer-specific, and can be empty.
This will print all available information in the form of key/value pairs.
You can just read specific information by appending the name of a specific key to the command.
For example:
Here are a few interesting pieces of information that you cat get:
[[Link].dex2oat-Xms]: [64m]
[[Link].dex2oat-Xmx]: [512m]
[[Link]]: [384m]
[[Link]-dex2oat-Xms]: [64m]
[[Link]-dex2oat-Xmx]: [64m]
[[Link]]: [[Link]=default]
[[Link].x86_64.features]: [default]
[[Link].x86_64.variant]: [x86_64]
[[Link]]: [500]
[[Link]-trace-file]: [/data/anr/[Link]]
[[Link]]: [0]
[debug.force_rtl]: [0]
[[Link]]: [1]
[[Link]-type]: [1]
[[Link]]: [true]
[[Link]]: [UMTS]
[[Link]]: [1469106902492]
[[Link]]: [Android]
[[Link]-country]: [us]
[[Link]]: [false]
[[Link]]: [310260]
[[Link]]: [Android]
[[Link]-country]: [us]
[Link] 54
[[Link]]: [310260]
[[Link]]: [READY]
[[Link]-impl]: [android reference-ril 1.0]
[[Link]]: [running]
[[Link]]: [stopped]
[[Link]]: [running]
[[Link]]: [running]
[[Link].debuggerd64]: [running]
[[Link]]: [running]
[[Link]]: [running]
[[Link]]: [running]
[[Link]-logcat]: [stopped]
[[Link]-setup]: [stopped]
[[Link]]: [running]
[[Link]]: [running]
[[Link]]: [running]
[[Link]]: [running]
[[Link]]: [running]
[[Link]-reinit]: [stopped]
[[Link]]: [running]
[[Link]]: [running]
[[Link]]: [running]
[[Link]-props]: [stopped]
[[Link]-daemon]: [running]
[[Link]]: [running]
[[Link]]: [running]
[[Link]]: [running]
[[Link]]: [running]
[[Link]]: [running]
[[Link].zygote_secondary]: [running]
[[Link]]: [Android]
[[Link]]: [net.dns2]
[net.dns1]: [[Link]]
[net.dns2]: [[Link]]
[net.eth0.dns1]: [[Link]]
[net.eth0.dns2]: [[Link]]
[[Link]]: [[Link]]
[[Link]-ip]: [[Link]]
[[Link]]: [android-5e1af924d72dc578]
[net.qtaguid_enabled]: [1]
[[Link].default_init_rwnd]: [60]
[[Link].2]: [[Link]]
[[Link].profiler_ms]: [0]
[[Link]]: [Europe/Vienna]
[[Link]]: [adb]
[[Link]]: [1]
[[Link]]: [0]
[[Link].fake_camera]: [none]
[[Link].lcd_density]: [560]
[[Link]]: [-d /dev/ttyS0]
[[Link]]: [/system/lib/[Link]]
[[Link]]: [0]
[[Link]]: [unknown]
[[Link]]: []
[[Link]]: [ranchu]
[[Link]]: [Thu Jul 7 [Link] UTC 2016]
[[Link]]: [1467906990]
[[Link]]:
[Android/sdk_google_phone_x86_64/generic_x86_64:6.0/MASTER/3038907:userdebug/test-keys]
[[Link]]: [unknown]
[[Link]]: [unknown]
[Link] 55
[[Link]]: [emulator]
[[Link]]: [Thu Jul 7 [Link] UTC 2016]
[[Link]]: [1467906930]
[[Link]]: [sdk_google_phone_x86_64-userdebug 6.0 MASTER 3038907 test-keys]
[[Link]]: [sdk_google_phone_x86_64-userdebug 6.0 MASTER 3038907 test-keys]
[[Link]]:
[Android/sdk_google_phone_x86_64/generic_x86_64:6.0/MASTER/3038907:userdebug/test-keys]
[[Link]]: [sdk_google_phone_x86_64-userdebug]
[[Link]]: [[Link]]
[[Link]]: [MASTER]
[[Link]]: [generic_x86_64]
[[Link]]: [test-keys]
[[Link]]: [userdebug]
[[Link]]: [android-build]
[[Link].all_codenames]: [REL]
[[Link].base_os]: []
[[Link]]: [REL]
[[Link]]: [3038907]
[[Link].preview_sdk]: [0]
[[Link]]: [6.0]
[[Link]]: [23]
[[Link].security_patch]: [2015-10-01]
[[Link]]: [1]
[[Link].alarm_alert]: [Alarm_Classic.ogg]
[[Link]]: [yes]
[[Link].notification_sound]: [[Link]]
[[Link]]: [unencrypted]
[[Link]]: [0]
[[Link]]: [1]
[[Link]]: [ranchu]
[[Link]]: [goldfish]
[[Link]]: [1]
[[Link]]: [1]
[[Link]]: [ranchu]
[[Link]]: [pit]
[[Link]]: [0]
[[Link]]: [2]
[[Link]]: [1]
[[Link]]: [1]
[[Link]]: [131072]
[[Link]]: []
[[Link]]: [Android]
[[Link]]: [x86_64]
[[Link]]: [x86_64,x86]
[[Link].abilist32]: [x86]
[[Link].abilist64]: [x86_64]
[[Link]]: [generic_x86_64]
[[Link]]: [en-US]
[[Link]]: [unknown]
[[Link]]: [Android SDK built for x86_64]
[[Link]]: [sdk_google_phone_x86_64]
[[Link]-ppp]: [no]
[[Link]]: [0]
[[Link]]: [1469106908722]
[[Link]]: [1]
[[Link]]: []
[[Link]]: []
[[Link]]: [zygote64_32]
[selinux.reload_policy]: [1]
[[Link]]: [1]
[[Link]]: [5]
[Link] 56
[[Link].level_raw]: [50]
[[Link].level_scale]: [9]
[[Link]]: [Slow]
[sys.boot_completed]: [1]
[[Link].extra_free_kbytes]: [43200]
[[Link].tcp_def_init_rwnd]: [60]
[[Link]]: [adb]
[[Link]]: [adb]
[vold.has_adoptable]: [1]
[[Link]]: [unloaded]
[[Link]-presence]: [true]
• Make sure your device and your computer are on the same network.
While your device is connected to adb via USB, do the following command to listen for a
TCP/IP connection on a port (default 5555):
For example:
adb usb
[Link] 57
You can also connect ADB via WiFi by installing a plugin to Android Studio. In order to do so,
go to Settings > Plugins and Browse repositories, search for ADB WiFi, install it, and reopen
Android Studio. You will see a new icon in your toolbar as shown in the following image.
Connect the device to the host computer via USB and click on this AndroidWiFiADB icon. It
will display a message whether your device is connected or not. Once it gets connected you
can unplug your USB.
Rooted device
Note: Some devices which are rooted can use the ADB WiFi App from the Play Store to enable
this in a simple way. Also, for certain devices (especially those with CyanogenMod ROMs) this
option is present in the Developer Options among the Settings. Enabling it will give you the IP
address and port number required to connect to adb by simply executing adb connect <ip
address>:<port>.
When you have a rooted device but don't have access to a USB cable
su
setprop [Link] <a tcp port number>
stop adbd
start adbd
For example:
For example:
To turn it off:
setprop [Link] -1
[Link] 58
stop adbd
start adbd
Avoid timeout
By default adb will timeout after 5000 ms. This can happen in some cases such as slow WiFi or
large APK.
android {
adbOptions {
timeOutInMs 10 * 1000
}
}
You may pull (download) files from the device by executing the following command:
For example:
You may also push (upload) files from your computer to the device:
For example:
Reboot device
adb reboot
[Link] 59
adb reboot bootloader
Turn on:
Turn off:
Command:
adb devices
Result example:
Android documentation
Connect device by IP
su
setprop [Link] 5555
stop adbd
start adbd
After this, you can use CMD and ADB to connect using the following command
[Link] 60
adb connect [Link].5555
And you can disable it and return ADB to listening on USB with
setprop [Link] -1
stop adbd
start adbd
From a computer, if you have USB access already (no root required)
It is even easier to switch to using Wi-Fi, if you already have USB. From a command line on the
computer that has the device connected via USB, issue the commands
Start/stop adb
Start ADB:
adb kill-server
Stop ADB:
adb start-server
View logcat
You can run logcat as an adb command or directly in a shell prompt of your emulator or connected
device. To view log output using adb, navigate to your SDK platform-tools/ directory and execute:
$ adb logcat
Alternatively, you can create a shell connection to a device and then execute:
$ adb shell
$ logcat
This displays the date, invocation time, priority, tag, and the PID and TID of the thread issuing the
message in a long message format.
[Link] 61
Filtering
You can filter logcat by log level as well. For instance if you want only to output Debug level:
Logcat can be filtered by a package name, of course you can combine it with the log level filter:
You can also filter the log using grep (more on filtering logcat output here):
To view alternative log buffer [main|events|radio], run the logcat with the -b option:
adb logcat -c
Use the -s option followed by a device name to select on which device the adb command should
run. The -s options should be first in line, before the command.
[Link] 62
Example:
adb devices
Example#2:
adb devices -l
adb -e <command>
adb -d <command>
Taking a screenshot and video (for kitkat only) from a device display
You can then use the pull command to download the file from the device into the current directory
on you computer:
The -p flag redirects the output of the screencap command to stdout. The Perl expression this is
piped into cleans up some end-of-line issues on Marshmallow and earlier. The stream is then
written to a file named [Link] within the current directory. See this article and this article for
more information.
Video
this only work in KitKat and via ADB only. This not Working below Kitkat To start recording your
device’s screen, run the following command:
adb shell screenrecord /sdcard/example.mp4, This command will start recording your device’s
screen using the default settings and save the resulting video to a file at /sdcard/example.mp4 file on
your device.
When you’re done recording, press Ctrl+C (z in Linux) in the Command Prompt window to stop the
screen recording. You can then find the screen recording file at the location you specified. Note
that the screen recording is saved to your device’s internal storage, not to your computer.
The default settings are to use your device’s standard screen resolution, encode the video at a
bitrate of 4Mbps, and set the maximum screen recording time to 180 seconds. For more
information about the command-line options you can use, run the following command:
adb shell screenrecord –help, This works without rooting the device. Hope this helps.
One can clear the user data of a specific app using adb:
This is the same as to browse the settings on the phone, select the app and press on the clear
data button.
Sending broadcast
[Link] 64
It's possible to send broadcast to BroadcastReceiver with adb.
In this example we are sending broadcast with action [Link] and string extra in
bundle 'foo'='bar':
You can put any other supported type to bundle, not only strings:
--ez - boolean
--ei - integer
--el - long
--ef - float
--eu - uri
--eia - int array (separated by ',')
--ela - long array (separated by ',')
--efa - float array (separated by ',')
--esa - string array (separated by ',')
-p [Link]
-n [Link]/.SomeReceiver
Useful examples:
[Link] 65
Use the following command to start an app with a provided package name (or a specific activity in
an app):
Backup
You can use the adb backup command to backup your device.
How to install the Android Debugging Bridge (ADB) to a Linux system with the terminal using your
distro's repositories.
[Link] 66
sudo apt-get update
sudo apt-get install adb
List all permissions that require runtime grant from users on Android 6.0
First, make sure your app can be backed up in [Link], i.e. android:allowBackup is not
false.
Backup command:
[Link] 67
adb -s <serialNumber> shell dumpsys activity activities
Very useful when used together with the watch unix command:
watch -n 5 "adb -s <serialNumber> shell dumpsys activity activities | sed -En -e '/Stack #/p'
-e '/Running activities/,/Run #0/p'"
You may use this command for listing the files for your own debuggable apk:
And this script for pulling from cache, this copy the content to sdcard first, pull and then remove it
at the end:
#!/bin/sh
adb shell "run-as <[Link]> cat '/data/data/<[Link]>/$1' > '/sdcard/$1'"
adb pull "/sdcard/$1"
adb shell "rm '/sdcard/$1'"
./[Link] cache/[Link]
[Link] 68
Chapter 9: adb shell
Introduction
adb shellopens a Linux shell in a target device or emulator. It is the most powerful and versatile
way to control an Android device via adb.
This topic was split from ADB (Android Debug Bridge) due to reaching the limit of examples, many
of which were involving adb shell command.
Syntax
• adb shell [-e escape] [-n] [-Tt] [-x] [command]
Parameters
Parameter Details
Examples
Send text, key pressed and touch events to Android Device via ADB
execute the following command to insert the text into a view with a focus (if it supports text input)
6.0
6.0
[Link] 69
Send text prior to SDK 23
Spaces are not accepted as the input, replace them with %s.
Send events
or alternatively
Even if you don't have a hardware key you still can use a keyevent to perform the equivalent action
To run a script in Ubuntu, Create [Link] right click the file and add read/write
permission and tick allow executing file as program.
[Link]
[Link] 70
• shortlist of several interesting events ADB Shell Input Events
• reference documentation
[Link]
List packages
Prints all packages, optionally only those whose package name contains the text in <FILTER>.
All <FILTER>
Attributes:
• granting
• revoking
[Link] 71
adb install -g /path/to/sample_package.apk
• version code
• version name
• granted permissions (Android API 23+)
• etc..
4.4
Recording the display of devices running Android 4.4 (API level 19) and higher:
Note: Stop the screen recording by pressing Ctrl-C, otherwise the recording stops
automatically at three minutes or the time limit set by --time-limit.
Sets the video size: 1280x720. The default value is the device's native display resolution (if
supported), 1280x720 if not. For best results, use a size supported by your device's Advanced
Video Coding (AVC) encoder.
Sets the video bit rate for the video, in megabits per second. The default value is 4Mbps. You can
increase the bit rate to improve video quality, but doing so results in larger movie files. The
following example sets the recording bit rate to 5Mbps:
[Link] 72
adb shell screenrecord --time-limit <TIME>
Sets the maximum recording time, in seconds. The default and maximum value is 180 (3 minutes).
Displays log information on the command-line screen. If you do not set this option, the utility does
not display any information while running.
4.4
The screen recording command isn't compatible with android versions pre 4.4
The screenrecord command is a shell utility for recording the display of devices running
Android 4.4 (API level 19) and higher. The utility records screen activity to an MPEG-4
file.
Notice, that in order to change file prmissions, your device need to be rooted, su binary
doesn't come with factory shipped devices!
Convention:
For example, if you want to change file to be readable, writable and executable by everyone, this
will be your command:
Or
1st digit-specifies user permission, 2nd digit- specifies group permission, 3rd digit - specifies
world (others) permission.
[Link] 73
Access permissions:
6.0
For example, to set July 17'th 10:10am, without changing the current year, type:
Tip 1: the date change will not be reflected immediately, and a noticable change will happen only
after the system clock advances to the next minute.
You can force an update by attaching a TIME_SET intent broadcast to your call, like that:
Linux:
Windows (PowerShell):
6.0
Tip: to synchronize Android's clock with your local (linux based) machine:
[Link] 74
adb shell date -s `date +%G%m%d.%H%M%S`
This is relevant for apps that implement a BootListener. Test your app by killing your app and then
test with:
View content:
View path:
Sometimes Android's logcat is running infinitely with errors coming from some process not own by
you, draining battery or just making it hard to debug your code.
A convenient way to fix the problem without restarting the device is to locate and kill the process
causing the problem.
From Logcat
Now we can open a shell and kill the process. Note that we cannot kill root process.
adb shell
[Link] 75
inside the shell we can check more about the process using
ps -x | grep 1550
kill -9 1550
[Link] 76
Chapter 10: Adding a FuseView to an Android
Project
Introduction
Export a [Link] from fusetools and use it inside an existing android project.
Our goal is to export the entire hikr sample app and use it inside an Activity.
Examples
hikr app, just another [Link]
Prerequisites
Step 1
Find [Link] file inside the project root folder and add "[Link]" to the "Packages" array.
{
"RootNamespace":"",
"Packages": [
"Fuse",
"FuseJS",
"[Link]"
],
"Includes": [
"*",
"Modules/*.js:Bundle"
]
}
[Link] 77
3.1 In the project root folder make a new file called [Link] and paste the contents of
[Link].
[Link]
<App Background="#022328">
<[Link] Style="Light" />
<[Link] Color="#022328" />
<ClientPanel>
<Navigator DefaultPath="splash">
<SplashPage ux:Template="splash" router="router" />
<HomePage ux:Template="home" router="router" />
<EditHikePage ux:Template="editHike" router="router" />
</Navigator>
</ClientPanel>
</App>
3.2 In [Link]
[Link]
<Navigator DefaultPath="splash">
<SplashPage ux:Template="splash" router="router" />
<HomePage ux:Template="home" router="router" />
<EditHikePage ux:Template="editHike" router="router" />
</Navigator>
</Page>
<App>
<HikrApp/>
</App>
Our app is back to its normal behavior, but we now have extracted it to a separate component
called HikrApp
[Link] 78
Step 4 Inside [Link] replace the <App> tags with <ExportedViews> and add
ux:Template="HikrAppView" to <HikrApp />
<ExportedViews>
<HikrApp ux:Template="HikrAppView" />
</ExportedViews>
Remember the template HikrAppView, because we'll need it to get a reference to our view from
Java.
ExportedViews will behave as App when doing normal fuse preview and uno build
Not true. You will get this error when previewing from Fuse Studio:
Error: Couldn't find an App tag in any of the included UX files. Have you forgot to
include the UX file that contains the app tag?
<Page ux:Class="SplashPage">
<Router ux:Dependency="router" />
<GraphicsView>
<DockPanel ClipToBounds="true">
<Video Layer="Background" File="../Assets/nature.mp4" IsLooping="true"
AutoPlay="true" StretchMode="UniformToFill" Opacity="0.5">
<Blur Radius="4.75" />
</Video>
<Grid RowCount="2">
<StackPanel Alignment="VerticalCenter">
<[Link] Alignment="HorizontalCenter" FontSize="70">hikr</[Link]>
<[Link] Alignment="HorizontalCenter" Opacity=".5">get out
there</[Link]>
</StackPanel>
[Link] 79
Step 6 Export the fuse project as an aar library
// Top-level build file where you can add configuration options common to all sub-
projects/modules.
buildscript { ... }
...
allprojects {
repositories {
jcenter()
flatDir {
dirs 'libs'
}
}
}
...
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "[Link]"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "[Link]"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('[Link]'), '[Link]'
}
}
}
dependencies {
compile(name: 'app-debug', ext: 'aar')
[Link] 80
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('[Link]:espresso-core:2.2.2', {
exclude group: '[Link]', module: 'support-annotations'
})
compile '[Link]:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
}
android:launchMode="singleTask"
android:taskAffinity=""
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize"
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:taskAffinity=""
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize">
<intent-filter>
<action android:name="[Link]" />
</manifest>
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
[Link] 81
final FrameLayout root = (FrameLayout) findViewById([Link].fuse_root);
final View fuseApp = [Link]();
[Link](fuseApp);
}
}
activity_main.xml
<TextView
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="24sp"
android:textStyle="bold"
android:layout_height="wrap_content"
android:text="Hello World, from Kotlin" />
<FrameLayout
android:id="@+id/fuse_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:text="THIS IS FROM NATIVE.\nBEHIND FUSE VIEW"
android:layout_gravity="center"
android:textStyle="bold"
android:textSize="30sp"
android:background="@color/colorAccent"
android:textAlignment="center"
android:layout_height="wrap_content" />
</FrameLayout>
</LinearLayout>
Note
When you press the back button, on android, the app crashes. You can follow the issue on the
fuse forum.
A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0xdeadcab1 in tid 18026
([Link])
[Link] 82
[ 05-25 [Link].658 16567:16567 W/ ]
And the final result is something like this. You can also find a short clip on github.
[Link] 83
[Link] 84
[Link]
[Link] 85
Chapter 11: AdMob
Syntax
• compile '[Link]:firebase-ads:10.2.1' //NOTE: SET TO NEWEST VERSION IF
AVAILABLE
• <uses-permission android:name="[Link]" /> Required to retrieve the ad
• AdRequest adRequest = new [Link]().build();//Banner ad
• AdView mAdView = (AdView) findViewById([Link]);//Banner ad
• [Link](adRequest);//Banner ad
Parameters
Param Details
Remarks
• Requires a valid Admob account
• Read the admob policy. Make sure you do not do anything that can get your admob account
suspended
Examples
Implementing
Note: This example requires a valid Admob account and valid Admob ad code.
compile '[Link]:firebase-ads:10.2.1'
[Link] 86
Manifest
Internet permission is required to access the ad data. Note that this permission does not have to
be requested (using API 23+) as it is a normal permission and not dangerous:
XML
The following XML example shows a banner ad:
<[Link]
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/adView"
ads:adSize="BANNER"
ads:adUnitId="@string/main_screen_ad" />
For the code of other types, refer to the Google AdMob Help.
Java
The following code is for the integration of banner ads. Note that other ad types may require
different integration:
Add the AdView life cycle methods in the onResume(), onPause(), and onDestroy() methods of your
activity:
@Override
public void onPause() {
if (mAdView != null) {
[Link]();
}
[Link]();
}
@Override
public void onResume() {
[Link]();
[Link] 87
if (mAdView != null) {
[Link]();
}
}
@Override
public void onDestroy() {
if (mAdView != null) {
[Link]();
}
[Link]();
}
[Link] 88
Chapter 12: AIDL
Introduction
AIDL is Android interface definition language.
What? It is a bounded services. This AIDL service will be active till atleast one of the client is exist.
It works based on marshaling and unmarshaling concept.
Why? Remote applications can access your service + Multi Threading.(Remote application
request).
How? Create the .aidl file Implement the interface Expose the interface to clients
Examples
AIDL Service
[Link]
interface ICalculator {
int add(int x,int y);
int sub(int x,int y);
}
[Link]
public AidlService() {
Log.i(TAG, className+" Constructor");
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.i(TAG, className+" onBind");
return [Link]();
}
@Override
public void onCreate() {
[Link]();
Log.i(TAG, className+" onCreate");
[Link] 89
}
@Override
public void onDestroy() {
[Link]();
Log.i(TAG, className+" onDestroy");
}
@Override
public int sub(int x, int y) throws RemoteException {
Log.i(TAG, className+" add Thread Name: "+[Link]().getName());
int z = x-y;
return z;
}
};
Service Connection
@Override
public void onServiceDisconnected(ComponentName name) {
unbindService(serviceConnection);
}
};
[Link] 90
Chapter 13: AlarmManager
Examples
Run an intent at a later time
1. Create a receiver. This class will receive the intent and handle it how you wish.
2. Give an intent to AlarmManager. This example will trigger the intent to be sent to
AlarmReceiver after 1 minute.
If you want to cancel an alarm, and you don't have a reference to the original PendingIntent used
to set the alarm, you need to recreate a PendingIntent exactly as it was when it was originally
created.
if their action, data, type, class, and categories are the same. This does not compare
any extra data included in the intents.
[Link] 91
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
[Link](AlarmManager.RTC_WAKEUP, targetTimeInMillis, pendingIntent);
Here is how you would create a new PendingIntent reference that you can use to cancel the alarm
with a new AlarmManager reference:
With more and more battery optimizations being put into the Android system over time, the
methods of the AlarmManager have also significantly changed (to allow for more lenient timing).
However, for some applications it is still required to be as exact as possible on all Android
versions. The following helper uses the most accurate method available on all platforms to
schedule a PendingIntent:
Android 6 (API23) introduced Doze mode which interferes with AlarmManager. It uses certain
maintenance windows to handle alarms, so even if you used setExactAndAllowWhileIdle() you
cannot make sure that your alarm fires at the desired point of time.
You can turn this behavior off for your app using your phone's settings (Settings/General/Battery &
power saving/Battery usage/Ignore optimizations or similar)
[Link] 92
... and eventually show the respective settings dialog:
[Link] 93
Chapter 14: Android Architecture
Components
Introduction
Android Architecture Components is new collection of libraries that help you design robust,
testable, and maintainable apps. Main parts are: Lifecycles, ViewModel, LiveData, Room.
Examples
Add Architecture Components
Project [Link]
allprojects {
repositories {
jcenter()
// Add this if you use Gradle 4.0+
google()
// Add this if you use Gradle < 4.0
maven { url '[Link] }
}
}
ext {
archVersion = '1.0.0-alpha5'
}
// For Room
compile "[Link]:runtime:$archVersion"
annotationProcessor "[Link]:compiler:$archVersion"
[Link] 94
public abstract class BaseCompatLifecycleActivity extends AppCompatActivity implements
LifecycleRegistryOwner {
// We need this class, because LifecycleActivity extends FragmentActivity not
AppCompatActivity
@NonNull
private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
@NonNull
@Override
public LifecycleRegistry getLifecycle() {
return lifecycleRegistry;
}
}
ContentRepository contentRepository;
public BaseViewModel() {
// some inits
}
Somewhere in UI:
[Link] 95
public class VideoActivity extends BaseCompatLifecycleActivity {
private VideoViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
// Get ViewModel
viewModel = [Link](this).get([Link]);
// Add observer
[Link]().observe(this, data -> {
// some checks
[Link](data);
});
...
if (savedInstanceState == null) {
// init loading only at first creation
// you just set params and
[Link](url, referrer);
}
}
Room peristence
Room require four parts: Database class, DAO classes, Entity classes and Migration classes (now
you may use only DDL methods):
Entity classes
[Link] 96
DAO classes
@Dao
public interface VideoDao {
// Create insert with custom conflict strategy
@Insert(onConflict = [Link])
void saveVideos(List<VideoItem> videos);
// Simple update
@Update
void updateVideos(VideoItem... videos);
Database class
Migrations
private Migrations() {
}
}
[Link] 97
ContentDatabase provideContentDatabase() {
return [Link](context, [Link], "[Link]")
.addMigrations([Link]).build();
}
Use in ViewModel:
Custom LiveData
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// Do something
}
@Override
public void onProviderEnabled(String provider) {
// Do something
}
@Override
public void onProviderDisabled(String provider) {
// Do something
}
[Link] 98
};
@Override
protected void onActive() {
// We have observers, start working
[Link](LocationManager.GPS_PROVIDER, 0, 0, listener);
}
@Override
protected void onInactive() {
// We have no observers, stop working
[Link](listener);
}
}
You may create component, that will be notified on lifecycle state change:
@OnLifecycleEvent([Link].ON_START)
void start() {
[Link] 99
if (enabled) {
// connect
}
}
@OnLifecycleEvent([Link].ON_STOP)
void stop() {
// disconnect if connected
}
}
[Link] 100
Chapter 15: Android Authenticator
Examples
Basic Account Authenticator Service
The Android Account Authenticator system can be used to make the client authenticate with a
remote server. Three pieces of information are required:
1. The service:
<service android:name="[Link]">
<intent-filter>
<action android:name="[Link]" />
</intent-filter>
<meta-data
android:name="[Link]"
android:resource="@xml/authenticator" />
</service>
Note that the [Link] is included within the intent-filter tag. The
xml resource (named authenticator here) is specified in the meta-data tag.
public MyAuthenticationService() {
super();
}
@Override
public void onCreate() {
[Link]();
[Link] 101
synchronized (lock) {
if (mAuthenticator == null) {
mAuthenticator = new MyAuthenticator(this);
}
}
}
@Override
public IBinder onBind(Intent intent) {
return [Link]();
}
<account-authenticator xmlns:android="[Link]
android:accountType="[Link]"
android:icon="@drawable/appicon"
android:smallIcon="@drawable/appicon"
android:label="@string/app_name" />
Do not directly assign a string to android:label or assign missing drawables. It will crash without
warning.
@Override
public Bundle addAccount(AccountAuthenticatorResponse response,
String accountType,
String authTokenType,
String[] requiredFeatures,
Bundle options) throws NetworkErrorException {
return bundle;
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,
Bundle options) throws NetworkErrorException {
return null;
}
[Link] 102
@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
return null;
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String
authTokenType, Bundle options) throws NetworkErrorException {
return null;
}
@Override
public String getAuthTokenLabel(String authTokenType) {
return null;
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[]
features) throws NetworkErrorException {
return null;
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
String authTokenType, Bundle options) throws NetworkErrorException {
return null;
}
}
[Link] 103
Chapter 16: Android game development
Introduction
A short introduction to creating a game on the Android platform using Java
Remarks
• The first example covers the basics: There are no objectives, but it shows you how you
create a basic part of a 2D game using SurfaceView.
• Make sure to save any important data when you create a game; everything else will be lost
Examples
Game using Canvas and SurfaceView
This covers how you can create a basic 2D game using SurfaceView.
Now for the game itself. First, we start by implementing a game thread:
/**
* Holds the surface frame
*/
private SurfaceHolder holder;
/**
* Draw thread
*/
[Link] 104
private Thread drawThread;
/**
* True when the surface is ready to draw
*/
private boolean surfaceReady = false;
/**
* Drawing thread flag
*/
/**
* Time per frame for 60 FPS
*/
private static final int MAX_FRAME_TIME = (int) (1000.0 / 60.0);
/*
* All the constructors are overridden to ensure functionality if one of the different
constructors are used through an XML file or programmatically
*/
public Game(Context context) {
super(context);
init();
}
public Game(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Game(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(21)
public Game(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
@Override
[Link] 105
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
if (width == 0 || height == 0){
return;
}
// resize your UI
}
@Override
public void surfaceCreated(SurfaceHolder holder){
[Link] = holder;
if (drawThread != null){
Log.d(LOGTAG, "draw thread still active..");
drawingActive = false;
try{
[Link]();
} catch (InterruptedException e){}
}
surfaceReady = true;
startDrawThread();
Log.d(LOGTAG, "Created");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder){
// Surface is not used anymore - stop the drawing thread
stopDrawThread();
// and release the surface
[Link]().release();
[Link] = null;
surfaceReady = false;
Log.d(LOGTAG, "Destroyed");
}
@Override
public boolean onTouchEvent(MotionEvent event){
// Handle touch events
return true;
}
/**
* Stops the drawing thread
*/
public void stopDrawThread(){
if (drawThread == null){
Log.d(LOGTAG, "DrawThread is null");
return;
}
drawingActive = false;
while (true){
try{
Log.d(LOGTAG, "Request last frame");
[Link](5000);
break;
} catch (Exception e) {
Log.e(LOGTAG, "Could not join with draw thread");
}
[Link] 106
}
drawThread = null;
}
/**
* Creates a new draw thread and starts it.
*/
public void startDrawThread(){
if (surfaceReady && drawThread == null){
drawThread = new Thread(this, "Draw thread");
drawingActive = true;
[Link]();
}
}
@Override
public void run() {
Log.d(LOGTAG, "Draw thread started");
long frameStartTime;
long frameTime;
/*
* In order to work reliable on Nexus 7, we place ~500ms delay at the start of drawing
thread
* (AOSP - Issue 58385)
*/
if ([Link]("google") &&
[Link]("asus") &&
[Link]("Nexus 7")) {
Log.w(LOGTAG, "Sleep 500ms (Device: Asus Nexus 7)");
try {
[Link](500);
} catch (InterruptedException ignored) {}
}
while (drawing) {
if (sf == null) {
return;
}
frameStartTime = [Link]();
Canvas canvas = [Link]();
if (canvas != null) {
try {
synchronized (sf) {
tick();
render(canvas);
}
} finally {
[Link](canvas);
}
}
[Link] 107
// ignore
}
}
}
Log.d(LOGTAG, "Draw thread finished");
}
}
That is the basic part. Now you have the ability to draw onto the screen.
public final int x = 100;//The reason for this being static will be shown when the game is
runnable
public int y;
public int velY;
For this next part, you are going to need an image. It should be about 100x100 but it can be bigger
or smaller. For learning, a Rect can also be used(but that requires change in code a little bit down)
...
[Link](PLAYER_BMP, x, y, null);
...
boolean up = false;
in onTouchEvent, we add:
if([Link]() == MotionEvent.ACTION_DOWN){
up = true;
}else if([Link]() == MotionEvent.ACTION_UP){
up = false;
}
if(up){
velY -=1;
}
else{
[Link] 108
velY +=1;
}
if(velY >14)velY = 14;
if(velY <-14)velY = -14;
y += velY *2;
At this point, the game is runnable. Meaning you can launch it and test it.
Now you should have a player image or rect going up and down the screen. The player can be
created as a custom class if needed. Then all the player-related things can be moved into that
class, and use an instance of that class to move, render and do other logic.
Now, as you probably saw under testing it flies off the screen. So we need to limit it.
In init, after initializing width and height, we create a new rect that is the screen.
and in tick:
if(!getPlayerBound().intersects(screen){
gameOver = true;
}
The implementation of gameOVer can also be used to show the start of a game.
[Link] 109
Other aspects of a game worth noting:
[Link] 110
Chapter 17: Android Java Native Interface
(JNI)
Introduction
JNI (Java Native Interface) is a powerful tool that enables Android developers to utilize the NDK
and use C++ native code in their applications. This topic describes the usage of Java <-> C++
interface.
Examples
How to call functions in a native library via the JNI interface
The Java Native Interface (JNI) allows you to call native functions from Java code, and vice versa.
This example shows how to load and call a native function via JNI, it does not go into accessing
Java methods and fields from native code using JNI functions.
#include <jni.h>
The pEnv argument is a pointer to the JNI environment that you can pass to JNI functions to
access methods and fields of Java objects and classes. The thiz pointer is a jobject reference to
the Java object that the native method was called on (or the class if it is a static method).
static{
[Link]("jniexample");
}
Note the lib at the start, and the .so at the end of the filename are omitted.
[Link] 111
Call the native function from Java like this:
The Java Native Interface (JNI) allows you to call Java functions from native code. Here is a
simple example of how to do it:
Java code:
package [Link];
public class JNITest {
public static int getAnswer(bool) {
return 42;
}
}
Native code:
int getTheAnswer()
{
// Get JNI environment
JNIEnv *env = JniGetEnv();
// Find the Java class - provide package ('.' replaced to '/') and class name
jclass jniTestClass = env->FindClass("com/example/jniexample/JNITest");
// Find the Java method - provide parameters inside () and return value (see table below
for an explanation of how to encode them)
jmethodID getAnswerMethod = env->GetStaticMethodID(jniTestClass, "getAnswer", "(Z)I;");
Z boolean
B byte
C char
S short
I int
J long
[Link] 112
JNI Signature Java Type
F float
D double
L fully-qualified-class ; fully-qualified-class
[ type type[]
So for our example we used (Z)I - which means the function gets a boolean and returns an int.
This method will help to get the Java string from C++ string.
if (!cstring) {
return nullString;
}
global_env->DeleteLocalRef(strClass);
global_env->DeleteLocalRef(encoding);
global_env->DeleteLocalRef(bytes);
return str;
}
[Link] 113
Chapter 18: Android Kernel Optimization
Examples
Low RAM Configuration
Android now supports devices with 512MB of RAM. This documentation is intended to help OEMs
optimize and configure Android 4.4 for low-memory devices. Several of these optimizations are
generic enough that they can be applied to previous releases as well.
For 512MB devices, this API is expected to return: "true" It can be enabled by the following system
property in the device makefile.
PRODUCT_PROPERTY_OVERRIDES += [Link].low_ram=true
Disable JIT
System-wide JIT memory usage is dependent on the number of applications running and the code
footprint of those applications. The JIT establishes a maximum translated code cache size and
touches the pages within it as needed. JIT costs somewhere between 3M and 6M across a typical
running system.
The large apps tend to max out the code cache fairly quickly (which by default has been 1M). On
average, JIT cache usage runs somewhere between 100K and 200K bytes per app. Reducing the
max size of the cache can help somewhat with memory usage, but if set too low will send the JIT
into a thrashing mode. For the really low-memory devices, we recommend the JIT be disabled
entirely.
This can be achieved by adding the following line to the product makefile:
PRODUCT_PROPERTY_OVERRIDES += [Link]=0
The CPU governor itself is just 1 C file, which is located in kernel_source/drivers/cpufreq/, for
example: cpufreq_smartass2.c. You are responsible yourself for find the governor (look in an
existing kernel repo for your device) But in order to successfully call and compile this file into your
kernel you will have to make the following changes:
[Link] 114
now paste it.
2. and open Kconfig (this is the interface of the config menu layout) when adding a kernel, you
want it to show up in your config. You can do that by adding the choice of governor.
config CPU_FREQ_GOV_GOVNAMEHERE
tristate "'gov_name_lowercase' cpufreq governor"
depends on CPU_FREQ
help
governor' - a custom governor!
config CPU_FREQ_GOV_SMARTASS2
tristate "'smartassV2' cpufreq governor"
depends on CPU_FREQ
help
'smartassV2' - a "smart" optimized governor!
next to adding the choice, you also must declare the possibility that the governor gets chosen as
default governor.
config CPU_FREQ_DEFAULT_GOV_GOVNAMEHERE
bool "gov_name_lowercase"
select CPU_FREQ_GOV_GOVNAMEHERE
help
Use the CPUFreq governor 'govname' as default.
config CPU_FREQ_DEFAULT_GOV_SMARTASS2
bool "smartass2"
select CPU_FREQ_GOV_SMARTASS2
help
Use the CPUFreq governor 'smartassV2' as default.
– can’t find the right place to put it? Just search for “CPU_FREQ_GOV_CONSERVATIVE”, and place the
code beneath, same thing counts for “CPU_FREQ_DEFAULT_GOV_CONSERVATIVE”
Now that Kconfig is finished you can save and close the file.
3. While still in the /drivers/cpufreq folder, open Makefile. In Makefile, add the line
corresponding to your CPU Governor. for example:
obj-$(CONFIG_CPU_FREQ_GOV_SMARTASS2) += cpufreq_smartass2.o
Be ware that you do not call the native C file, but the O file! which is the compiled C file. Save the
file.
4. Move to: kernel_source/includes/linux. Now open cpufreq.h Scroll down until you see
something like:
[Link] 115
#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND)
extern struct cpufreq_governor cpufreq_gov_ondemand;
#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_ondemand)
Now add your entry with the selected CPU Governor, example:
#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS2)
extern struct cpufreq_governor cpufreq_gov_smartass2;
#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_smartass2)
The initial CPU Governor setup is now complete. when you’ve done all steps successfully, you
should be able to choose your governor from the menu (menuconfig, xconfig, gconfig, nconfig).
Once checked in the menu it will be included to the kernel.
Commit that is nearly the same as above instructions: Add smartassV2 and lulzactive governor
commit
I/O Schedulers
You can enhance your kernel by adding new I/O schedulers if needed. Globally, governors and
schedulers are the same; they both provide a way how the system should work. However, for the
schedulers it is all about the input/output datastream except for the CPU settings. I/O schedulers
decide how an upcoming I/O activity will be scheduled. The standard schedulers such as noop or
cfq are performing very reasonably.
1. Copy your I/O scheduler file (for example, sio-iosched.c) and browse to kernel_source/block.
Paste the scheduler file there.
2. Now open [Link] and add your choice to the Kconfig, for example for SIO:
config IOSCHED_SIO
tristate "Simple I/O scheduler"
default y
---help---
The Simple I/O scheduler is an extremely simple scheduler,
based on noop and deadline, that relies on deadlines to
ensure fairness. The algorithm does not do any sorting but
basic merging, trying to keep a minimum overhead. It is aimed
mainly for aleatory access devices (eg: flash devices).
[Link] 116
4. Open the Makefile in kernel_source/block/ and simply add the following line for SIO:
obj-$(CONFIG_IOSCHED_SIO) += sio-iosched.o
Save the file and you are done! The I/O schedulers should now pop up at the menu config.
[Link] 117
Chapter 19: Android NDK
Examples
Building native executables for Android
project/jni/main.c
#include <stdio.h>
#include <unistd.h>
int main(void) {
printf("Hello world!\n");
return 0;
}
project/jni/[Link]
include $(CLEAR_VARS)
LOCAL_MODULE := hello_world
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)
project/jni/[Link]
APP_ABI := all
APP_PLATFORM := android-21
If you want to support devices running Android versions lower than 5.0 (API 21), you need to
compile your binary with APP_PLATFORM set to an older API, e.g. android-8. This is a consequence of
Android 5.0 enforcing Position Independent Binaries (PIE), whereas older devices do not
necessarily support PIEs. Therefore, you need to use either the PIE or the non-PIE, depending on
the device version. If you want to use the binary from within your Android application, you need to
check the API level and extract the correct binary.
APP_ABI can be changed to specific platforms such as armeabi to build the binary for those
architectures only.
In the worst case, you will have both a PIE and a non-PIE binary for each architecture (about 14
different binaries using ndk-r10e).
cd project
ndk-build
[Link] 118
You will find the binaries at project/libs/<architecture>/hello_world. You can use them via ADB (
push and chmod it with executable permission) or from your application (extract and chmod it with
executable permission).
To determine the architecture of the CPU, retrieve the build property [Link] for the
primary architecture or [Link] (on newer devices) for a complete list of supported
architectures. You can do this using the [Link] class from within your application or
using getprop <name> via ADB.
ndk-build clean
First make sure you link against the logging library in your [Link] file:
LOCAL_LDLIBS := -llog
#include <android/log.h>
#define TAG "MY LOG"
Example:
int x = 42;
LOGD("The value of x is %d", x);
[Link] 119
Read Android NDK online: [Link]
[Link] 120
Chapter 20: Android Paypal Gateway
Integration
Remarks
Paypal provide us their own library for payment so it is now much secure and easy to implement in
our application. Below are the important step to do.
Examples
Setup paypal in your android code
2)Now open your manifest file and give the below permissions
<service
android:name="[Link]"
android:exported="false" />
<activity android:name="[Link]" />
<activity android:name="[Link]" />
<activity android:name="[Link]" />
<activity android:name="[Link]" />
<activity android:name="[Link]" />
<activity android:name="[Link]" />
<activity android:name="[Link]" />
<activity
android:name="[Link]"
android:configChanges="keyboardHidden|orientation" />
<activity android:name="[Link]" />
4)Open your Activity class and set Configuration for your app-
5)Now set client id from the Paypal developer account- private static final String
CONFIG_CLIENT_ID = "PUT YOUR CLIENT ID"; 6)Inside onCreate method call the Paypal
service- Intent intent = new Intent(this, [Link]);
[Link](PayPalService.EXTRA_PAYPAL_CONFIGURATION, config); startService(intent);
7)Now you are ready to make a payment just on button press call the Payment Activity-
[Link] 121
PayPalPayment thingToBuy = new PayPalPayment(new BigDecimal(1),"USD", "[Link]",
PayPalPayment.PAYMENT_INTENT_SALE);
Intent intent = new Intent([Link],
[Link]);
[Link](PaymentActivity.EXTRA_PAYMENT, thingToBuy);
startActivityForResult(intent, REQUEST_PAYPAL_PAYMENT);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_PAYPAL_PAYMENT) {
if (resultCode == Activity.RESULT_OK) {
PaymentConfirmation confirm = data
.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION);
if (confirm != null) {
try {
[Link]("Responseeee"+confirm);
Log.i("paymentExample", [Link]().toString());
JSONObject jsonObj=new
JSONObject([Link]().toString());
String
paymentId=[Link]("response").getString("id");
[Link]("payment id:-=="+paymentId);
[Link](getApplicationContext(), paymentId,
Toast.LENGTH_LONG).show();
} catch (JSONException e) {
Log.e("paymentExample", "an extremely unlikely failure
occurred: ", e);
}
}
} else if (resultCode == Activity.RESULT_CANCELED) {
Log.i("paymentExample", "The user canceled.");
} else if (resultCode == PaymentActivity.RESULT_EXTRAS_INVALID) {
Log.i("paymentExample", "An invalid Payment was submitted. Please see
the docs.");
}
}
[Link] 122
Chapter 21: Android Places API
Examples
Place Picker Usage Example
Place Picker is a really simple UI widget provided by Places API. It provides a built-in map, current
location, nearby places, search abilities and autocomplete.
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_place_picker_sample);
[Link] 123
Getting Current Places by Using Places API
You can get the current location and local places of user by using the Google Places API.
Ar first, you should call the [Link]() method in order to retrieve local
business or other places. This method returns a PlaceLikelihoodBuffer object which contains a list
of PlaceLikelihood objects. Then, you can get a Place object by calling the
[Link]() method.
Important: You must request and obtain the ACCESS_FINE_LOCATION permission in order to
allow your app to access precise location information.
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_location);
getCurrentLocation();
}
[Link](this,new
String[]{[Link].ACCESS_FINE_LOCATION},PERMISSION_REQUEST_TO_ACCESS_LOCATION);
return;
}
PendingResult<PlaceLikelihoodBuffer> result =
[Link](googleApiClient, null);
[Link](new ResultCallback<PlaceLikelihoodBuffer>() {
@Override
public void onResult(PlaceLikelihoodBuffer likelyPlaces) {
Log.i(LOG_TAG, [Link]("Result received : %d " , [Link]() ));
StringBuilder stringBuilder = new StringBuilder();
[Link] 124
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[]
grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_TO_ACCESS_LOCATION: {
// If the request is cancelled, the result arrays are empty.
if ([Link] > 0 && grantResults[0] ==
PackageManager.PERMISSION_GRANTED) {
getCurrentLocation();
} else {
// Permission denied, boo!
// Disable the functionality that depends on this permission.
}
return;
}
// Add further 'case' lines to check for other permissions this app might request.
}
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.e(LOG_TAG, "GoogleApiClient connection failed: " +
[Link]());
}
The autocomplete feature in the Google Places API for Android provides place predictions to user.
While user types in the search box, autocomplete shows places according to user's queries.
[Link]
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_autocomplete);
[Link](new PlaceSelectionListener() {
@Override
public void onPlaceSelected(Place place) {
Log.i(LOG_TAG, "Place: " + [Link]());
[Link]([Link]("Selected places : %s - %s" ,
[Link](), [Link]()));
}
@Override
[Link] 125
public void onError(Status status) {
Log.i(LOG_TAG, "An error occurred: " + status);
[Link]([Link], "Place cannot be selected!!",
Toast.LENGTH_SHORT).show();
}
});
activity_autocomplete.xml
<fragment
android:id="@+id/fragment_autocomplete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="[Link]"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/txtSelectedPlaceName"
android:layout_margin="20dp"
android:padding="15dp"
android:hint="@string/txt_select_place_hint"
android:textSize="@dimen/place_autocomplete_prediction_primary_text"/>
[Link](new [Link]() {
@Override
public void onClick(View v) {
try {
//Do your stuff from place
startActivityForResult(intent,
PLACE_AUTOCOMPLETE_FROM_PLACE_REQUEST_CODE);
} catch (GooglePlayServicesRepairableException e) {
// TODO: Handle the error.
} catch (GooglePlayServicesNotAvailableException e) {
// TODO: Handle the error.
}
}
});
[Link](new [Link]() {
@Override
public void onClick(View v) {
try {
//Do your stuff to place
[Link] 126
startActivityForResult(intent, PLACE_AUTOCOMPLETE_TO_PLACE_REQUEST_CODE);
} catch (GooglePlayServicesRepairableException e) {
// TODO: Handle the error.
} catch (GooglePlayServicesNotAvailableException e) {
// TODO: Handle the error.
}
}
});
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PLACE_AUTOCOMPLETE_FROM_PLACE_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
//Do your ok >from place< stuff here
} else if (resultCode == PlaceAutocomplete.RESULT_ERROR) {
//Handle your error >from place<
} else if (resultCode == RESULT_CANCELED) {
// The user canceled the operation.
}
} else if (requestCode == PLACE_AUTOCOMPLETE_TO_PLACE_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
//Do your ok >to place< stuff here
} else if (resultCode == PlaceAutocomplete.RESULT_ERROR) {
//Handle your error >to place<
} else if (resultCode == RESULT_CANCELED) {
// The user canceled the operation.
}
}
}
In some scenarios, we might want to narrow down the results being shown by
PlaceAutocomplete to a specific country or maybe to show only Regions. This can be achieved
by setting an AutocompleteFilter on the intent. For example, if I want to look only for places of
type REGION and only belonging to India, I would do the following:
[Link]
Intent intent =
new [Link](PlaceAutocomplete.MODE_FULLSCREEN)
.setFilter(typeFilter)
[Link] 127
.build(this);
startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE);
} catch (GooglePlayServicesRepairableException
| GooglePlayServicesNotAvailableException e) {
[Link]();
}
}
activity_main.xml
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/selected_place"/>
</LinearLayout>
The PlaceAutocomplete will launch automatically and you can then select a place from the
results which will only be of the type REGION and will only belong to the specified country. The
intent can also be launched at the click of a button.
[Link] 128
Chapter 22: Android programming with Kotlin
Introduction
Using Kotlin with Android Studio is an easy task as Kotlin is developed by JetBrains. It is the same
company that stands behind IntelliJ IDEA - a base IDE for Android Studio. That is why there are
almost none problems with the compatibility.
Remarks
If you want to learn more about Kotlin Programming Language check out Documentation.
Examples
Installing the Kotlin plugin
For Windows:
For Mac:
And then search for and install Kotlin. You'll need to restart the IDE after this completes.
[Link] 129
[Link] 130
and then add Kotlin support to it or modify your existing project. To do it, you have to:
1. Add dependency to a root gradle file - you have to add the dependency for kotlin-android
plugin to a root [Link] file.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath '[Link]:gradle:2.3.1'
classpath '[Link]:kotlin-gradle-plugin:1.1.2'
}
}
allprojects {
repositories {
jcenter()
}
}
2. Apply Kotlin Android Plugin - simply add apply plugin: 'kotlin-android' to a module
[Link] file.
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "[Link]"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "[Link]"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('[Link]'), '[Link]'
}
}
}
dependencies {
[Link] 131
compile '[Link]:kotlin-stdlib:1.1.1'
compile '[Link]:constraint-layout:1.0.2'
compile '[Link]:appcompat-v7:25.3.1'
androidTestCompile('[Link]:espresso-core:2.2.2', {
exclude group: '[Link]', module: 'support-annotations'
})
testCompile 'junit:junit:4.12'
}
[Link] 132
Final class could look like this:
import [Link]
import [Link]
[Link] 133
Converting existing Java code to Kotlin
Kotlin Plugin for Android Studio support converting existing Java files to Kotlin files. Choose a
Java file and invoke action Convert Java File to Kotlin File:
fun startNewActivity(){
val intent: Intent = Intent(context, Activity::[Link])
startActivity(intent)
}
fun startNewActivityWithIntents(){
val intent: Intent = Intent(context, Activity::[Link])
[Link](KEY_NAME, KEY_VALUE)
startActivity(intent)
}
[Link] 134
Chapter 23: Android Sound and Media
Examples
How to pick image and video for api >19
Here is a tested code for image and [Link] will work for all APIs less than 19 and greater than 19
as well.
Image:
Video:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
[Link](requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == 10) {
Uri selectedImageUri = [Link]();
String selectedImagePath = getRealPathFromURI(selectedImageUri);
} else if (requestCode == 20) {
Uri selectedVideoUri = [Link]();
String selectedVideoPath = getRealPathFromURI(selectedVideoUri);
}
[Link] 135
if (uri == null) {
return null;
}
String[] projection = {[Link]};
Cursor cursor = getActivity().getContentResolver().query(uri, projection, null,
null, null);
if (cursor != null) {
int column_index = cursor
.getColumnIndexOrThrow([Link]);
[Link]();
return [Link](column_index);
}
return [Link]();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if ([Link]() == MotionEvent.ACTION_DOWN) {
// Getting the user sound settings
AudioManager audioManager = (AudioManager)
getSystemService(AUDIO_SERVICE);
float actualVolume = (float) audioManager
.getStreamVolume(AudioManager.STREAM_MUSIC);
float maxVolume = (float) audioManager
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
float volume = actualVolume / maxVolume;
// Is the sound loaded already?
if (loaded) {
[Link](soundID, volume, volume, 1, 0, 1f);
Log.e("Test", "Played sound");
[Link] 136
}
}
return false;
}
}
[Link] 137
Chapter 24: Android Studio
Examples
Filter logs from UI
Android logs can be filtered directly from the UI. Using this code
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
Log.e(TAG1,"Log from onCreate method with TAG1");
Log.i(TAG2,"Log from onCreate method with TAG2");
}
}
The level can be set to get logs with given level and above. For example the verbose level will
catch verbose, debug, info, warn, error and assert logs.
Using the same example, if I set the level to error, I only get
[Link] 138
01-14 [Link].961 12880-12880/[Link] E/MainActivity: Log
from onCreate method with TAG1
Custom filters can be set and save from the UI. In the AndroidMonitor tab, click on the right
dropdown (must contains Show only selected application or No filters) and select Edit filter
configuration.
[Link] 139
Important If you add an input in the filter bar, android studio will consider both your filter and your
input.
[Link] 140
Custom colors of logcat message based on message importance
Go to File -> Settings -> Editor -> Colors & Fonts -> Android Logcat
[Link] 141
Enable/Disable blank line copy
ctrl + alt + shift + / (cmd + alt + shift + / on MacOS) should show you the following dialog:
[Link] 142
The key you want to enable/disable is
[Link]
These are based on the default IntelliJ shortcut map. You can switch to other common IDE
shortcut maps via File -> Settings -> Keymap -> <Choose Eclipse/Visual Studio/etc from Keymaps
dropdown>
[Link] 143
Action Shortcut
Build CTRL + F9
Find CTRL +F
Refactor:
Action Shortcut
Refactor This (menu/picker for all applicable refactor Mac CTRL + T - Win/Linux CTRL +
actions of the current element) ALT + T
Rename SHIFT + F6
[Link] 144
Action Shortcut
1. Click File -> Settings. Search for "gradle" and click in Offline work box.
2. Go to Compiler (in same settings dialog just below Gradle) and add --offline to Command-line
Options text box.
[Link]=true
[Link]=true
-Xms1024m
-Xmx4096m
-XX:MaxPermSize=1024m
-XX:ReservedCodeCacheSize=256m
-XX:+UseCompressedOops
Window
%USERPROFILE%.{FOLDER_NAME}\[Link] and/or
%USERPROFILE%.{FOLDER_NAME}\[Link]
Mac
~/Library/Preferences/{FOLDER_NAME}/[Link]
Linux
~/.{FOLDER_NAME}/[Link] and/or
~/.{FOLDER_NAME}/[Link]
[Link] 145
System Requirements
Installation
Window
Linux
By going to Settings >> Keymap A window will popup showing All the Editor Actions with the their
name and shortcuts. Some of the Editor Actions do not have shortcuts. So right click on that and
add a new shortcut to that.
Check the image below
[Link] 146
Gradle build project takes forever
Android Studio -> Preferences -> Gradle -> Tick Offline work and then restart your Android
studio.
Reference screenshot:
[Link] 147
[Link] 148
• Assets folder will be under MAIN folder with the same symbol as RES folder.
• In this example I put a font file.
[Link] 149
Chapter 25: Android Things
Examples
Controlling a Servo Motor
This example assumes you have a servo with the following characteristics, which happen to be
typical:
You need to check if those values match your hardware, since forcing it to go outside its specified
operating range can damage the servo. A damaged servo in turn has the potential to damage your
Android Things device. The example ServoController class consists of two methods, setup() and
setPosition():
[Link](1000.0d / periodMs);
setPosition(90);
[Link](true);
}
Log.i(TAG, "Duty cycle = " + dutyCycle + " pulse length = " + pulseLengthMs);
try {
[Link](dutyCycle);
} catch (IOException e) {
[Link]();
[Link] 150
}
}
}
You can discover pin names that support PWM on your device as follows:
In order to make your servo swinging forever between 80 degrees and 100 degrees, you can
simply use the following code:
You can compile and deploy all of the above code without actually hooking any servo motors to
the computing device. For the wiring, refer to your computing device pinout chart (e.g. a Raspberry
Pi 3 pinout chart is available here).
Then you need to hook your servo to Vcc, Gnd, and signal.
[Link] 151
Chapter 26: Android Versions
Remarks
Android API-
Name Release date Build.VERSION_CODES
version level
Battenberg 9 February
1.1 2 BASE_1_1
(Beta) 2009
15 September
Donut 1.6 4 DONUT
2009
26 October
Eclair 2.0 5 ECLAIR
2009
3 December
2.0.1 6 ECLAIR_0_1
2009
12 January
2.1 7 ECLAIR_MR1
2010
6 December
Gingerbread 2.3 9 GINGERBREAD
2010
9 February
2.3.3 10 GINGERBREAD_MR1
2011
22 February
Honeycomb 3.0 11 HONEYCOMB
2011
16 December
4.0.3 15 ICE_CREAM_SANDWICH_MR1
2011
[Link] 152
Android API-
Name Release date Build.VERSION_CODES
version level
13 November
4.2 17 JELLY_BEAN_MR1
2012
31 October
KitKat 4.4 19 KITKAT
2013
17 October
Lollipop 5.0 21 LOLLIPOP
2014
5 October
Marshmallow 6.0 23 M
2015
22 August
Nougat 7.0 24 N
2016
5 December
7.1.1 25 N_MR1
2016
Examples
Checking the Android Version on device at runtime
In order to conditionally run code based on the device's Android version, use the TargetApi
annotation to avoid Lint errors, and check the build version before running the code specific to the
API level.
Here is an example of how to use a class that was introduced in API-23, in a project that supports
API levels lower than 23:
@Override
@TargetApi(23)
public void onResume() {
[Link]();
if ([Link].SDK_INT <= Build.VERSION_CODES.M) {
//run Marshmallow code
FingerprintManager fingerprintManager =
[Link]([Link]);
[Link] 153
//......................
}
}
[Link] 154
Chapter 27: Android Vk Sdk
Examples
Initialization and login
5. Add recieved fingerprint into your Signing certificate fingerprint for Android: field in Vk
app settings (where you entered your package name)
compile '[Link]:androidsdk:1.6.5'
8. Initialize the SDK on startup using the following method. The best way is to call it in the
Applications onCreate method.
This is the best way to initizlize VKSdk. Don't use the methid where VK_ID should be placed
inside [Link] because api will not work correctly after it.
[Link] 155
[Link],
[Link],
[Link]
};
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
[Link](new [Link]() {
@Override
public void onClick(View v) {
[Link](this, VK_SCOPES);
}
});
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
[Link](requestCode, resultCode, data);
[Link](requestCode, resultCode, data, new VKCallback<VKAccessToken>()
{
@Override
public void onResult(VKAccessToken res) {
[Link]; //getting our token here.
}
@Override
public void onError(VKError error) {
[Link]([Link],
"User didn't pass Authorization", Toast.LENGTH_SHORT).show();
}
});
}
[Link] 156
Chapter 28: Android-x86 in VirtualBox
Introduction
The idea of this section is to cover how to install and use the VirtualBox with Android-x86 for
debugging purposes. This is a difficult task because there are differences between versions. For
the moment I´m going to cover 6.0 which is the one that I had to work with and then we'll have to
find similarities.
It doesn't cover VirtualBox or a Linux in detail but it shows the commands I've used to make it
work.
Examples
Virtual Machine setup
• OS Type: Linux 2.6 (I've user 64bit because my computer can support it)
• Virtual hard drive size: 4Gb
• Ram Memory: 2048
• Video Memory: 8M
• Sound device: Sound Blaster 16.
• Network device: PCnet-Fast III, attached to NAT. You can also use bridged adapter, but you
need a DHCP server in your environment.
The image used with this configuration has been android-x86_64-[Link] (it is 64bit)
downloaded from [Link] I suppose that it also works with 32bit
version.
With the virtual hard drive just created, boot the virtual machine with the android-x86 image in the
optical drive.
[Link] 157
Once you boot, you can see the grub menu of the Live CD
[Link] 158
Choose the Debug Mode Option, then you should see the shell prompt. This is a busybox shell.
You can get more shell by switching between virtual console Alt-F1/F2/F3.
Create two partitions by fdisk (some other versions would use cfdisk). Format them to ext3. Then
reboot:
# fdisk /dev/sda
Then type:
"261" (choose a cylinder, we'll leave 50% of the disk for a 2nd partition)
[Link] 159
"262" (262nd cylinder)
#mdev -s
#mke2fs -j -L DATA /dev/sda1
#mke2fs -j -L SDCARD /dev/sda2
#reboot -f
When you restart the virtual machine and the grub menu appears and you will be able edit the
kernel boot line so you can add DATA=sda1 SDCARD=sda2 options to point to the sdcard or the data
partition.
Installation in partition
With the virtual hard drive just created, boot the virtual machine with the android-x86 image as the
optical drive.
In the booting options of the Live CD choose "Installation - Install Android to hard disk"
[Link] 160
Choose the sda1 partition and install android and we'll install grub.
Reboot the virtual machine but make sure that the image is not in the optical drive so it can restart
from the virtual hard drive.
In the grub menu we need to edit kernel like in the "Android-x86 6.0-r3" option so press e.
[Link] 161
Then we substitute "quiet" with "vga=ask" and add the option "SDCARD=sda2"
Press b to boot, then you'll be able to choose the screen size pressing ENTER (the vga=ask option)
[Link] 162
Once the installation wizard has started choose the language. I could choose English (United
States) and Spanish (United States) and I had trouble choosing any other.
[Link] 163
Chapter 29: Animated AlertDialog Box
Introduction
Animated Alert Dialog Which display with some animation effects.. You Can Get Some Animation
for dialog box like Fadein, Slideleft, Slidetop, SlideBottom, Slideright, Fall, Newspager, Fliph, Flipv,
RotateBottom, RotateLeft, Slit, Shake, Sidefill to make Your application attractive..
Examples
Put Below code for Animated dialog...
animated_android_dialog_box.xml
<LinearLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#1184be"
android:onClick="animatedDialog1"
android:text="Animated Fall Dialog"
android:textColor="#fff" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:background="#1184be"
android:onClick="animatedDialog2"
android:text="Animated Material Flip Dialog"
android:textColor="#fff" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#1184be"
android:onClick="animatedDialog3"
android:text="Animated Material Shake Dialog"
android:textColor="#fff" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:background="#1184be"
android:onClick="animatedDialog4"
android:text="Animated Slide Top Dialog"
[Link] 164
android:textColor="#fff" />
[Link]
NiftyDialogBuilder materialDesignAnimatedDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].animated_android_dialog_box);
materialDesignAnimatedDialog = [Link](this);
}
[Link] 165
.withDialogColor("#1c90ec")
.withButton1Text("OK")
.withButton2Text("Cancel")
.withDuration(700)
.withEffect([Link])
.show();
}
}
[Link]
dependencies {
compile '[Link]:library:2.4.0'
compile '[Link]:niftydialogeffects:1.0.0@aar'
[Link] 166
Chapter 30: Animators
Examples
Shake animation of an ImageView
Under res folder, create a new folder called "anim" to store your animation resources and put this
on that folder.
[Link]
activity_landing.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imgBell"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/ic_notifications_white_48dp"/>
</RelativeLayout>
Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
mContext=this;
setContentView([Link].activity_landing);
AnimateBell();
}
[Link] 167
Animation shake = [Link](mContext, [Link]);
ImageView imgBell= (ImageView) findViewById([Link]);
[Link]([Link].ic_notifications_active_white_48dp);
[Link](shake);
}
In order to get a view to slowly fade in or out of view, use an ObjectAnimator. As seen in the code
below, set a duration using .setDuration(millis) where the millis parameter is the duration (in
milliseconds) of the animation. In the below code, the views will fade in / out over 500
milliseconds, or 1/2 second. To start the ObjectAnimator's animation, call .start(). Once the
animation is complete, onAnimationEnd(Animator animation) is called. Here is a good place to set
your view's visibility to [Link] or [Link].
import [Link];
import [Link];
import [Link];
[Link](500);
[Link](new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// We wanna set the view to GONE, after it's fade out. so it actually disappear
from the layout & don't take up space.
[Link]([Link]);
}
});
[Link]();
}
[Link](new AnimatorListenerAdapter() {
@Override
public void onAnimationStar(Animator animation) {
// We wanna set the view to VISIBLE, but with alpha 0. So it appear invisible in
the layout.
[Link]([Link]);
[Link](0);
}
});
[Link]();
}
TransitionDrawable animation
This example displays a transaction for an image view with only two images.(can use more
images as well one after the other for the first and second layer positions after each transaction as
[Link] 168
a loop)
<resources>
<array
name="splash_images">
<item>@drawable/spash_imge_first</item>
<item>@drawable/spash_img_second</item>
</array>
</resources>
@SuppressWarnings("ResourceType")
Drawable drawable = [Link](0); // ending image
@SuppressWarnings("ResourceType")
Drawable drawableTwo = [Link](1); // starting image
ValueAnimator
ValueAnimator introduces a simple way to animate a value (of a particular type, e.g. int, float, etc.).
[Link] 169
There are two ways you can create the ValueAnimator:
<animator xmlns:android="[Link]
android:duration="250"
android:valueFrom="20"
android:valueTo="40"
android:valueType="floatType"/>
ObjectAnimator
ObjectAnimator is a subclass of ValueAnimator with the added ability to set the calculated value to
the property of a target View.
Just like in the ValueAnimator, there are two ways you can create the ObjectAnimator:
(the example code animates an alpha of a View from 0.4f to 0.2f in 250ms)
<objectAnimator xmlns:android="[Link]
android:duration="250"
android:propertyName="alpha"
android:valueFrom="0.4"
android:valueTo="0.2"
android:valueType="floatType"/>
[Link] 170
ObjectAnimator animator = (ObjectAnimator) [Link](context,
[Link].example_animator);
[Link](exampleView);
// set all the animation-related stuff you want (interpolator etc.)
[Link]();
2. From code:
ViewPropertyAnimator
Every single View has a ViewPropertyAnimator object available through the animate() method. You
can use that to animate multiple properties at once with a simple call. Every single method of a
ViewPropertyAnimator specifies the target value of a specific parameter that the
ViewPropertyAnimator should animate to.
Note: Calling start() on a ViewPropertyAnimator object is NOT mandatory. If you don't do that
you're just letting the platform to handle the starting of the animation in the appropriate time (next
animation handling pass). If you actually do that (call start()) you're making sure the animation is
started immediately.
[Link]().height = 0;
[Link]([Link]);
Animation a = new Animation()
{
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
[Link]().height = interpolatedTime == 1
? LayoutParams.WRAP_CONTENT
: (int)(targtetHeight * interpolatedTime);
[Link] 171
[Link]();
}
@Override
public boolean willChangeBounds() {
return true;
}
};
[Link]((int)(targtetHeight /
[Link]().getResources().getDisplayMetrics().density));
[Link](a);
}
@Override
public boolean willChangeBounds() {
return true;
}
};
[Link]((int)(initialHeight /
[Link]().getResources().getDisplayMetrics().density));
[Link](a);
}
}
[Link] 172
Chapter 31: Annotation Processor
Introduction
Annotation processor is a tool build in javac for scanning and processing annotations at compile
time.
Annotations are a class of metadata that can be associated with classes, methods, fields, and
even other [Link] are two ways to access these annotations at runtime via reflection
and at compile time via annotation processors.
Examples
@NonNull Annotation
Here @NonNull is annotation which is processed compile time by the android studio to warn you
that the particular function needs non null parameter.
Types of Annotations
@interface CustomAnnotation {}
@interface CustomAnnotation {
int value();
}
@interface CustomAnnotation{
int value1();
String value2();
String value3();
}
[Link] 173
Creating and Using Custom Annotations
• Target - on which these annotations will work on like field level, method level, type level etc.
• Retention - to what level annotation will be available.
For this, we have built in custom annotations. Check out these mostly used ones:
@Target
@Retention
[Link] 174
Creating Custom Annotation
class Foo{
@CustomAnnotation(value = 1) // will be used by an annotation processor
public void foo(){..}
}
[Link] 175
Chapter 32: AsyncTask
Parameters
Parameter Details
Params the type of the parameters sent to the task upon execution.
Progress the type of the progress units published during the background computation
Examples
Basic Usage
In Android Activities and Services, most callbacks are run on the main thread. This makes it
simple to update the UI, but running processor- or I/O-heavy tasks on the main thread can cause
your UI to pause and become unresponsive (official documentation on what then happens).
You can remedy this by putting these heavier tasks on a background thread.
One way to do this is using an AsyncTask, which provides a framework to facilitate easy usage of
a background Thread, and also perform UI Thread tasks before, during, and after the background
Thread has completed its work.
Example
public class MyCustomAsyncTask extends AsyncTask<File, Void, String> {
@Override
protected void onPreExecute(){
// This runs on the UI thread before the background thread executes.
[Link]();
// Do pre-thread tasks such as initializing variables.
Log.v("myBackgroundTask", "Starting Background Task");
}
[Link] 176
@Override
protected String doInBackground(File... params) {
// Disk-intensive work. This runs on a background thread.
// Search through a file for the first line that contains "Hello", and return
// that line.
try (Scanner scanner = new Scanner(params[0])) {
while ([Link]()) {
final String line = [Link]();
publishProgress(); // tell the UI thread we made progress
if ([Link]("Hello")) {
return line;
}
}
return null;
}
}
@Override
protected void onProgressUpdate(Void...p) {
// Runs on the UI thread after publishProgress is invoked
Log.v("Read another line!")
}
@Override
protected void onPostExecute(String s) {
// This runs on the UI thread after complete execution of the doInBackground() method
// This function receives result(String s) returned from the doInBackground() method.
// Update UI with the found string.
TextView view = (TextView) findViewById([Link].found_string);
if (s != null) {
[Link](s);
} else {
[Link]("Match not found.");
}
}
Usage:
MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
[Link](userSuppliedFilename);
or simply:
new MyCustomAsyncTask().execute(userSuppliedFilename);
Note
When defining an AsyncTask we can pass three types between < > brackets.
[Link] 177
Defined as <Params, Progress, Result> (see Parameters section)
Note that you can't pass primitive types (i.e. int, float and 6 others) as parameters. In such cases,
you should pass their wrapper classes, e.g. Integer instead of int, or Float instead of float.
AsyncTasks don't follow Activity instances' life cycle. If you start an AsyncTask inside an Activity
and you rotate the device, the Activity will be destroyed and a new instance will be created. But
the AsyncTask will not die. It will go on living until it completes.
Solution: AsyncTaskLoader
One subclass of Loaders is the AsyncTaskLoader. This class performs the same function as the
AsyncTask, but much better. It can handle Activity configuration changes more easily, and it
behaves within the life cycles of Fragments and Activities. The nice thing is that the
AsyncTaskLoader can be used in any situation that the AsyncTask is being used. Anytime data
needs to be loaded into memory for the Activity/Fragment to handle, The AsyncTaskLoader can
do the job better.
Canceling AsyncTask
This doesn't stop your task if it was in progress, it just sets the cancelled flag which can be
checked by checking the return value of isCancelled() (assuming your code is currently running)
by doing this:
[Link] 178
}
}
Note
If an AsyncTask is canceled while doInBackground(Params... params) is still executing then the
method onPostExecute(Result result) will NOT be called after doInBackground(Params... params)
returns. The AsyncTask will instead call the onCancelled(Result result) to indicate that the task
was cancelled during execution.
Publishing progress
Sometimes, we need to update the progress of the computation done by an AsyncTask. This
progress could be represented by a string, an integer, etc. To do this, we have to use two
functions. First, we need to set the onProgressUpdate function whose parameter type is the same as
the second type parameter of our AsyncTask.
Second, we have to use the function publishProgress necessarily on the doInBackground function,
and that is all, the previous method will do all the job.
This tutorial explains how to download Image using AsyncTask in Android. The example below
download image while showing progress bar while during download.
[Link] 179
• AsyncTasks should ideally be used for short operations (a few seconds at the most.)
• An asynchronous task is defined by 3 generic types, called Params, Progress and Result,
and 4 steps, called onPreExecute(), doInBackground(), onProgressUpdate() and onPostExecute().
• In onPreExecute() you can define code, which need to be executed before background
processing starts.
• doInBackground have code which needs to be executed in background, here in
doInBackground() we can send results to multiple times to event thread by publishProgress()
method, to notify background processing has been completed we can return results simply.
• onProgressUpdate() method receives progress updates from doInBackground() method, which
is published via publishProgress() method, and this method can use this progress update to
update event thread
• onPostExecute() method handles results returned by doInBackground() method.
• The generic types used are
○Params, the type of the parameters sent to the task upon execution
○Progress, the type of the progress units published during the background computation.
○Result, the type of the result of the background computation.
• If an async task not using any types, then it can be marked as Void type.
• An running async task can be cancelled by calling cancel(boolean) method.
<LinearLayout
xmlns:android="[Link]
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/downloadButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click Here to Download" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="Your image will appear here" />
</LinearLayout>
.java class
package [Link];
import [Link];
import [Link];
import [Link];
[Link] 180
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Override
public void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link]);
Button imageDownloaderBtn = (Button) findViewById([Link]);
[Link](new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new ImageDownloader().execute(downloadUrl);
}
});
}
@Override
protected Bitmap doInBackground(String... param) {
// TODO Auto-generated method stub
return downloadBitmap(param[0]);
}
@Override
protected void onPreExecute() {
Log.i("Async-Example", "onPreExecute Called");
simpleWaitDialog = [Link]([Link],
"Wait", "Downloading Image");
@Override
protected void onPostExecute(Bitmap result) {
Log.i("Async-Example", "onPostExecute Called");
[Link](result);
[Link]();
[Link] 181
}
if (statusCode != HttpStatus.SC_OK) {
Log.w("ImageDownloader", "Error " + statusCode +
" while retrieving bitmap from " + url);
return null;
return bitmap;
} finally {
if (inputStream != null) {
[Link]();
}
[Link]();
}
}
} catch (Exception e) {
// You Could provide a more explicit error message for IOException
[Link]();
Log.e("ImageDownloader", "Something went wrong while" +
" retrieving bitmap from " + url + [Link]());
}
return null;
}
}
}
Since there is currently no comment field for examples (or I haven't found it or I haven't permission
for it) here is some comment about this:
[Link] 182
However the example currently has problems with
It is common for an AsyncTask to require a reference to the Activity that called it.
If the AsyncTask is an inner class of the Activity, then you can reference it and any member
variables/methods directly.
If, however, the AsyncTask is not an inner class of the Activity, you will need to pass an Activity
reference to the AsyncTask. When you do this, one potential problem that may occur is that the
AsyncTask will keep the reference of the Activity until the AsyncTask has completed its work in its
background thread. If the Activity is finished or killed before the AsyncTask's background thread
work is done, the AsyncTask will still have its reference to the Activity, and therefore it cannot be
garbage collected.
In order to prevent this from happening, make use of a WeakReference in the AsyncTask instead
of having a direct reference to the Activity.
@Override
protected void onPreExecute() {
final Activity activity = [Link]();
if (activity != null) {
....
}
}
@Override
protected Void doInBackground(String... params) {
//Do something
String param1 = params[0];
[Link] 183
String param2 = params[1];
return null;
}
@Override
protected void onPostExecute(Void result) {
final Activity activity = [Link]();
if (activity != null) {
[Link]();
}
}
}
Order of execution
When first introduced, AsyncTasks were executed serially on a single background thread. Starting
with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel.
Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors
caused by parallel execution.
SERIAL_EXECUTOR -> An Executor that executes tasks one at a time in serial order.
sample :
AsyncTask is an abstract Class and does not inherit the Thread class. It has an abstract method
doInBackground(Params... params), which is overridden to perform the task. This method is called
from [Link]().
[Link] 184
Moreover, AsyncTask contains 2 Executors
THREAD_POOL_EXECUTOR
SERIAL_EXECUTOR
Both Executors are static, hence only one THREAD_POOL_EXECUTOR and one SerialExecutor objects
exist, but you can create several AsyncTask objects.
Therefore, if you try to do multiple background task with the default Executor (SerialExecutor),
these task will be queue and executed serially.
If you try to do multiple background task with THREAD_POOL_EXECUTOR, then they will be executed
parallelly.
Example:
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
bt = (Button) findViewById([Link]);
[Link](new [Link]() {
@Override
public void onClick(View v) {
BackgroundTask backgroundTask = new BackgroundTask ();
Integer data[] = { ++CountTask, null, null };
}
});
[Link] 185
private class BackgroundTask extends AsyncTask<Integer, Integer, Integer> {
int taskNumber;
@Override
protected Integer doInBackground(Integer... integers) {
taskNumber = integers[0];
try {
[Link](1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
[Link]();
}
publishProgress(taskNumber);
return null;
}
@Override
protected void onPreExecute() {
[Link]();
}
@Override
protected void onPostExecute(Integer aLong) {
[Link](aLong);
}
@Override
protected void onProgressUpdate(Integer... values) {
[Link](values);
Log.d(TAG, "Task = " + (int) values[0]
+ " Task Execution Completed");
}
}
}
Perform Click on button several times to start a task and see the result.
At t=36s, tasks 2, 3 and 4 are queued and started executing also because they are executing
parallelly.
[Link] 186
08-02 [Link]**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Queued
08-02 [Link]**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Running in Background
08-02 [Link].025: D/AsyncTaskExample(11693): Task = 2 Task Execution Completed
08-02 [Link].165: D/AsyncTaskExample(11693): Task = 3 Task Execution Completed
----------
Comment Task Executed in thread pool (1) and uncomment Task executed Serially (2).
Perform Click on button several times to start a task and see the result.
It is executing the task serially hence every task is started after the current task completed
execution. Hence when Task 1's execution completes, only Task 2 starts running in background.
Vice versa.
[Link] 187
Chapter 33: AudioManager
Examples
Requesting Transient Audio Focus
[Link](audioListener, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
[Link](audioListener, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
[Link] 188
Chapter 34: AudioTrack
Examples
Generate tone of a specific frequency
To play a sound of with a specific tone,we first have to create a sine wave [Link] is done in
the following way.
Now we have to configure AudioTrack to play in accordance with the generated buffer . It is done
in the following manner
[Link](buffer, 0, [Link]);
[Link]();
[Link] 189
Chapter 35: AutoCompleteTextView
Remarks
If you want to offer suggestions to the user when they type in an editable text field, you can use an
AutoCompleteTextView. It provides suggestions automatically when the user is typing. The list of
suggestions is displayed in a drop down menu from which the user can select one to replace the
contents of the edit box.
Examples
Simple, hard-coded AutoCompleteTextView
<AutoCompleteTextView
android:id="@+id/autoCompleteTextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="65dp"
android:ems="10" />
Find the view in code after setContentView() (or its fragment or custom view equivalent):
Tip: Though the preferred way would be to provide data via a Loader of some kind instead of a
hard-coded list like this.
[Link] 190
<AutoCompleteTextView
android:id="@+id/auto_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="2"
android:hint="@string/hint_enter_name" />
</LinearLayout>
<TextView
android:id="@+id/lbl_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="16dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
[Link]
<resources>
<string name="hint_enter_name">Enter Name</string>
</resources>
[Link]
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
mList = retrievePeople();
txtSearch = (AutoCompleteTextView) findViewById([Link].auto_name);
adapter = new PeopleAdapter(this, [Link].activity_main, [Link].lbl_name, mList);
[Link](adapter);
[Link](new [Link]() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int pos, long id) {
//this is the way to find selected object/item
selectedPerson = (People) [Link](pos);
[Link] 191
}
});
}
[Link] 192
Adapter class : [Link]
Context context;
int resource, textViewResourceId;
List<People> items, tempItems, suggestions;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater)
[Link](Context.LAYOUT_INFLATER_SERVICE);
view = [Link]([Link], parent, false);
}
People people = [Link](position);
if (people != null) {
TextView lblName = (TextView) [Link]([Link].lbl_name);
if (lblName != null)
[Link]([Link]());
}
return view;
}
@Override
public Filter getFilter() {
return nameFilter;
}
/**
* Custom Filter implementation for custom suggestions we provide.
*/
Filter nameFilter = new Filter() {
@Override
public CharSequence convertResultToString(Object resultValue) {
String str = ((People) resultValue).getName();
return str;
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
if (constraint != null) {
[Link]();
for (People people : tempItems) {
if
([Link]().toLowerCase().contains([Link]().toLowerCase())) {
[Link](people);
}
[Link] 193
}
FilterResults filterResults = new FilterResults();
[Link] = suggestions;
[Link] = [Link]();
return filterResults;
} else {
return new FilterResults();
}
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
List<People> filterList = (ArrayList<People>) [Link];
if (results != null && [Link] > 0) {
clear();
for (People people : filterList) {
add(people);
notifyDataSetChanged();
}
}
}
};
}
[Link] 194
Chapter 36: Autosizing TextViews
Introduction
A TextView that automatically resizes text to fit perfectly within its bounds.
Android O allows you to instruct a TextView to let the size of the text expand or contract
automatically to fill its layout based on the TextView’s characteristics and boundaries.
There are two ways to set autosizing TextView: Granularity and Preset Sizes
Examples
Granularity
In Java:
In XML:
<TextView android:id=”@+id/autosizing_textview_presetsize”
android:layout_width=”wrap_content”
android:layout_height=”250dp”
android:layout_marginLeft=”0dp”
android:layout_marginTop=”0dp”
android:autoSizeMaxTextSize=”100sp”
android:autoSizeMinTextSize=”12sp”
android:autoSizeStepGranularity=”2sp”
android:autoSizeText=”uniform”
android:text=”Hello World!”
android:textSize=”100sp”
app:layout_constraintLeft_toLeftOf=”parent”
app:layout_constraintTop_toTopOf=”parent” />
Preset Sizes
In Java:
[Link] 195
Call the setAutoSizeTextTypeUniformWithPresetSizes() method:
In XML:
<TextView android:id=”@+id/autosizing_textview_presetsize”
android:layout_width=”wrap_content”
android:layout_height=”250dp”
android:layout_marginLeft=”0dp”
android:layout_marginTop=”0dp”
android:autoSizeText=”uniform”
android:autoSizePresetSizes=”@array/autosize_text_sizes”
android:text=”Hello World!”
android:textSize=”100sp”
app:layout_constraintLeft_toLeftOf=”parent”
app:layout_constraintTop_toTopOf=”parent” />
To access the array as a resource, define the array in the res/values/[Link] file:
<array name=”autosize_text_sizes”>
<item>10sp</item>
<item>12sp</item>
<item>20sp</item>
<item>40sp</item>
<item>100sp</item>
</array>
[Link] 196
Chapter 37: Barcode and QR code reading
Remarks
QRCodeReaderView
Zxing
Examples
Using QRCodeReaderView (based on Zxing)
QRCodeReaderView implements an Android view which show camera and notify when there's a
QR code inside the preview.
It uses the zxing open-source, multi-format 1D/2D barcode image processing library.
dependencies{
compile '[Link]:qrcodereaderview:2.0.0'
}
First use
• Add to your layout a QRCodeReaderView
<[Link]
android:id="@+id/qrdecoderview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
[Link] 197
private QRCodeReaderView qrCodeReaderView;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_decoder);
@Override
protected void onResume() {
[Link]();
[Link]();
}
@Override
protected void onPause() {
[Link]();
[Link]();
}
}
[Link] 198
Chapter 38: Bitmap Cache
Introduction
Memory efficient bitmap caching: This is particularly important if your application uses animations
as they will be stopped during GC cleanup and make your application appears sluggish to the
user. A cache allows reusing objects which are expensive to create. If you load on object into
memory, you can think of this as a cache for the [Link] with bitmap in android is [Link] is
more important to cache the bimap if you are going to use it repeatedly.
Syntax
• LruCache<String, Bitmap> mMemoryCache;//declaration of LruCache object.
• void addBitmapToMemoryCache(String key, Bitmap bitmap){}//declaration of generic method
adding bitmap into cache memory
• Bitmap getBitmapFromMemCache(String key){}//declaration of generic method for get bimap
from cache.
Parameters
Parameter Details
Examples
Bitmap Cache Using LRU Cache
LRU Cache
The following example code demonstrates a possible implementation of the LruCache class for
caching images.
[Link] 199
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;
[Link] 200
Chapter 39: Bluetooth and Bluetooth LE API
Remarks
Bluetooth Classic is available from Android 2.0 (API level 5) and above. Bluetooth LE is available
from Android 4.3 (API level 18) and above.
Examples
Permissions
Add this permission to the manifest file to use Bluetooth features in your application:
If you need to initiate device discovery or manipulate Bluetooth settings, you also need to add this
permission:
Targetting Android API level 23 and above, will require location access:
* Also see the Permissions topic for more details on how to use permissions appropriately.
// ...
if (![Link]()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
// ...
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent
data) {
[Link](requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {
[Link] 201
// Bluetooth was enabled
} else if (resultCode == RESULT_CANCELED) {
// Bluetooth was not enabled
}
}
}
// ...
// ...
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent
data) {
[Link](requestCode, resultCode, data);
if (requestCode == REQUEST_DISCOVERABLE_BT) {
if (resultCode == RESULT_OK) {
// Device is discoverable
} else if (resultCode == RESULT_CANCELED) {
// Device is not discoverable
}
}
}
BluetoothAdapter mBluetoothAdapter;
//Device found
if (BluetoothDevice.ACTION_FOUND.equals(action))
{
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = [Link](BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a list
[Link]([Link]() + "\n" + [Link]());
[Link] 202
}
}
};
[Link]();
unregisterReceiver(mReceiver);
After you obtained BluetoothDevice, you can communicate with it. This kind of communication
performed by using socket input\output streams:
1) Initialize socket:
2) Connect to socket:
try {
_socket.connect();
} catch (IOException connEx) {
try {
_socket.close();
} catch (IOException closeException) {
//Error
}
}
[Link] 203
3) Obtaining socket Input\Output streams
Input stream - Used as incoming data channel (receive data from connected device)
Output stream - Used as outgoing data channel (send data to connected device)
After finishing 3rd step, we can receive and send data between both devices using
previously initialized streams:
while (true) {
try {
//reading data from input stream
bytesCount = _inStream.read(buffer);
if(buffer != null && bytesCount > 0)
{
//Parse received bytes
}
} catch (IOException e) {
//Error
}
}
The BluetoothLE API was introduced in API 18. However, the way of scanning devices has
[Link] 204
changed in API 21. The searching of devices must start with defining the service UUID that is to
be scanned (either officailly adopted 16-bit UUID's or proprietary ones). This example illustrates,
how to make an API independent way of searching for BLE devices:
public BluetoothScanningFactory() {
if (isNewerAPI()) {
mScanningAdapter = new LollipopBluetoothLEScanAdapter();
} else {
mScanningAdapter = new JellyBeanBluetoothLEScanAdapter();
}
}
@Override
public void startScanning(String[] uuids) {
[Link](uuids);
[Link] 205
}
@Override
public void stopScanning() {
[Link]();
}
@Override
public List<BTDevice> getFoundDeviceList() {
return [Link]();
}
}
API 18:
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class JellyBeanBluetoothLEScanAdapter implements ScanningAdapter{
BluetoothAdapter bluetoothAdapter;
ScanCallback mCallback;
List<BTDevice> mBluetoothDeviceList;
public JellyBeanBluetoothLEScanAdapter() {
bluetoothAdapter = [Link]();
mCallback = new ScanCallback();
mBluetoothDeviceList = new ArrayList<>();
}
@Override
public void startScanning(String[] uuids) {
if (uuids == null || [Link] == 0) {
return;
}
UUID[] uuidList = createUUIDList(uuids);
[Link](uuidList, mCallback);
}
[Link] 206
}
return uuidList;
}
@Override
public void stopScanning() {
[Link](mCallback);
}
@Override
public List<BTDevice> getFoundDeviceList() {
return mBluetoothDeviceList;
}
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (isAlreadyAdded(device)) {
return;
}
BTDevice btDevice = new BTDevice();
[Link](new String([Link]()));
[Link]([Link]());
[Link](btDevice);
Log.d("Bluetooth discovery", [Link]() + " " + [Link]());
Parcelable[] uuids = [Link]();
String uuid = "";
if (uuids != null) {
for (Parcelable ep : uuids) {
uuid += ep + " ";
}
Log.d("Bluetooth discovery", [Link]() + " " + [Link]() + "
" + uuid);
}
}
API 21:
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
[Link] 207
import [Link];
import [Link];
import [Link];
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class LollipopBluetoothLEScanAdapter implements ScanningAdapter {
BluetoothLeScanner bluetoothLeScanner;
ScanCallback mCallback;
List<BTDevice> mBluetoothDeviceList;
public LollipopBluetoothLEScanAdapter() {
bluetoothLeScanner = [Link]().getBluetoothLeScanner();
mCallback = new ScanCallback();
mBluetoothDeviceList = new ArrayList<>();
}
@Override
public void startScanning(String[] uuids) {
if (uuids == null || [Link] == 0) {
return;
}
List<ScanFilter> filterList = createScanFilterList(uuids);
ScanSettings scanSettings = createScanSettings();
[Link](filterList, scanSettings, mCallback);
}
@Override
public void stopScanning() {
[Link](mCallback);
}
@Override
public List<BTDevice> getFoundDeviceList() {
return mBluetoothDeviceList;
}
@Override
public void onScanResult(int callbackType, ScanResult result) {
[Link] 208
[Link](callbackType, result);
if (result == null) {
return;
}
BTDevice device = new BTDevice();
[Link]([Link]().getAddress());
[Link](new
StringBuffer([Link]().getDeviceName()).toString());
if (device == null || [Link]() == null) {
return;
}
if (isAlreadyAdded(device)) {
return;
}
[Link](device);
}
[Link]({uuidlist});
[Link] 209
Chapter 40: Bluetooth Low Energy
Introduction
This documentation is meant as an enhancement over the original documentation and it will focus
on the latest Bluetooth LE API introduced in Android 5.0 (API 21). Both Central and Peripheral
roles will be covered as well as how to start scanning and advertising operations.
Examples
Finding BLE Devices
[Link]
[Link].BLUETOOTH_ADMIN
If you're targeting devices with Android 6.0 (API Level 23) or higher and want to perform
scanning/advertising operations you will require a Location permission:
[Link].ACCESS_FINE_LOCATION
or
[Link].ACCESS_COARSE_LOCATION
Note.- Devices with Android 6.0 (API Level 23) or higher also need to have Location
Services enabled.
The startScan (ScanCallback callback)method of the BluetoothLeScanner class is the most basic
way to start a scanning operation. A ScanCallback object is required to receive results:
[Link]().startScan(new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
[Link](callbackType, result);
Log.i(TAG, "Remote device name: " + [Link]().getName());
}
});
[Link] 210
Connecting to a GATT Server
Once you have discovered a desired BluetoothDevice object, you can connect to it by using its
connectGatt() method which takes as parameters a Context object, a boolean indicating whether to
automatically connect to the BLE device and a BluetoothGattCallback reference where connection
events and client operations results will be delivered:
BluetoothGattCallback bluetoothGattCallback =
new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i(TAG, "Connected to GATT server.");
Once you are connected to a Gatt Server, you're going to be interacting with it by writing and
reading from the server's characteristics. To do this, first you have to discover what services are
available on this server and which characteristics are avaiable in each service:
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i(TAG, "Connected to GATT server.");
[Link]();
}
. . .
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
List<BluetoothGattService> services = [Link]();
for (BluetoothGattService service : services) {
List<BluetoothGattCharacteristic> characteristics =
[Link] 211
[Link]();
for (BluetoothGattCharacteristic characteristic : characteristics) {
///Once you have a characteristic object, you can perform read/write
//operations with it
}
}
}
}
[Link](newValue);
[Link](BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
[Link](characteristic);
When the write process has finished, the onCharacteristicWrite method of your
BluetoothGattCallback will be called:
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic, int status) {
[Link](gatt, characteristic, status);
Log.d(TAG, "Characteristic " + [Link]() + " written);
}
[Link](characteristic);
When the write process has finished, the onCharacteristicRead method of your
BluetoothGattCallback will be called:
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic, int status) {
[Link](gatt, characteristic, status);
byte[] value = [Link]();
}
You can request to be notified from the Gatt Server when the value of a characteristic has been
changed:
[Link](characteristic, true);
BluetoothGattDescriptor descriptor = [Link](
[Link]("00002902-0000-1000-8000-00805f9b34fb");
[Link](BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
[Link](descriptor);
All notifications from the server will be received in the onCharacteristicChanged method of your
BluetoothGattCallback:
[Link] 212
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic) {
[Link](gatt, characteristic);
byte[] newValue = [Link]();
}
You can use Bluetooth LE Advertising to broadcast data packages to all nearby devices without
having to establish a connection first. Bear in mind that there's a strict limit of 31 bytes of
advertisement data. Advertising your device is also the first step towards letting other users
connect to you.
Since not all devices support Bluetooth LE Advertising, the first step is to check that your device
has all the necessary requirements to support it. Afterwards, you can initialize a
BluetoothLeAdvertiser object and with it, you can start advertising operations:
@Override
public void onStartFailure(int errorCode) {
[Link](errorCode);
Log.e(TAG, "onStartFailure: "+errorCode );
}
};
[Link]([Link](),[Link](),advertiseCallback);
}
In order for your device to act as a peripheral, first you need to open a BluetoothGattServer and
[Link] 213
populate it with at least one BluetoothGattService and one BluetoothGattCharacteristic:
BluetoothGattServer server=[Link](context,
bluetoothGattServerCallback);
[Link](new BluetoothGattDescriptor([Link]("00002902-0000-1000-
8000-00805f9b34fb"), BluetoothGattCharacteristic.PERMISSION_WRITE));
[Link](characteristic);
[Link](service);
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
int offset, BluetoothGattCharacteristic characteristic) {
[Link](device, requestId, offset,
characteristic);
}
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int
requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean
responseNeeded, int offset, byte[] value) {
[Link](device, requestId, characteristic,
preparedWrite, responseNeeded, offset, value);
}
@Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int
offset, BluetoothGattDescriptor descriptor) {
[Link](device, requestId, offset, descriptor);
}
[Link] 214
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset,
byte[] value) {
[Link](device, requestId, descriptor,
preparedWrite, responseNeeded, offset, value);
}
Whenever you receive a request for a write/read to a characteristic or descriptor you must send a
response to it in order for the request to be completed succesfully :
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
BluetoothGattCharacteristic characteristic) {
[Link](device, requestId, offset, characteristic);
[Link](device, requestId, BluetoothGatt.GATT_SUCCESS, offset, YOUR_RESPONSE);
}
[Link] 215
Chapter 41: Bottom Sheets
Introduction
A bottom sheet is a sheet that slides up from the bottom edge of the screen.
Remarks
Bottom sheets slide up from the bottom of the screen to reveal more content.
They were added to the Android Support Library in v23.2.0 version.
Examples
BottomSheetBehavior like Google maps
2.1.x
BottomSheetBehavior is characterized by :
1. Two toolbars with animations that respond to the bottom sheet movements.
2. A FAB that hides when it is near to the "modal toolbar" (the one that appears when you are
sliding up).
3. A backdrop image behind bottom sheet with some kind of parallax effect.
4. A Title (TextView) in Toolbar that appears when bottom sheet reach it.
5. The notification satus bar can turn its background to transparent or full color.
6. A custom bottom sheet behavior with an "anchor" state.
ToolBars
When you open that view in Google Maps, you can see a toolbar in where you can search, it's the
only one that I'm not doing exactly like Google Maps, because I wanted to do it more generic.
Anyway that ToolBar is inside an AppBarLayout and it got hidden when you start dragging the
BottomSheet and it appears again when the BottomSheet reach the COLLAPSED state.
To achieve it you need to:
[Link] 216
This is how I did it for first toolbar or ActionBar:
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof NestedScrollView;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
View dependency) {
if (mChild == null) {
initValues(child, dependency);
return false;
}
//going up
if (dVerticalScroll <= 0 && !hidden) {
dismissAppBar(child);
return true;
}
return false;
}
mChild = child;
mInitialY = [Link]();
BottomSheetBehaviorGoogleMapsLike bottomSheetBehavior =
[Link](dependency);
[Link](new
[Link]() {
@Override
public void onStateChanged(@NonNull View bottomSheet,
@[Link] int newState) {
if (newState == BottomSheetBehaviorGoogleMapsLike.STATE_COLLAPSED ||
newState == BottomSheetBehaviorGoogleMapsLike.STATE_HIDDEN)
showAppBar(child);
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
}
mToolbarAnimation.y(-([Link]()+25)).start();
}
[Link] 217
private void showAppBar(View child) {
hidden = false;
AppBarLayout appBarLayout = (AppBarLayout)child;
mToolbarAnimation =
[Link]().setDuration([Link]().getInteger([Link].config_mediumAn
mToolbarAnimation.y(mInitialY).start();
}
The code for this one is a little extensive, so I will let the link
The FAB
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child,
View dependency) {
if (offset == 0)
setOffsetValue(parent);
if ([Link]() <=0)
return false;
return false;
}
[Link] 218
Like the others, it's a custom behavior, the only "complicated" thing in this one is the little algorithm
that keeps the image anchored to the BottomSheet and avoid the image collapse like default
parallax effect:
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
View dependency) {
if (mYmultiplier == 0) {
initValues(child, dependency);
return true;
}
//going up
if (dVerticalScroll <= 0 && [Link]() <= 0) {
[Link](0);
return true;
}
//going down
if (dVerticalScroll >= 0 && [Link]() <= mImageHeight)
return false;
return true;
}
2. Copy paste code from default BottomSheetBehavior file to your new one.
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
[Link] 219
}
int constrain(int amount, int low, int high) {
return amount < low ? low : (amount > high ? high : amount);
}
[Link] 220
int top;
int targetState;
if (mLastNestedScrollDy > 0) {
//top = mMinOffset;
//targetState = STATE_EXPANDED;
int currentTop = [Link]();
if (currentTop > mAnchorPoint) {
top = mAnchorPoint;
targetState = STATE_ANCHOR_POINT;
}
else {
top = mMinOffset;
targetState = STATE_EXPANDED;
}
} else if (mHideable && shouldHide(child, getYVelocity())) {
top = mParentHeight;
targetState = STATE_HIDDEN;
} else if (mLastNestedScrollDy == 0) {
int currentTop = [Link]();
if ([Link](currentTop - mMinOffset) < [Link](currentTop - mMaxOffset)) {
top = mMinOffset;
targetState = STATE_EXPANDED;
} else {
top = mMaxOffset;
targetState = STATE_COLLAPSED;
}
} else {
//top = mMaxOffset;
//targetState = STATE_COLLAPSED;
int currentTop = [Link]();
if (currentTop > mAnchorPoint) {
top = mMaxOffset;
targetState = STATE_COLLAPSED;
}
else {
top = mAnchorPoint;
targetState = STATE_ANCHOR_POINT;
}
}
if ([Link](child, [Link](), top)) {
setStateInternal(STATE_SETTLING);
[Link](child, new SettleRunnable(child, targetState));
} else {
setStateInternal(targetState);
}
mNestedScrolled = false;
}
[Link] 221
}
return;
}
V child = [Link]();
if (child == null) {
return;
}
int top;
if (state == STATE_COLLAPSED) {
top = mMaxOffset;
} else if (state == STATE_ANCHOR_POINT) {
top = mAnchorPoint;
} else if (state == STATE_EXPANDED) {
top = mMinOffset;
} else if (mHideable && state == STATE_HIDDEN) {
top = mParentHeight;
} else {
throw new IllegalArgumentException("Illegal state argument: " + state);
}
setStateInternal(STATE_SETTLING);
if ([Link](child, [Link](), top)) {
[Link](child, new SettleRunnable(child, state));
}
}
Link to the whole project where you can see all the Custom Behaviors
[Link] 222
]
Quick Setup
Make sure the following dependency is added to your app's [Link] file under dependencies:
compile '[Link]:design:25.3.1'
Then you can use the Bottom sheet using these options:
You can achieve a Persistent Bottom Sheet attaching a BottomSheetBehavior to a child View of a
CoordinatorLayout:
<[Link] >
[Link] 223
<!-- ..... -->
<LinearLayout
android:id="@+id/bottom_sheet"
android:elevation="4dp"
android:minHeight="120dp"
app:behavior_peekHeight="120dp"
...
app:layout_behavior="[Link]">
</LinearLayout>
</[Link]>
You can set the state of your BottomSheetBehavior using the setState() method:
[Link](BottomSheetBehavior.STATE_EXPANDED);
• STATE_COLLAPSED:this collapsed state is the default and shows just a portion of the layout
along the bottom. The height can be controlled with the app:behavior_peekHeight attribute
(defaults to 0)
• STATE_EXPANDED: the fully expanded state of the bottom sheet, where either the whole bottom
sheet is visible (if its height is less than the containing CoordinatorLayout) or the entire
CoordinatorLayout is filled
If you’d like to receive callbacks of state changes, you can add a BottomSheetCallback:
[Link](new BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
// React to state change
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
// React to dragging events
}
});
[Link] 224
Modal bottom sheets with BottomSheetDialogFragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return [Link]([Link].my_fragment_bottom_sheet, container);
}
}
Just use:
[Link] 225
[Link](new [Link]() {
@Override
public void onShow(DialogInterface dialog) {
BottomSheetDialog d = (BottomSheetDialog) dialog;
[Link](bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
}
});
Although dialog animation is slightly noticeable but does the task of opening the DialogFragment
in full screen very well.
[Link] 226
Chapter 42: BottomNavigationView
Introduction
The Bottom Navigation View has been in the material design guidelines for some time, but it hasn’t
been easy for us to implement it into our apps.
Some applications have built their own solutions, whilst others have relied on third-party open-
source libraries to get the job done.
Now the design support library is seeing the addition of this bottom navigation bar, let’s take a dive
into how we can use it!
Remarks
Represents a standard bottom navigation bar for application. It is an implementation of material
design bottom navigation.
Links:
• Official Javadoc
Examples
Basic implemetation
compile '[Link]:design:25.1.0'
<[Link]
xmlns:android="[Link]
xmlns:app="[Link]
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_navigation_menu"/>
[Link] 227
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="[Link]
xmlns:app="[Link]
<item
android:id="@+id/my_action1"
android:enabled="true"
android:icon="@drawable/my_drawable"
android:title="@string/text"
app:showAsAction="ifRoom" />
....
</menu>
case [Link].my_action1:
//Do something...
break;
//...
}
return true;//returning false disables the Navigation bar animations
}
});
Customization of BottomNavigationView
This example I will explain how to add selector for BottomNavigationView. So you can state on UI for
icons and texts.
app:itemIconTint="@drawable/bottom_navigation_view_selector"
[Link] 228
app:itemTextColor="@drawable/bottom_navigation_view_selector"
[Link]
[Link]
<[Link]
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:itemBackground="@color/colorPrimary"
app:itemIconTint="@drawable/nav_item_color_state"
app:itemTextColor="@drawable/nav_item_color_state"
app:menu="@menu/bottom_navigation_main" />
This example is strictly a workaround since, currently there is no way to disable a behaviour
known as ShiftMode.
[Link] 229
public static void disableMenuShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) [Link](0);
try {
Field shiftingMode = [Link]().getDeclaredField("mShiftingMode");
[Link](true);
[Link](menuView, false);
[Link](false);
for (int i = 0; i < [Link](); i++) {
BottomNavigationItemView item = (BottomNavigationItemView) [Link](i);
//noinspection RestrictedApi
[Link](false);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
[Link]([Link]().isChecked());
}
} catch (NoSuchFieldException e) {
Log.e("BNVHelper", "Unable to get shift mode field", e);
} catch (IllegalAccessException e) {
Log.e("BNVHelper", "Unable to change value of shift mode", e);
}
}
This disables the Shifting behaviour of the menu when item count exceeds 3 nos.
USAGE
Proguard Issue : Add following line proguard configuration file as well else, this wouldn't work.
Alternatively, you can create a Class and access this method from there. See Original Reply Here
NOTE : This is a Reflection based HOTFIX, please update this once Google's support library is
updated with a direct function call.
[Link] 230
Chapter 43: BroadcastReceiver
Introduction
BroadcastReceiver (receiver) is an Android component which allows you to register for system or
application events. All registered receivers for an event are notified by the Android runtime once
this event happens.
for example, a broadcast announcing that the screen has turned off, the battery is low, or a picture
was captured.
Applications can also initiate broadcasts—for example, to let other applications know that some
data has been downloaded to the device and is available for them to use.
Examples
Introduction to Broadcast receiver
A Broadcast receiver is an Android component which allows you to register for system or
application events.
A receiver can be registered via the [Link] file or dynamically via the
[Link]() method.
Here I have taken an example of ACTION_BOOT_COMPLETED which is fired by the system once the
Android has completed the boot process.
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<receiver android:name="MyReceiver">
<intent-filter>
<action android:name="[Link].BOOT_COMPLETED">
</action>
</intent-filter>
</receiver>
</application>
Now device gets booted, onReceive() method will be called and then you can do your work (e.g.
[Link] 231
start a service, start an alarm).
BroadcastReceiver Basics
BroadcastReceivers are used to receive broadcast Intents that are sent by the Android OS, other
apps, or within the same app.
Each Intent is created with an Intent Filter, which requires a String action. Additional information
can be configured in the Intent.
Likewise, BroadcastReceivers register to receive Intents with a particular Intent Filter. They can be
registered programmatically:
[Link](new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//Your implementation goes here.
}
}, new IntentFilter("Some Action"));
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="Some Action"/>
</intent-filter>
</receiver>
To receive the Intent, set the Action to something documented by Android OS, by another app or
API, or within your own application, using sendBroadcast:
Additionally, the Intent can contain information, such as Strings, primitives, and Parcelables, that
can be viewed in onReceive.
Using LocalBroadcastManager
[Link] 232
if ([Link]().equals("Some Action")) {
//Do something
}
}
});
//Remember to unregister the receiver when you are done with it:
[Link](receiver);
Register broadcast
[Link] 233
}
Unregister broadcast
[Link](
componentName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
[Link](
componentName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
Example below shows how to create a BroadcastReceiver which is able to receive BOOT_COMPLETED
events. This way, you are able to start a Service or start an Activity as soon device was powered
up.
Also, you can use BOOT_COMPLETED events to restore your alarms since they are destroyed when
device is powered off.
NOTE: The user needs to have started the application at least once before you can receive the
BOOT_COMPLETED action.
[Link]
<manifest xmlns:android="[Link]
[Link] 234
package="[Link]" >
...
<uses-permission android:name="[Link].RECEIVE_BOOT_COMPLETED" />
...
<application>
...
<receiver android:name="[Link]">
<intent-filter>
<!-- REGISTER TO RECEIVE BOOT_COMPLETED EVENTS -->
<action android:name="[Link].BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
[Link]
@Override
public void onReceive(Context context, Intent intent) {
String action = [Link]();
if(action != null) {
if ([Link](Intent.ACTION_BOOT_COMPLETED) ) {
// TO-DO: Code to handle BOOT COMPLETED EVENT
// TO-DO: I can start an service.. display a notification... start an activity
}
}
}
}
Example of a LocalBroadcastManager
"A Broadcast receiver is an Android component which allows you to register for system
or application events."
1. since the data remains inside the application process, the data cannot be leaked.
2. LocalBroadcasts are resolved faster, since the resolution of a normal broadcast happens at
runtime throughout the OS.
SenderActivity
[Link] 235
Intent intent = new Intent("anEvent");
[Link]("key", "This is an event");
[Link](this).sendBroadcast(intent);
ReceiverActivity
1. Register a receiver
[Link](this).registerReceiver(aLBReceiver,
new IntentFilter("anEvent"));
@Override
protected void onPause() {
// Unregister since the activity is about to be closed.
[Link](this).unregisterReceiver(aLBReceiver);
[Link]();
}
You can communicate two activities so that Activity A can be notified of an event happening in
Activity B.
Activity A
@Override
protected void onCreate(Bundle savedInstanceState) {
registerEventReceiver();
[Link](savedInstanceState);
}
@Override
protected void onDestroy() {
unregisterEventReceiver(eventReceiver);
[Link]();
}
[Link] 236
}
Activity B
Of course you can add more information to the broadcast adding extras to the Intent that is passed
between the activities. Not added to keep the example as simple as possible.
Sticky Broadcast
Ordered broadcasts are used when you need to specify a priority for broadcast listeners.
In this example firstReceiver will receive broadcast always before than a secondReceiver:
[Link] 237
// register our receivers
[Link](firstReceiver, firstFilter);
[Link](secondReceiver, secondFilter);
@Override
public void onReceive(final Context context, final Intent intent) {
abortBroadcast();
}
in this case all receivers with lower priority will not receive a broadcast message.
Starting with Android 3.1 all applications, upon installation, are placed in a stopped state. While in
stopped state, the application will not run for any reason, except by a manual launch of an activity,
or an explicit intent that addresses an activity ,service or broadcast.
When writing system app that installs APKs directly, please take into account that the newly
installed APP won't receive any broadcasts until moved into a non stopped state.
An easy way to to activate an app is to sent a explicit broadcast to this app. as most apps
implement INSTALL_REFERRER, we can use it as a hooking point
Scan the manifest of the installed app, and send an explicit broadcast to to each receiver:
[Link] 238
Chapter 44: Building Backwards Compatible
Apps
Examples
How to handle deprecated API
It is unlikely for a developer to not come across a deprecated API during a development process.
A deprecated program element is one that programmers are discouraged from using, typically
because it is dangerous, or because a better alternative exists. Compilers and analyzers (like LINT
) warn when a deprecated program element is used or overridden in non-deprecated code.
A deprecated API is usually identified in Android Studio using a strikeout. In the example below,
the method .getColor(int id) is deprecated:
getResources().getColor([Link]));
If possible, developers are encouraged to use alternative APIs and elements. It is possible to
check backwards compatibility of a library by visiting the Android documentation for the library and
checking the "Added in API level x" section:
[Link] 239
[Link] 240
[Link]
[Link] 241
Chapter 45: ButterKnife
Introduction
Butterknife is a view binding tool that uses annotations to generate boilerplate code for us. This
tool is developed by Jake Wharton at Square and is essentially used to save typing repetitive lines
of code like findViewById([Link]) when dealing with views thus making our code look a lot
cleaner.
To be clear, Butterknife is not a dependency injection library. Butterknife injects code at compile
time. It is very similar to the work done by Android Annotations.
Remarks
ButterKnife
Field and method binding for Android views which uses annotation processing to generate
boilerplate code for you.
License
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
in compliance with the License. You may obtain a copy of the License at
[Link]
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied. See the License for the specific language governing permissions and
limitations under the License.
Examples
Configuring ButterKnife in your project
[Link] 242
Configure your project-level [Link] to include the android-apt plugin:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath '[Link]:butterknife-gradle-plugin:8.5.1'
}
}
Then, apply the android-apt plugin in your module-level [Link] and add the ButterKnife
dependencies:
android {
...
}
dependencies {
compile '[Link]:butterknife:8.5.1'
annotationProcessor '[Link]:butterknife-compiler:8.5.1'
}
Note: If you are using the new Jack compiler with version 2.2.0 or newer you do not need the
android-apt plugin and can instead replace apt with annotationProcessor when declaring the
compiler dependency.
In order to use ButterKnife annotations you shouldn't forget about binding them in onCreate() of
your Activities or onCreateView() of your Fragments:
@Override
public void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
// Binding annotations
[Link](this);
// ...
}
// Or
class ExampleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
[Link](inflater, container, savedInstanceState);
View view = [Link](getContentView(), container, false);
// Binding annotations
[Link](this, view);
[Link] 243
// ...
return view;
}
Below are the additional steps you'd have to take to use ButterKnife in a library project
To use ButterKnife in a library project, add the plugin to your project-level [Link]:
buildscript {
dependencies {
classpath '[Link]:butterknife-gradle-plugin:8.5.1'
}
}
…and then apply to your module by adding these lines on the top of your library-level [Link]:
Now make sure you use R2 instead of R inside all ButterKnife annotations.
// Listeners
@OnClick([Link])
public void submit(View view) {
// TODO submit data to server...
}
[Link] 244
Binding Views using ButterKnife
we can annotate fields with @BindView and a view ID for Butter Knife to find and automatically cast
the corresponding view in our layout.
Binding Views
Binding Views in Activity
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
View view = [Link]([Link].fancy_fragment, container, false);
unbinder = [Link](this, view);
// TODO Use fields...
return view;
}
// in fragments or non activity bindings we need to unbind the binding when view is about to
be destroyed
@Override
public void onDestroy() {
[Link]();
[Link]();
}
}
[Link] 245
infer the return type and automatically performs the cast.
Binding Resources
Apart from being useful for binding views, one could also use ButterKnife to bind resources such
as those defined within [Link], [Link], [Link], [Link], etc.
@Override
public void onCreate(Bundle savedInstanceState) {
// ...
[Link](this);
}
[Link] 246
//The apply method allows you to act on all the views in a list at once.
[Link](nameViews, DISABLE);
[Link](nameViews, ENABLED, false);
//We can use Action and Setter interfaces allow specifying simple behavior.
static final [Link]<View> DISABLE = new [Link]<View>() {
@Override public void apply(View view, int index) {
[Link](false);
}
};
static final [Link]<View, Boolean> ENABLED = new [Link]<View,
Boolean>() {
@Override public void set(View view, Boolean value, int index) {
[Link](value);
}
};
Optional Bindings
By default, both @Bind and listener bindings are required. An exception is thrown if the target view
cannot be found. But if we are not sure if a view will be there or not then we can add a @Nullable
annotation to fields or the @Optional annotation to methods to suppress this behavior and create an
optional binding.
@Nullable
@BindView([Link].might_not_be_there) TextView mightNotBeThere;
@Optional
@OnClick([Link].maybe_missing)
void onMaybeMissingClicked() {
// TODO ...
}
OnClick Listener:
@OnClick([Link])
public void login(View view) {
// Additional logic
}
@OnClick([Link])
public void login() {
// Additional logic
}
[Link] 247
@OnClick([Link])
public void sayHi(Button button) {
[Link]("Hello!");
}
Custom Views can bind to their own listeners by not specifying an ID:
Fragments have a different view lifecycle than activities. When binding a fragment in
onCreateView, set the views to null in onDestroyView. Butter Knife returns an Unbinder instance
when you call bind to do this for you. Call its unbind method in the appropriate lifecycle callback.
An example:
[Link] 248
Android Studio ButterKnife Plugin
Note : Make sure that you make the right click for your_xml_layou([Link].your_xml_layou) else
the Generate menu will not contain Butterknife injector option.
[Link] 249
Chapter 46: Button
Syntax
• <Button ... />
• android:onClick="methodname"
• [Link](new OnClickListener(){...});
• public class classname implements [Link]
Examples
inline onClickListener
Say we have a button (we can create it programmatically, or bind it from a view using
findViewbyId(), etc...)
[Link](new [Link]() {
@Override
public void onClick(View v) {
// Do stuff here...
}
});
When we create a button in layout, we can use the android:onClick attribute to reference a method
in code to handle clicks.
Button
<Button
android:width="120dp"
android:height="wrap_content"
android:text="Click me"
android:onClick="handleClick" />
[Link] 250
Using the same click event for one or more Views in the XML
When we create any View in layout, we can use the android:onClick attribute to reference a
method in the associated activity or fragment to handle the click events.
XML Layout
<Button android:id="@+id/button"
...
// onClick should reference the method in your activity or fragment
android:onClick="doSomething" />
// Note that this works with any class which is a subclass of View, not just Button
<ImageView android:id="@+id/image"
...
android:onClick="doSomething" />
Activity/fragment code
In your code, create the method you named, where v will be the view that was touched, and do
something for each view that calls this method.
If you want, you can also use different method for each View (in this case, of course, you don't
have to check for the ID).
To catch a long click and use it you need to provide appropriate listener to button:
[Link](listener);
[Link] 251
When should I use it
• When the code inside an inline listener is too big and your method / class becomes ugly and
hard to read
• You want to perform same action in various elements (view) of your app
To achieve this you need to create a class implementing one of the listeners in the View API.
@Override
public void onLongClick(View v) {
// show help toast or popup
}
}
Then you just need to have an attribute or variable in your Activity to use it:
[Link](helpListener);
[Link](helpListener);
[Link](helpListener);
[Link](helpListener);
NOTE: defining listeners in separated class has one disadvantage, it cannot access class fields
directly, so you need to pass data (context, view) through constructor unless you make attributes
public or define geters.
In order to prevent a button from firing multiple times within a short period of time (let's say
2 clicks within 1 second, which may cause serious problems if the flow is not controlled), one can
implement a custom SingleClickListener.
This ClickListener sets a specific time interval as threshold (for instance, 1000ms).
When the button is clicked, a check will be ran to see if the trigger was executed in the past
amount of time you defined, and if not it will trigger it.
public SingleClickListener() {
[Link] 252
this(1000);
}
@Override
public void onClick(View v) {
if ([Link]() - lastTimeClicked < defaultInterval) {
return;
}
lastTimeClicked = [Link]();
performClick(v);
}
There are many possible ways of customizing the look of a Button. This example presents several
options:
[Link]
<resources>
<style name=“mybutton” parent=”[Link]”>
<!-- customize colorButtonNormal for the disable color -->
<item name="colorButtonNormal">@color/colorbuttonnormal</item>
<!-- customize colorAccent for the enabled color -->
<item name="colorButtonNormal">@color/coloraccent</item>
</style>
</resources>
Then in the layout where you place your button (e.g. MainActivity):
activity_main.xml
[Link] 253
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="[Link]
xmlns:tools="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<Button
android:id="@+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"
android:theme="@style/mybutton"
style="@style/[Link]"/>
</LinearLayout>
[Link]
<resources>
<style name="mybuttonstyle" parent="@android:style/[Link]">
<item name="android:gravity">center_vertical|center_horizontal</item>
<item name="android:textColor">#FFFFFFFF</item>
<item name="android:shadowColor">#FF000000</item>
<item name="android:shadowDx">0</item>
<item name="android:shadowDy">-1</item>
<item name="android:shadowRadius">0.2</item>
<item name="android:textSize">16dip</item>
<item name="android:textStyle">bold</item>
<item name="android:background">@drawable/button</item>
</style>
</resources>
Then in the layout where you place your button (e.g. in MainActivity):
activity_main.xml
[Link] 254
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<Button
android:id="@+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"
android:theme="@style/mybuttonstyle"/>
</LinearLayout>
Create an xml file into drawable folder called '[Link]' to define the drawable
resource of each of your button states:
drawable/[Link]
<selector xmlns:android="[Link]
<item
android:state_enabled="false"
android:drawable="@drawable/mybutton_disabled" />
<item
android:state_pressed="true"
android:state_enabled="true"
android:drawable="@drawable/mybutton_pressed" />
<item
android:state_focused="true"
android:state_enabled="true"
android:drawable="@drawable/mybutton_focused" />
<item
android:state_enabled="true"
android:drawable="@drawable/mybutton_enabled" />
</selector>
Each of those drawables may be images (e.g. mybutton_disabled.png) or xml files defined by you
and stored in the drawables folder. For instance:
drawable/mybutton_disabled.xml
<shape xmlns:android="[Link]
android:shape="rectangle">
<gradient
android:startColor="#F2F2F2"
android:centerColor="#A4A4A4"
android:endColor="#F2F2F2"
android:angle="90"/>
<padding android:left="7dp"
android:top="7dp"
android:right="7dp"
android:bottom="7dp" />
[Link] 255
<stroke
android:width="2dip"
android:color="#FFFFFF" />
<corners android:radius= "8dp" />
</shape>
Then in the layout where you place your button (e.g. MainActivity):
activity_main.xml
<Button
android:id="@+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"
android:background="@drawable/mybuttondrawable"/>
</LinearLayout>
You can override the default android button style in the definition of your app theme (in
values/[Link]).
[Link]
<resources>
<style name="AppTheme" parent="android:Theme">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:button">@style/mybutton</item>
</style>
[Link] 256
<item name="android:textStyle">bold</item>
<item name="android:background">@drawable/anydrawable</item>
</style>
</resources>
Just find you button in your activity and apply a color filter:
You can check different blending modes here and nice examples here.
[Link] 257
Chapter 47: Callback URL
Examples
Callback URL example with Instagram OAuth
One of the use cases of callback URLs is OAuth. Let us do this with an Instagram Login: If the
user enters their credentials and clicks the Login button, Instagram will validate the credentials and
return an access_token. We need that access_token in our app.
For our app to be able to listen to such links, we need to add a callback URL to our Activity. We
can do this by adding an <intent-filter/> to our Activity, which will react to that callback URL.
Assume that our callback URL is appSchema://[Link]. Then you have to add the following lines
to your desired Activity in the [Link] file:
Now, in order to get the contents of the URL in your Activity, you need to override the onResume()
method as follows:
@Override
public void onResume() {
// The following line will return "appSchema://[Link]".
String CALLBACK_URL = getResources().getString([Link].insta_callback);
Uri uri = getIntent().getData();
if (uri != null && [Link]().startsWith(CALLBACK_URL)) {
String access_token = [Link]("access_token");
}
// Perform other operations here.
}
Now you have retrieved the access_token from Instagram, that is used in various API endpoints of
Instagram.
[Link] 258
Chapter 48: Camera 2 API
Parameters
Parameter Details
The subset of the results of a single image capture from the image
sensor. Contains a subset of the final configuration for the capture
CaptureResult hardware (sensor, lens, flash), the processing pipeline, the control
algorithms, and the output buffers. It is produced by a CameraDevice
after processing a CaptureRequest
Remarks
• Camera2 APIs are available in API 21+ (Lollipop and beyond)
• Even if an Android device has a 21+ ROM officially, there is no guarantee that it implements
Camera2 APIs, it's totally up to the manufacturer to implement it or not (Example: LG G2 has
official Lollipop support, but no Camera2 APIs)
• With Camera2, Camera ("Camera1") is deprecated
• With great power comes great responsability: It's easier to mess it up when using this APIs.
• Remember, if you only want to take a photo in your app, and simply get it, you don't need to
implement Camera2, you can open the device's camera app via an Intent, and receive it
[Link] 259
back
Examples
Preview the main camera in a TextureView
In this case, building against API 23, so permissions are handled too.
You must add in the Manifest the following permission (wherever the API level you're using):
<uses-permission android:name="[Link]"/>
We're about to create an activity ([Link]) that fills a TextureView with the preview of
the device's camera.
Attributes (You may need to read the entire example to understand some of it)
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
}
[Link] 260
};
A CameraDevice represent one physical device's camera. In this attribute, we save the ID of the
current CameraDevice
This is the view (TextureView) that we'll be using to "draw" the preview of the Camera
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
// This method is called when the camera is opened. We start camera preview here.
[Link]();
mCameraDevice = cameraDevice;
createCameraPreviewSession();
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
[Link]();
[Link]();
mCameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
[Link]();
[Link]();
mCameraDevice = null;
finish();
}
};
[Link] 261
An additional thread for running tasks that shouldn't block the UI
A Semaphore to prevent the app from exiting before closing the camera.
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_camera2);
@Override
public void onResume() {
[Link]();
startBackgroundThread();
// When the screen is turned off and turned back on, the SurfaceTexture is already
// available, and "onSurfaceTextureAvailable" will not be called. In that case, we can
open
// a camera and start preview from here (otherwise, we wait until the surface is ready in
// the SurfaceTextureListener).
if ([Link]()) {
openCamera([Link](), [Link]());
} else {
[Link] 262
[Link](mSurfaceTextureListener);
}
}
@Override
public void onPause() {
closeCamera();
stopBackgroundThread();
[Link]();
}
[Link] 263
}
// Danger! Attempting to use too large a preview size could exceed the camera
// bus' bandwidth limitation, resulting in gorgeous previews but the storage of
// garbage capture data.
mPreviewSize = chooseOptimalSize([Link]([Link]),
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
maxPreviewHeight, largest);
mCameraId = cameraId;
return;
}
} catch (CameraAccessException e) {
[Link]();
} catch (NullPointerException e) {
[Link] 264
// Currently an NPE is thrown when the Camera2API is used but not supported on the
// device this code runs.
[Link]([Link], "Camera2 API not supported on this device",
Toast.LENGTH_LONG).show();
}
}
// We configure the size of default buffer to be the size of camera preview we want.
[Link]([Link](), [Link]());
@Override
public void onConfigured(@NonNull CameraCaptureSession
cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
}
@Override
public void onConfigureFailed(
@NonNull CameraCaptureSession cameraCaptureSession) {
showToast("Failed");
}
}, null
);
[Link] 265
} catch (CameraAccessException e) {
[Link]();
}
}
}
})
.create();
} else {
[Link](this, new String[]{[Link]},
REQUEST_CAMERA_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if ([Link] != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED)
{
[Link]([Link], "ERROR: Camera permissions not granted",
Toast.LENGTH_LONG).show();
}
} else {
[Link](requestCode, permissions, grantResults);
}
}
[Link] 266
private void stopBackgroundThread() {
[Link]();
try {
[Link]();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
[Link]();
}
}
Utility methods
Given choices of Sizes supported by a camera, choose the smallest one that is at least at large as
the respective texture view size, and that is as most as large as the respective max size, and
whose aspect ratio matches with the specified value. If doesn't exist, choose the largest one that is
at most as large as the respective max size, and whose aspect ratio matches with the specified
value
// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
// Collect the supported resolutions that are smaller than the preview Surface
List<Size> notBigEnough = new ArrayList<>();
int w = [Link]();
int h = [Link]();
for (Size option : choices) {
if ([Link]() <= maxWidth && [Link]() <= maxHeight &&
[Link]() == [Link]() * h / w) {
if ([Link]() >= textureViewWidth &&
[Link]() >= textureViewHeight) {
[Link](option);
} else {
[Link](option);
}
}
}
// Pick the smallest of those big enough. If there is no one big enough, pick the
// largest of those not big enough.
if ([Link]() > 0) {
return [Link](bigEnough, new CompareSizesByArea());
} else if ([Link]() > 0) {
return [Link](notBigEnough, new CompareSizesByArea());
} else {
Log.e("Camera2", "Couldn't find any suitable preview size");
return choices[0];
}
}
[Link] 267
return;
}
int rotation = getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, [Link](), [Link]());
float centerX = [Link]();
float centerY = [Link]();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
[Link](centerX - [Link](), centerY - [Link]());
[Link](viewRect, bufferRect, [Link]);
float scale = [Link](
(float) viewHeight / [Link](),
(float) viewWidth / [Link]());
[Link](scale, scale, centerX, centerY);
[Link](90 * (rotation - 2), centerX, centerY);
} else if (Surface.ROTATION_180 == rotation) {
[Link](180, centerX, centerY);
}
[Link](matrix);
}
@Override
public int compare(Size lhs, Size rhs) {
// We cast here to ensure the multiplications won't overflow
return [Link]((long) [Link]() * [Link]() -
(long) [Link]() * [Link]());
}
}
/**
* Shows a {@link Toast} on the UI thread.
*
* @param text The message to show
*/
private void showToast(final String text) {
runOnUiThread(new Runnable() {
@Override
public void run() {
[Link]([Link], text, Toast.LENGTH_SHORT).show();
}
});
}
[Link] 268
Chapter 49: Camera and Gallery
Examples
Taking full-sized photo from camera
• - to open camera app. If attribute required is set to true you will not be able to install
Camera
this app if you don't have hardware camera.
• WRITE_EXTERNAL_STORAGE - This permission is required to create new file, in which captured
photo will be saved.
[Link]
<uses-feature android:name="[Link]"
android:required="true" />
<uses-permission android:name="[Link].WRITE_EXTERNAL_STORAGE"/>
The main idea in taking full-sized photo from camera is that we need to create new file for photo,
before we open camera app and capture photo.
[Link] 269
storageDir /* directory */
);
if (Environment.MEDIA_MOUNTED.equals([Link]())) {
if (![Link]()) {
if (![Link]()) {
Log.d("CameraSample", "failed to create directory");
return null;
}
}
} else {
Log.v(getString([Link].app_name), "External storage is not mounted READ/WRITE.");
}
return storageDir;
}
/* There isn't enough memory to open up more than a couple camera photos */
/* So pre-scale the target bitmap into which the file is decoded */
[Link] 270
/* Decode the JPEG file into a Bitmap */
Bitmap bitmap = [Link](mCurrentPhotoPath, bmOptions);
bitmap = [Link](bitmap, 0, 0, [Link](), [Link](), matrix,
false);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return 90f;
case ExifInterface.ORIENTATION_ROTATE_180:
return 180f;
case ExifInterface.ORIENTATION_ROTATE_270:
return 270f;
default:
return 0f;
}
} catch (Exception e) {
Log.e("Add Recipe", "getRotation", e);
return 0f;
}
}
if (mCurrentPhotoPath != null) {
setPic();
galleryAddPic();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
[Link](requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
handleBigCameraPhoto();
}
}
Take photo
[Link] 271
<uses-permission android:name="[Link]"></uses-permission>
<uses-permission android:name="[Link].WRITE_EXTERNAL_STORAGE" />
Xml file :
Activity
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
//Camera variables
//a surface holder
private SurfaceHolder sHolder;
//a variable to control the camera
private Camera mCamera;
//the camera parameters
private Parameters parameters;
[Link] 272
//get the Surface View at the [Link] file
sv = (SurfaceView) findViewById([Link]);
//Get a surface
sHolder = [Link]();
//add the callback interface methods defined below as the Surface View callbacks
[Link](this);
//tells Android that this surface will have its data constantly replaced
[Link](SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
{
//get camera parameters
parameters = [Link]();
@Override
public void surfaceCreated(SurfaceHolder holder)
{
[Link] 273
// The Surface has been created, acquire the camera and tell it where
// to draw the preview.
mCamera = [Link]();
try {
[Link](holder);
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
//stop the preview
[Link]();
//release the camera
[Link]();
//unbind the camera from this object
mCamera = null;
}
}
First of all you need Uri and temp Folders and request codes :
[Link] 274
public void openCamera(){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
try {
mImageCaptureUri = null;
String state = [Link]();
if (Environment.MEDIA_MOUNTED.equals(state)) {
mImageCaptureUri = [Link](mFileTemp);
} else {
mImageCaptureUri = InternalStorageContentProvider.CONTENT_URI;
}
[Link](MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
[Link]("return-data", true);
startActivityForResult(intent, REQUEST_CODE_TAKE_PICTURE);
} catch (Exception e) {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
Bitmap bitmap;
switch (requestCode) {
case REQUEST_SELECT_PICTURE:
try {
Uri uri = [Link]();
try {
bitmap = [Link](getContentResolver(), uri);
Bitmap bitmapScaled = [Link](bitmap, 800, 800, true);
Drawable drawable=new BitmapDrawable(bitmapScaled);
[Link] 275
[Link](drawable);
[Link]([Link]);
} catch (IOException e) {
Log.v("act result", "there is an error : "+[Link]());
}
} catch (Exception e) {
Log.v("act result", "there is an error : "+[Link]());
}
break;
case REQUEST_CODE_TAKE_PICTURE:
try{
Bitmap bitmappicture = [Link](getContentResolver() ,
mImageCaptureUri);
[Link](bitmappicture);
[Link]([Link]);
}catch (IOException e){
Log.v("error camera",[Link]());
}
break;
}
[Link](requestCode, resultCode, data);
}
And you need to handle runtime permissions such as Read/Write external storage etc ...
My requestPermission method :
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
switch (requestCode) {
[Link] 276
case REQUEST_STORAGE_READ_ACCESS_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
handleGallery();
}
break;
default:
[Link](requestCode, permissions, grantResults);
}
}
showAlertDialog method :
Decode bitmap correctly rotated from the uri fetched with the intent
[Link] 277
@Nullable
public Bitmap getBitmap(@NonNull Uri bitmapUri, int maxDimen) {
InputStream is = [Link]().openInputStream(bitmapUri);
Bitmap bitmap = [Link](is, null, getBitmapOptions(bitmapUri,
maxDimen));
return bitmap;
}
try {
boolean hasRotation = false;
//If image comes from the gallery and is not in the folder DCIM (Scheme: content://)
String[] projection = {[Link]};
Cursor cursor = [Link]().query(imgUri, projection, null, null,
null);
[Link] 278
if (cursor != null) {
if ([Link]() > 0 && [Link]()) {
photoRotation = [Link]([Link](projection[0]));
hasRotation = photoRotation != 0;
Log.d("Cursor orientation: "+ photoRotation);
}
[Link]();
}
//If image comes from the camera (Scheme: [Link] or is from the folder DCIM (Scheme:
content://)
if (!hasRotation) {
ExifInterface exif = new ExifInterface(getAbsolutePath(imgUri));
int exifRotation = [Link](ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (exifRotation) {
case ExifInterface.ORIENTATION_ROTATE_90: {
photoRotation = 90;
break;
}
case ExifInterface.ORIENTATION_ROTATE_180: {
photoRotation = 180;
break;
}
case ExifInterface.ORIENTATION_ROTATE_270: {
photoRotation = 270;
break;
}
}
Log.d(TAG, "Exif orientation: "+ photoRotation);
}
} catch (IOException e) {
Log.e(TAG, "Error determining rotation for image"+ imgUri, e);
}
return photoRotation;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private String getAbsolutePath(Uri uri) {
//Code snippet edited from: [Link]
String filePath = [Link]();
if ([Link].SDK_INT >= Build.VERSION_CODES.KITKAT &&
[Link](context, uri)) {
// Will return "image:x*"
String[] wholeID = [Link]([Link](uri),
COLON_SEPARATOR);
// Split at colon, use second item in the array
String type = wholeID[0];
if ([Link](type)) {//If it not type image, it means it comes from a
remote location, like Google Photos
String id = wholeID[1];
String[] column = {[Link]};
// where id is equal to
String sel = [Link]._ID + "=?";
Cursor cursor = [Link]().
query([Link].EXTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
if (cursor != null) {
int columnIndex = [Link](column[0]);
if ([Link]()) {
filePath = [Link](columnIndex);
[Link] 279
}
[Link]();
}
Log.d(TAG, "Fetched absolute path for uri" + uri);
}
}
return filePath;
}
[Link] 280
Chapter 50: Canvas drawing using
SurfaceView
Remarks
It's important to understand the basic concept of the surface view before using:
Deadlocks can easily occur if the lockCanvas() and unlockCanvasAndPost() methods are not called in
the correct order.
Examples
SurfaceView with drawing thread
This example describes how to create a SurfaceView with a dedicated drawing thread. This
implementation also handles edge cases such as manufacture specific issues as well as
starting/stopping the thread to save cpu time.
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
/**
* Defines a custom SurfaceView class which handles the drawing thread
**/
public class BaseSurface extends SurfaceView implements [Link],
[Link], Runnable
{
/**
* Holds the surface frame
*/
private SurfaceHolder holder;
/**
* Draw thread
*/
[Link] 281
private Thread drawThread;
/**
* True when the surface is ready to draw
*/
private boolean surfaceReady = false;
/**
* Drawing thread flag
*/
/**
* Paint for drawing the sample rectangle
*/
private Paint samplePaint = new Paint();
/**
* Time per frame for 60 FPS
*/
private static final int MAX_FRAME_TIME = (int) (1000.0 / 60.0);
// red
[Link](0xffff0000);
// smooth edges
[Link](true);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
if (width == 0 || height == 0)
{
return;
}
// resize your UI
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
[Link] = holder;
if (drawThread != null)
{
Log.d(LOGTAG, "draw thread still active..");
drawingActive = false;
try
{
[Link] 282
[Link]();
} catch (InterruptedException e)
{ // do nothing
}
}
surfaceReady = true;
startDrawThread();
Log.d(LOGTAG, "Created");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
// Surface is not used anymore - stop the drawing thread
stopDrawThread();
// and release the surface
[Link]().release();
[Link] = null;
surfaceReady = false;
Log.d(LOGTAG, "Destroyed");
}
@Override
public boolean onTouch(View v, MotionEvent event)
{
// Handle touch events
return true;
}
/**
* Stops the drawing thread
*/
public void stopDrawThread()
{
if (drawThread == null)
{
Log.d(LOGTAG, "DrawThread is null");
return;
}
drawingActive = false;
while (true)
{
try
{
Log.d(LOGTAG, "Request last frame");
[Link](5000);
break;
} catch (Exception e)
{
Log.e(LOGTAG, "Could not join with draw thread");
}
}
drawThread = null;
}
/**
* Creates a new draw thread and starts it.
*/
public void startDrawThread()
[Link] 283
{
if (surfaceReady && drawThread == null)
{
drawThread = new Thread(this, "Draw thread");
drawingActive = true;
[Link]();
}
}
@Override
public void run()
{
Log.d(LOGTAG, "Draw thread started");
long frameStartTime;
long frameTime;
/*
* In order to work reliable on Nexus 7, we place ~500ms delay at the start of drawing
thread
* (AOSP - Issue 58385)
*/
if ([Link]("google") &&
[Link]("asus") &&
[Link]("Nexus 7"))
{
Log.w(LOGTAG, "Sleep 500ms (Device: Asus Nexus 7)");
try
{
[Link](500);
} catch (InterruptedException ignored)
{
}
}
try
{
while (drawingActive)
{
if (holder == null)
{
return;
}
frameStartTime = [Link]();
Canvas canvas = [Link]();
if (canvas != null)
{
// clear the screen using black
[Link](255, 0, 0, 0);
try
{
// Your drawing here
[Link](0, 0, getWidth() / 2, getHeight() / 2, samplePaint);
} finally
{
[Link](canvas);
}
}
[Link] 284
frameTime = ([Link]() - frameStartTime) / 1000000;
if (frameTime < MAX_FRAME_TIME) // faster than the max fps - limit the FPS
{
try
{
[Link](MAX_FRAME_TIME - frameTime);
} catch (InterruptedException e)
{
// ignore
}
}
}
} catch (Exception e)
{
Log.w(LOGTAG, "Exception while locking/unlocking");
}
Log.d(LOGTAG, "Draw thread finished");
}
}
This layout only contains the custom SurfaceView and maximizes it to the screen size.
<[Link]
android:id="@+id/baseSurface"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
The activity which uses the SurfaceView is responsible for starting and stopping the drawing
thread. This approach saves battery as the drawing is stopped as soon as the activity gets in the
background.
import [Link];
import [Link];
/**
* Surface object
*/
private BaseSurface surface;
@Override
protected void onCreate(Bundle savedInstanceState)
{
[Link](savedInstanceState);
setContentView([Link].activity_main);
surface = (BaseSurface) findViewById([Link]);
[Link] 285
}
@Override
protected void onResume()
{
[Link]();
// start the drawing
[Link]();
}
@Override
protected void onPause()
{
// stop the drawing to save cpu time
[Link]();
[Link]();
}
}
[Link] 286
Chapter 51: Capturing Screenshots
Examples
Capturing Screenshot via Android Studio
[Link] 287
Capturing Screenshot via ADB
If you use Linux (or Windows with Cygwin), you can run:
If you want to take a screenshot of a particular View v, then you can use the following code:
if(backgroundDrawable != null){
// Draw the background onto the canvas.
[Link](viewCanvas);
[Link] 288
}
else{
[Link]([Link]);
// Draw the view onto the canvas.
[Link](viewCanvas)
}
[Link] 289
Chapter 52: CardView
Introduction
A FrameLayout with a rounded corner background and shadow.
CardView uses elevation property on Lollipop for shadows and falls back to a custom emulated
shadow implementation on older platforms.
Due to expensive nature of rounded corner clipping, on platforms before Lollipop, CardView does
not clip its children that intersect with rounded corners. Instead, it adds padding to avoid such
intersection (See setPreventCornerOverlap(boolean) to change this behavior).
Parameters
Parameter Details
Inner padding between the left edge of the Card and children of
contentPaddingLeft
the CardView.
Inner padding between the right edge of the Card and children
cardElevation
of the CardView.
contentPaddingTop Inner padding between the top edge of the Card and children of
[Link] 290
Parameter Details
the CardView.
Remarks
CardViewuses real elevation and dynamic shadows on Lollipop (API 21) and above. However,
before Lollipop CardView falls back to a programmatic shadow implementation.
If trying to make an ImageView fit within the rounded corners of a CardView, you may notice it does
not look correct pre-Lollipop (API 21). To fix this you should call setPreventCornerOverlap(false) on
your CardView, or add app:cardPreventCornerOverlap="false" to your layout.
Before using the CardView you have to add the support library dependency in the [Link] file:
dependencies{
compile '[Link]:cardview-v7:25.2.0'
}
Official Documentation:
[Link]
[Link]
Examples
Getting Started with CardView
CardView is a member of the Android Support Library, and provides a layout for cards.
To add CardView to your project, add the following line to your [Link] dependencies.
compile '[Link]:cardview-v7:25.1.1'
In your layout you can then add the following to get a card.
<[Link]
xmlns:card_view="[Link]
android:layout_width="match_parent"
android:layout_height="wrap_content">
</[Link]>
[Link] 291
You can then add other layouts inside this and they will be encompassed in a card.
Also, CardView can be populated with any UI element and manipulated from code.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp" >
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/item_image"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginRight="16dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/item_title"
android:layout_toRightOf="@+id/item_image"
android:layout_alignParentTop="true"
android:textSize="30sp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/item_detail"
android:layout_toRightOf="@+id/item_image"
android:layout_below="@+id/item_title"
/>
</RelativeLayout>
</[Link]>
CardView provides a default elevation and corner radius so that cards have a consistent
appearance across the platforms.
You can customize these default values using these attributes in the xml file:
[Link] 292
1. card_view:cardElevation attribute add elevation in CardView.
2. card_view:cardBackgroundColor attribute is used to customize background color of CardView's
background(you can give any color).
3. card_view:cardCornerRadius attribute is used to curve 4 edges of CardView
4. card_view:contentPadding attribute add padding between card and children of card
Here an example:
<[Link]
xmlns:card_view="[Link]
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardElevation="4dp"
card_view:cardBackgroundColor="@android:color/white"
card_view:cardCornerRadius="8dp"
card_view:contentPadding="16dp">
</[Link]>
[Link](....);
[Link](...);
[Link](....);
[Link]();
<[Link]
...
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground">
...
</[Link]>
While using Image/Colour as an background in a CardView, You might end up with slight white
paddings (If default Card colour is white) on the edges. This occurs due to the default rounded
corners in the Card View. Here is how to avoid those margins in Pre-lollipop devices.
[Link] 293
<[Link]
xmlns:card_view="[Link]
android:layout_width="match_parent"
card_view:cardPreventCornerOverlap="false"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/row_wallet_redeem_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@drawable/bg_image" />
</[Link]>
Doing so removes an unwanted padding on the Card's edges. Here are some visual examples
related to this implementation.
2 Card with image background in API 19 without attribute (notice the paddings around image)
[Link] 294
3 FIXED Card with image background in API 19 with attribute
[Link](false) (Issue now fixed)
[Link] 295
Read CardView online: [Link]
[Link] 296
Chapter 53: Check Data Connection
Examples
Check data connection
ConnectivityManager cm = (ConnectivityManager)
[Link](Context.CONNECTIVITY_SERVICE);
return [Link] () != null && [Link]
().isConnectedOrConnecting ();
When your device connects to a network, an intent is sent. Many apps don’t check for these
intents, but to make your application work properly, you can listen to network change intents that
will tell you when communication is possible. To check for network connectivity you can, for
example, use the following clause:
if
([Link]().equals([Link].CONNECTIVITY_ACTION)){
NetworkInfo info =
[Link](ConnectivityManager.EXTRA_NETWORK_INFO);
//perform your action when connected to a network
}
[Link] 297
Chapter 54: Check Internet Connectivity
Introduction
This method is used to check weather WI-Fi is connected or not.
Syntax
• isNetworkAvailable() : To check if Internet available on device
Parameters
Parameter Detail
Remarks
If internet connected then method will return true or false.
Examples
Check if device has internet connectivity
/**
* If network connectivity is available, will return true
*
* @param context the current context
* @return boolean true if a network connection is available
*/
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivity = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
Log.d("NetworkCheck", "isNetworkAvailable: No");
return false;
}
// get network info for all of the data interfaces (e.g. WiFi, 3G, LTE, etc.)
NetworkInfo[] info = [Link]();
[Link] 298
// make sure that there is at least one interface to test against
if (info != null) {
// iterate through the interfaces
for (int i = 0; i < [Link]; i++) {
// check this interface for a connected state
if (info[i].getState() == [Link]) {
Log.d("NetworkCheck", "isNetworkAvailable: Yes");
return true;
}
}
}
return false;
}
ConnectivityManager cm = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo Info = [Link]();
if (Info == null || ![Link]()) {
Log.i(TAG, "No connection");
} else {
int netType = [Link]();
int netSubtype = [Link]();
if (netType == ConnectivityManager.TYPE_WIFI) {
Log.i(TAG, "Wifi connection");
WifiManager wifiManager = (WifiManager)
getApplication().getSystemService(Context.WIFI_SERVICE);
List<ScanResult> scanResult = [Link]();
for (int i = 0; i < [Link](); i++) {
Log.d("scanResult", "Speed of wifi"+[Link](i).level);//The db
level of signal
}
if (netType == ConnectivityManager.TYPE_WIFI) {
Log.i(TAG, "Wifi connection");
[Link] 299
WifiManager wifiManager = (WifiManager)
getApplication().getSystemService(Context.WIFI_SERVICE);
List<ScanResult> scanResult = [Link]();
for (int i = 0; i < [Link](); i++) {
Log.d("scanResult", "Speed of wifi"+[Link](i).level);//The db level of
signal
}
/**
* Check if there is any connectivity
*
* @param context
* @return
*/
public static boolean isConnected(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = [Link]();
return (info != null && [Link]());
}
/**
* Check if there is fast connectivity
*
* @param context
* @return
*/
public static String isConnectedFast(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = [Link]();
[Link] 300
/**
* Check if the connection is fast
*
* @param type
* @param subType
* @return
*/
public static String isConnectionFast(int type, int subType) {
if (type == ConnectivityManager.TYPE_WIFI) {
[Link]("CONNECTED VIA WIFI");
return "CONNECTED VIA WIFI";
} else if (type == ConnectivityManager.TYPE_MOBILE) {
switch (subType) {
case TelephonyManager.NETWORK_TYPE_1xRTT:
return "NETWORK TYPE 1xRTT"; // ~ 50-100 kbps
case TelephonyManager.NETWORK_TYPE_CDMA:
return "NETWORK TYPE CDMA (3G) Speed: 2 Mbps"; // ~ 14-64 kbps
case TelephonyManager.NETWORK_TYPE_EDGE:
[Link] 301
} else {
return "";
}
}
[Link] 302
Chapter 55: CleverTap
Introduction
Quick hacks for the analytics and engagement SDK provided by CleverTap - Android
Remarks
Get your CleverTap credentials from [Link]
Examples
Get an instance of the SDK to record events
CleverTapAPI cleverTap;
try {
cleverTap = [Link](getApplicationContext());
} catch (CleverTapMetaDataNotFoundException e) {
// thrown if you haven't specified your CleverTap Account ID or Token in your
[Link]
} catch (CleverTapPermissionsNotSatisfied e) {
// thrown if you haven’t requested the required permissions in your [Link]
}
In your custom application class, override the onCreate() method, add the line below:
[Link](1);
[Link] 303
Chapter 56: Colors
Examples
Color Manipulation
To manipulate colors we will modify the argb (Alpha, Red, Green and Blue) values of a color.
Now you can reduce or increase red, green, and blue values and combine them to be a color
again:
Or if you want to add some alpha to it, you can add it while creating the color:
[Link] 304
Chapter 57: ConstraintLayout
Introduction
ConstraintLayoutis a ViewGroup which allows you to position and size widgets in a flexible way. It is
compatible with Android 2.3 (API level 9) and higher.
It allows you to create large and complex layouts with a flat view hierarchy. It is similar to
RelativeLayout in that all views are laid out according to relationships between sibling views and
the parent layout, but it's more flexible than RelativeLayout and easier to use with Android Studio's
Layout Editor.
Syntax
• ConstraintLayout
○ protected [Link]
generateLayoutParams([Link] params)
○ protected void onLayout(boolean changed, int left, int top, int right, int bottom)
• [Link]
Parameters
[Link] 305
Parameter Details
layoutDirection -
a -
widthAttr -
heightAttr -
Remarks
At Google IO 2016 Google announced a new Android layout named ConstraintLayout.
Pay attention because currently, this layout is a Beta release.
Examples
Adding ConstraintLayout to your project
To work with ConstraintLayout, you need Android Studio Version 2.2 or newer and have at least
[Link] 306
version 32 (or higher) of Android Support Repository.
dependencies {
compile '[Link]:constraint-layout:1.0.2'
}
2. Sync project
1. Right-click on your module's layout directory, then click New > XML > Layout XML.
2. Enter a name for the layout and enter "[Link]" for the
Root Tag.
3. Click Finish.
</[Link]>
Chains
Since ConstraintLayout alpha 9, Chains are available. A Chain is a set of views inside a
ConstraintLayout that are connected in a bi-directional way between them, i.e A connected to B
with a constraint, and B connected to A with another constraint.
Example:
<[Link]
xmlns:android="[Link]
xmlns:app="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- this view is linked to the topTextView at the same time -->
<TextView
[Link] 307
android:id="@+id/bottomTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bottom\nMkay"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topTextView"/>
</[Link]>
In this example, the two views are positioned one under another and both of them are centered
vertically. You may change the vertical position of these views by adjusting the chain's bias. Add
the following code to the first element of a chain:
app:layout_constraintVertical_bias="0.2"
In a vertical chain, the first element is a top-most view, and in a horizontal chain it is the left-most
view. The first element defines the whole chain's behavior.
Chains are a new feature and are updated frequently. Here is an official Android Documentation
on Chains.
[Link] 308
Chapter 58: ConstraintSet
Introduction
This class allows you to define programmatically a set of constraints to be used with
ConstraintLayout. It lets you create and save constraints, and apply them to an existing
ConstraintLayout.
Examples
ConstraintSet with ContraintLayout Programmatically
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
Context context = this;
[Link](context, [Link].state2); // get constraints from layout
setContentView([Link].state1);
mConstraintLayout = (ConstraintLayout) findViewById([Link].activity_main);
[Link](mConstraintLayout); // get constraints from ConstraintSet
}
[Link] 309
Chapter 59: ContentProvider
Remarks
Content providers manage access to a structured set of data. They encapsulate the data, and
provide mechanisms for defining data security. Content providers are the standard interface that
connects data in one process with code running in another process.
When you want to access data in a content provider, you use the ContentResolver object in your
application's Context to communicate with the provider as a client. The ContentResolver object
communicates with the provider object, an instance of a class that implements ContentProvider.
The provider object receives data requests from clients, performs the requested action, and
returns the results.
You don't need to develop your own provider if you don't intend to share your data with other
applications. However, you do need your own provider to provide custom search suggestions in
your own application. You also need your own provider if you want to copy and paste complex
data or files from your application to other applications.
Android itself includes content providers that manage data such as audio, video, images, and
personal contact information. You can see some of them listed in the reference documentation for
the [Link] package. With some restrictions, these providers are accessible to any
Android application.
Examples
Implementing a basic content provider class
A contract class defines constants that help applications work with the content URIs, column
names, intent actions, and other features of a content provider. Contract classes are not included
automatically with a provider; the provider's developer has to define them and then make them
available to other developers.
A provider usually has a single authority, which serves as its Android-internal name. To avoid
conflicts with other providers, use a unique content authority. Because this recommendation is
also true for Android package names, you can define your provider authority as an extension of
the name of the package containing the provider. For example, if your Android package name is
[Link], you should give your provider the authority [Link].
[Link] 310
A content URI is a URI that identifies data in a provider. Content URIs include the symbolic name
of the entire provider (its authority) and a name that points to a table or file (a path). The optional
id part points to an individual row in a table. Every data access method of ContentProvider has a
content URI as an argument; this allows you to determine the table, row, or file to access. Define
these in the contract class.
@Override
public void onCreate(SQLiteDatabase db) {
// Called when the database is created for the first time. This is where the
// creation of tables and the initial population of the tables should happen.
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Called when the database needs to be upgraded. The implementation
// should use this method to drop tables, add tables, or do anything else it
// needs to upgrade to the new schema version.
}
}
A UriMatcher maps an authority and path to an integer value. The method match() returns a unique
integer value for a URI (it can be any arbitrary number, as long as it's unique). A switch statement
chooses between querying the entire table, and querying for a single record. Our UriMatcher
returns 100 if the URI is the Content URI of Table and 101 if the URI points to a specific row within
[Link] 311
that table. You can use the # wildcard to match with any number and * to match with any string.
IMPORTANT: the ordering of addURI() calls matters! The UriMatcher will look in sequential order
from first added to last. Since wildcards like # and * are greedy, you will need to make sure that
you have ordered your URIs correctly. For example:
is the proper ordering, since the matcher will look for /example first before resorting to the /* match.
If these method calls were reversed and you called [Link]("/example"), then the
UriMatcher will stop looking for matches once it encounters the /* path and return the wrong
result!
onCreate(): Initialize your provider. The Android system calls this method immediately after it
creates your provider. Notice that your provider is not created until a ContentResolver object tries
to access it.
@Override
public boolean onCreate() {
dbhelper = new DatabaseHelper(getContext());
return true;
}
@Override
public String getType(Uri uri) {
final int match = [Link](uri);
switch (match) {
case DATA_TABLE:
return ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + MyContract.CONTENT_AUTHORITY +
"/" + MyContract.PATH_DATATABLE;
case DATA_TABLE_DATE:
return ContentResolver.ANY_CURSOR_ITEM_TYPE + "/" + MyContract.CONTENT_AUTHORITY +
"/" + MyContract.PATH_DATATABLE;
default:
throw new UnsupportedOperationException("Unknown Uri: " + uri);
}
}
query(): Retrieve data from your provider. Use the arguments to select the table to query, the
rows and columns to return, and the sort order of the result. Return the data as a Cursor object.
[Link] 312
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Cursor retCursor = [Link]().query(
MyContract.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
[Link](getContext().getContentResolver(), uri);
return retCursor;
}
Insert a new row into your provider. Use the arguments to select the destination table and to get
the column values to use. Return a content URI for the newly-inserted row.
@Override
public Uri insert(Uri uri, ContentValues values)
{
final SQLiteDatabase db = [Link]();
long id = [Link](MyContract.TABLE_NAME, null, values);
return [Link](MyContract.CONTENT_URI, ID);
}
delete(): Delete rows from your provider. Use the arguments to select the table and the rows to
delete. Return the number of rows deleted.
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = [Link]();
int rowsDeleted = [Link](MyContract.TABLE_NAME, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
update(): Update existing rows in your provider. Use the arguments to select the table and rows to
update and to get the new column values. Return the number of rows updated.
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SQLiteDatabase db = [Link]();
int rowsUpdated = [Link](MyContract.TABLE_NAME, values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
<provider
android:authorities="[Link]"
android:name=".DatabaseProvider"/>
[Link] 313
Chapter 60: Context
Introduction
Per Google documentation: "Interface to global information about an application environment. It
allows access to application-specific resources and classes, as well as up-calls for application-
level operations such as launching activities, broadcasting and receiving intents, etc."
More simply put, Context is the current state of your application. It allows you to provide
information to objects so that they can be aware of what is going on in other parts of your
application.
Syntax
• getApplicationContext()
• getBaseContext()
• getContext()
• this
Remarks
This StackOverflow page has several comprehensive and well written explanations of the concept
of Context:
What is Context?
Examples
Basic Examples
this (when in a class that extends from Context, such as the Application, Activity, Service and
IntentService classes)
[Link] 314
Intent intent = new Intent(this, [Link]);
startActivity(intent);
[Link] 315
Chapter 61: Convert vietnamese string to
english string Android
Examples
example:
converted:
[Link] 316
Chapter 62: CoordinatorLayout and
Behaviors
Introduction
The CoordinatorLayout is a super-powered FrameLayout and goal of this ViewGroup is to
coordinate the views that are inside it.
The main appeal of the CoordinatorLayout is its ability to coordinate the animations and transitions
of the views within the XML file itself.
:As a container for a specific interaction with one or more child views
Remarks
The CoordinatorLayout is a container that extends the FrameLayout.
By attaching a [Link] to a direct child of CoordinatorLayout, you’ll be able to
intercept touch events, window insets, measurement, layout, and nested scrolling.
By specifying Behaviors for child views of a CoordinatorLayout you can provide many different
interactions within a single parent and those views can also interact with one another. View
classes can specify a default behavior when used as a child of a CoordinatorLayout using the
DefaultBehavior annotation.
Examples
Creating a simple Behavior
/**
* Default constructor.
*/
public MyBehavior() {
[Link] 317
}
/**
* Default constructor for inflating a MyBehavior from layout.
*
* @param context The {@link Context}.
* @param attrs The {@link AttributeSet}.
*/
public MyBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
<View
android:layout_height="...."
android:layout_width="...."
app:layout_behavior=".MyBehavior" />
@[Link]([Link])
public class MyView extends ..... {
The SwipeDismissBehavior works on any View and implements the functionality of swipe to dismiss
in our layouts with a CoordinatorLayout.
Just use:
[Link] 318
final SwipeDismissBehavior<MyView> swipe = new SwipeDismissBehavior();
@Override
public void onDragStateChanged(int state) {
//......
}
});
You can use the [Link] to create dependencies between views. You can
anchor a View to another View by:
For example, in order to create a Behavior for moving an ImageView when another one is moved
(example Toolbar), perform the following steps:
• Override the layoutDependsOn method returning true. This method is called every time a
change occurs to the layout:
@Override
public boolean layoutDependsOn(CoordinatorLayout parent,
ImageView child, View dependency) {
// Returns true to add a dependency.
return dependency instanceof Toolbar;
}
@Override
[Link] 319
public boolean onDependentViewChanged(CoordinatorLayout parent, ImageView child, View
dependency) {
// Implement here animations, translations, or movements; always related to the
provided dependency.
float translationY = [Link](0, [Link]() -
[Link]());
[Link](translationY);
}
[Link] 320
Chapter 63: Count Down Timer
Parameters
Parameter Details
The total duration the timer will run for, a.k.a how far in the future you
long millisInFuture
want the timer to end. In milliseconds.
long The interval at which you would like to receive timer updates. In
countDownInterval milliseconds.
Remarks
CountDownTimer is a pretty lean class - it does one thing very well. Since you can only
start/cancel a CountDownTimer, you have to implement pause/resume functionality as shown in
the second example. For more complex functionality, or to specify a timer that should run
indefinitely, use the Timer object.
Examples
Creating a simple countdown timer
CountDownTimer is useful for repeatedly performing an action in a steady interval for a set
duration. In this example, we will update a text view every second for 30 seconds telling how much
time is remaining. Then when the timer finishes, we will set the TextView to say "Done."
In this example, we will pause/resume the CountDownTimer based off of the Activity lifecycle.
[Link] 321
private static final long TIMER_DURATION = 60000L;
private static final long TIMER_INTERVAL = 1000L;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
@Override
public void onTick(long millisUntilFinished) {
[Link]([Link]([Link](), "%d sec.", millisUntilFinished
/ 1000L));
mTimeRemaining = millisUntilFinished; // Saving timeRemaining in Activity for
pause/resume of CountDownTimer.
}
@Override
public void onFinish() {
[Link]("Done.");
}
}.start();
}
@Override
protected void onResume() {
[Link]();
@Override
public void onFinish() {
[Link]("Done.");
}
}.start();
}
}
@Override
protected void onPause() {
[Link]();
[Link]();
mCountDownTimer = null;
}
[Link] 322
Read Count Down Timer online: [Link]
[Link] 323
Chapter 64: Crash Reporting Tools
Remarks
The best complete wiki is available here in github.
Examples
Fabric - Crashlytics
Fabric is a modular mobile platform that provides useful kits you can mix to build your application.
Crashlytics is a crash and issue reporting tool provided by Fabric that allows you to track and
monitor your applications in detail.
buildscript {
repositories {
maven { url '[Link] }
}
dependencies {
// The Fabric Gradle plugin uses an open ended version to react
// quickly to Android tooling updates
classpath '[Link]:gradle:1.+'
}
}
repositories {
maven { url '[Link] }
}
[Link] 324
dependencies {
compile('[Link]:crashlytics:2.6.6@aar') {
transitive = true;
}
}
Step 2: Add Your API Key and the INTERNET permission in [Link]
<meta-data
android:name="[Link]"
android:value="25eeca3bb31cd41577e097cabd1ab9eee9da151d"
/>
</application>
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
}
}
[Link] 325
After installing the plugin, restart Android Studio and login with your account using Android
Studio.
[Link] 326
Then it will show the projects that you have / the project you opened, select the one you need and
click next .. next.
Select the kit you would like to add, for his example it is Crashlytics :
[Link] 327
Then hit Install. You don't need to add it manually this time like above gradle plugin, instead it
will build for you.
[Link] 328
Done!
Step 1: Add the dependency of latest ACRA AAR to your application gradle([Link]).
Step 2: In your application class(the class which extends Application; if not create it) Add a
@ReportsCrashes annotation and override the attachBaseContext() method.
@ReportsCrashes(
formUri = "Your choice of backend",
reportType = REPORT_TYPES(JSON/FORM),
httpMethod = HTTP_METHOD(POST/PUT),
formUriBasicAuthLogin = "AUTH_USERNAME",
formUriBasicAuthPassword = "AUTH_PASSWORD,
customReportContent = {
ReportField.USER_APP_START_DATE,
[Link] 329
ReportField.USER_CRASH_DATE,
ReportField.APP_VERSION_CODE,
ReportField.APP_VERSION_NAME,
ReportField.ANDROID_VERSION,
ReportField.DEVICE_ID,
[Link],
[Link],
ReportField.DEVICE_FEATURES,
ReportField.PACKAGE_NAME,
ReportField.REPORT_ID,
ReportField.STACK_TRACE,
},
mode = NOTIFICATION_TYPE(TOAST,DIALOG,NOTIFICATION)
resToastText = [Link].crash_text_toast)
Where AUTH_USERNAME and AUTH_PASSWORD are the credentials of your desired backends
.
<application
android:name=".MyApplication">
<service></service>
<activity></activity>
<receiver></receiver>
</application>
Step 5: Make sure you have internet permission to receive the report from crashed application
<uses-permission android:name="[Link]"/>
In case if you want to send the silent report to the backend then just use the below method to
achieve it.
[Link]().handleSilentException(e);
Add a button you can tap to trigger a crash. Paste this code into your layout where you’d like the
button to appear.
<Button
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="Force Crash!"
[Link] 330
android:onClick="forceCrash"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
Throw a RuntimeException
Run your app and tap the new button to cause a crash. In a minute or two you should be able to
see the crash on your Crashlytics dashboard as well as you will get a mail.
Sherlock captures all your crashes and reports them as a notification. When you tap on the
notification, it opens up an activity with all the crash details along with Device and Application info
dependencies {
compile('[Link]:sherlock:1.0.1@aar') {
transitive = true
}
}
After syncing your android studio, initialize Sherlock in your Application class.
package [Link];
import [Link];
import [Link];
Thats all you need to do. Also Sherlock does much more than just reporting a crash. To checkout
all its features take a look at this article.
Demo
[Link] 331
Read Crash Reporting Tools online: [Link]
[Link] 332
Chapter 65: Create Android Custom ROMs
Examples
Making Your Machine Ready for Building!
Before you can build anything, you are required to make your machine ready for building. For this
you need to install a lot of libraries and modules. The most recommended Linux distribution is
Ubuntu, so this example will focus on installing everything that is needed on Ubuntu.
Installing Java
First, add the following Personal Package Archive (PPA): sudo apt-add-repository ppa:openjdk-
r/ppa.
sudo apt-get install git-core python gnupg flex bison gperf libsdl1.2-dev libesd0-dev
libwxgtk2.8-dev squashfs-tools build-essential zip curl libncurses5-dev zlib1g-dev openjdk-8-
jre openjdk-8-jdk pngcrush schedtool libxml2 libxml2-utils xsltproc lzop libc6-dev schedtool
g++-multilib lib32z1-dev lib32ncurses5-dev gcc-multilib liblz4-* pngquant ncurses-dev texinfo
gcc gperf patch libtool automake g++ gawk subversion expat libexpat1-dev python-all-dev
binutils-static bc libcloog-isl-dev libcap-dev autoconf libgmp-dev build-essential gcc-
multilib g++-multilib pkg-config libmpc-dev libmpfr-dev lzma* liblzma* w3m android-tools-adb
maven ncftp figlet
Finally, let us set up the cache and the repo by the following commands:
[Link] 333
sudo install utils/repo /usr/bin/
sudo install utils/ccache /usr/bin/
Please note: We can also achieve this setup by running the automated scripts made by Akhil
Narang (akhilnarang), one of the maintainers of Resurrection Remix OS. These scripts can be
found on GitHub.
[Link] 334
Chapter 66: Create Singleton Class for Toast
Message
Introduction
Toast messages are the most simple way of providing feedback to the user. By default, Android
provide gray color message toast where we can set the message and the duration of the
message. If we need to create more customizable and reusable toast message, we can implement
it by ourselves with the use of a custom layout. More importantly when we are implementing it, the
use of Singelton design pattern will make it easy for maintaining and development of the custom
toast message class.
Syntax
• Toast Toast(Context contex)
• void setDuration(int duration)
• void setGravity(int gravity, int xOffset, int yOffset)
• void setView(View view)
• void show()
Parameters
Parameter details
Relevant context which needs to display your toast message. If you use this in
context
the activity pass "this" keyword or If you use in fragement pass as "getActivity()".
view Create a custom view and pass that view object to this.
Pass the gravity position of the toaster. All the position has added under the
gravity Gravity class as the static variables . The Most common positions are
[Link], [Link], [Link], [Link].
Remarks
Toast message is a simple way of providing feedback to user about something is happening. If
[Link] 335
you need a more advanced way to give feedback you can use dialogs or snackbar.
To get more details about the toast message please check this documentation.
[Link]
Examples
Create own singleton class for toast massages
Here is how to create your own singleton class for toast messages, If your application need to
show success, warning and the danger messages for different use cases you can use this class
after you have modified it to your own specifications.
switch (type){
case 0:
//if the message type is 0 fail toaster method will call
createFailToast(toastLayout,toastShowMessage,message);
break;
case 1:
//if the message type is 1 success toaster method will call
createSuccessToast(toastLayout,toastShowMessage,message);
break;
case 2:
createWarningToast( toastLayout, toastShowMessage, message);
//if the message type is 2 warning toaster method will call
break;
default:
createFailToast(toastLayout,toastShowMessage,message);
}
}
[Link] 336
//Failure toast message method
private final void createFailToast(LinearLayout toastLayout,TextView
toastMessage,String message){
[Link]([Link]().getColor([Link].button_alert_normal));
[Link](message);
[Link]([Link]().getColor([Link]));
showToast(context,toastLayout);
}
[Link]([Link]().getColor([Link].warning_toast));
[Link](message);
[Link]([Link]().getColor([Link]));
showToast(context, toastLayout);
}
//success toast message method
private final void createSuccessToast(LinearLayout toastLayout,TextView
toastMessage,String message){
[Link]([Link]().getColor([Link].success_toast));
[Link](message);
[Link]([Link]().getColor([Link]));
showToast(context,toastLayout);
}
[Link] 337
Chapter 67: Creating Custom Views
Examples
Creating Custom Views
If you need a completely customized view, you'll need to subclass View (the superclass of all
Android views) and provide your custom sizing (onMeasure(...)) and drawing (onDraw(...))
methods:
1. Create your custom view skeleton: this is basically the same for every custom view. Here
we create the skeleton for a custom view that can draw a smiley, called SmileyView:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {/* ... */}
@Override
protected void onDraw(Canvas canvas) {/* ... */}
}
2. Initialize your paints: the Paint objects are the brushes of your virtual canvas defining how
your geometric objects are rendered (e.g. color, fill and stroke style, etc.). Here we create
two Paints, one yellow filled paint for the circle and one black stroke paint for the eyes and
the mouth:
[Link] 338
[Link]([Link]);
mEyeAndMouthPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
[Link]([Link]);
[Link](16 * getResources().getDisplayMetrics().density);
[Link]([Link]);
[Link]([Link]);
}
3. Implement your own onMeasure(...) method: this is required so that the parent layouts
(e.g. FrameLayout) can properly align your custom view. It provides a set of measureSpecs that
you can use to determine your view's height and width. Here we create a square by making
sure that the height and width are the same:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = [Link](widthMeasureSpec);
int h = [Link](heightMeasureSpec);
Note that onMeasure(...) must contain at least one call to setMeasuredDimension(..) or else
your custom view will crash with an IllegalStateException.
4. Implement your own onSizeChanged(...) method: this allows you to catch the current height
and width of your custom view to properly adjust your rendering code. Here we just calculate
our center and our radius:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mCenterX = w / 2f;
mCenterY = h / 2f;
mRadius = [Link](w, h) / 2f;
}
5. Implement your own onDraw(...) method: this is where you implement the actual rendering
of your view. It provides a Canvas object that you can draw on (see the official Canvas
documentation for all drawing methods available).
@Override
protected void onDraw(Canvas canvas) {
// draw face
[Link](mCenterX, mCenterY, mRadius, mCirclePaint);
// draw eyes
float eyeRadius = mRadius / 5f;
float eyeOffsetX = mRadius / 3f;
float eyeOffsetY = mRadius / 3f;
[Link](mCenterX - eyeOffsetX, mCenterY - eyeOffsetY, eyeRadius,
mEyeAndMouthPaint);
[Link](mCenterX + eyeOffsetX, mCenterY - eyeOffsetY, eyeRadius,
mEyeAndMouthPaint);
// draw mouth
float mouthInset = mRadius /3f;
[Link] 339
[Link](mouthInset, mouthInset, mRadius * 2 - mouthInset, mRadius * 2 -
mouthInset);
[Link](mArcBounds, 45f, 90f, false, mEyeAndMouthPaint);
}
6. Add your custom view to a layout: the custom view can now be included in any layout files
that you have. Here we just wrap it inside a FrameLayout:
<FrameLayout
xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent">
<[Link]
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Note that it is recommended to build your project after the view code is finished. Without building it
you won't be able to see the view on a preview screen in Android Studio.
After putting everything together, you should be greeted with the following screen after launching
the activity containing the above layout:
Custom views can also take custom attributes which can be used in Android layout resource files.
To add attributes to your custom view you need to do the following:
1. Define the name and type of your attributes: this is done inside res/values/[Link]
(create it if necessary). The following file defines a color attribute for our smiley's face color
[Link] 340
and an enum attribute for the smiley's expression:
<resources>
<declare-styleable name="SmileyView">
<attr name="smileyColor" format="color" />
<attr name="smileyExpression" format="enum">
<enum name="happy" value="0"/>
<enum name="sad" value="1"/>
</attr>
</declare-styleable>
<!-- attributes for other views -->
</resources>
2. Use your attributes inside your layout: this can be done inside any layout files that use
your custom view. The following layout file creates a screen with a happy yellow smiley:
<FrameLayout xmlns:android="[Link]
xmlns:app="[Link]
android:layout_height="match_parent"
android:layout_width="match_parent">
<[Link]
android:layout_height="56dp"
android:layout_width="56dp"
app:smileyColor="#ffff00"
app:smileyExpression="happy" />
</FrameLayout>
Tip: Custom attributes do not work with the tools: prefix in Android Studio 2.1 and older (and
possibly in future versions). In this example, replacing app:smileyColor with tools:smileyColor
would result in smileyColor neither being set during runtime nor at design time.
3. Read your attributes: this is done inside your custom view source code. The following
snippet of SmileyView demonstrates how the attributes can be extracted:
[Link] 341
// initPaints(); ...
}
}
4. (Optional) Add default style: this is done by adding a style with the default values and
loading it inside your custom view. The following default smiley style represents a happy
yellow one:
Which gets applied in our SmileyView by adding it as the last parameter of the call to
obtainStyledAttributes (see code in step 3):
Note that any attribute values set in the inflated layout file (see code in step 2) will override
the corresponding values of the default style.
5. (Optional) Provide styles inside themes: this is done by adding a new style reference
attribute which can be used inside your themes and providing a style for that attribute. Here
we simply name our reference attribute smileyStyle:
Which we then provide a style for in our app theme (here we just reuse the default style from
step 4):
A compound view is a custom ViewGroup that's treated as a single view by the surrounding
program code. Such a ViewGroup can be really useful in DDD-like design, because it can
correspond to an aggregate, in this example, a Contact. It can be reused everywhere that contact
is displayed.
This means that the surrounding controller code, an Activity, Fragment or Adapter, can simply
pass the data object to the view without picking it apart into a number of different UI widgets.
This facilitates code reuse and makes for a better design according to SOLID priciples.
[Link] 342
The layout XML
This is usually where you start. You have an existing bit of XML that you find yourself reusing,
perhaps as an <include/>. Extract it into a separate XML file and wrap the root tag in a <merge>
element:
<ImageView
android:id="@+id/photo"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentRight="true" />
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/photo" />
<TextView
android:id="@+id/phone_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/name"
android:layout_toLeftOf="@id/photo" />
</merge>
This XML file keeps working in the Layout Editor in Android Studio perfectly fine. You can treat it
like any other layout.
Once you have the XML file, create the custom view group.
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import myapp.R;
/**
* A compound view to show contacts.
*
* This class can be put into an XML layout or instantiated programmatically, it
* will work correctly either way.
*/
public class ContactView extends RelativeLayout {
[Link] 343
// This class extends RelativeLayout because that comes with an automatic
// (MATCH_PARENT, MATCH_PARENT) layout for its child item. You can extend
// the raw [Link] class if you want more control. See the
// note in the layout XML why you wouldn't want to extend a complex view
// such as RelativeLayout.
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ContactView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
// 3. Define a setter that's expressed in your domain model. This is what the example is
// all about. All controller code can just invoke this setter instead of fiddling with
// lots of strings, visibility options, colors, animations, etc. If you don't use a
// custom view, this code will usually end up in a static helper method (bad) or copies
The init(Context, AttributeSet) method is where you would read any custom XML attributes as
explained in Adding Attributes to Views.
Usage in XML
[Link] 344
Here's an example fragment_contact_info.xml that illustrates how you'd put a single ContactView
on top of a list of messages:
<LinearLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- The compound view becomes like any other view XML element -->
<[Link]
android:id="@+id/contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<[Link]
android:id="@+id/message_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
Usage in Code
Here's an example [Link] that shows a list of contacts. This example illustrates just
how much cleaner the controller code gets when it's completely free of View manipulation.
package myapp;
import [Link];
import [Link];
import [Link];
@Override
public ContactsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ContactView v = new ContactView(context); // <--- this
return new ContactsViewHolder(v);
}
@Override
public void onBindViewHolder(ContactsViewHolder holder, int position) {
Contact contact = [Link](position);
[Link](contact); // <--- this
}
[Link] 345
public void setContact(Contact contact) {
((ContactView) itemView).setContact(contact); // <--- this
}
}
}
@Override
protected void onDraw(Canvas canvas) {
[Link](canvas);
Paint paint = new Paint(); //Do not allocate here
}
[Link](boundsRect);
[Link](canvas);
Do not redraw the entire view to update just a small part of it. Instead redraw the specific part of
view.
invalidate(boundToBeRefreshed);
If your view is doing some continuous animation, for instance a watch-face showing each and
every second, at least stop the animation at onStop() of the activity and start it back on onStart() of
the activity.
Do not do any calculations inside the onDraw method of a view, you should instead finish drawing
before calling invalidate(). By using this technique you can avoid frame dropping in your view.
Rotations
The basic operations of a view are translate, rotate, etc... Almost every developer has faced this
problem when they use bitmap or gradients in their custom view. If the view is going to show a
rotated view and the bitmap has to be rotated in that custom view, many of us will think that it will
be expensive. Many think that rotating a bitmap is very expensive because in order to do that, you
need to translate the bitmap's pixel matrix. But the truth is that it is not that tough! Instead of
rotating the bitmap, just rotate the canvas itself!
[Link] 346
// Rotate the canvas by providing the center point as pivot and angle
[Link](pivotX, pivotY, angle);
// Draw whatever you want
// Basically whatever you draw here will be drawn as per the angle you rotated the canvas
[Link](...);
// Now restore your your canvas to its original state
[Link](save);
// Unless canvas is restored to its original state, further draw will also be rotated.
Main motive to develop this compound view is, below 5.0 devices does not support svg in
drawable inside TextView/EditText. One more pros is, we can set height and width of drawableRight
inside EditText. I have separated it from my project and created in separate module.
[Link]
dependencies {
compile '[Link]:appcompat-v7:25.3.1'
}
<EditText
android:id="@+id/edt_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1"
android:paddingEnd="40dp"
android:paddingLeft="5dp"
android:paddingRight="40dp"
android:paddingStart="5dp" />
[Link] 347
android:layout_gravity="right|center_vertical"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" />
</FrameLayout>
Code : [Link]
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public EditTextWithDrawable(Context context, AttributeSet attrs, int defStyleAttr, int
defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs);
}
[Link] 348
int drawableRes =
[Link](
[Link].EditTextWithDrawable_c_e_d_drawableRightSVG, -1);
if (drawableRes != -1) {
[Link](drawableRes);
}
[Link]([Link](
[Link].EditTextWithDrawable_c_e_d_hint));
[Link]([Link](
[Link].EditTextWithDrawable_c_e_d_textColor, [Link]));
int textSize =
[Link]([Link].EditTextWithDrawable_c_e_d_textSize, 15);
[Link](TypedValue.COMPLEX_UNIT_PX, textSize);
[Link] layoutParams =
[Link]();
[Link] = (textSize * 3) / 2;
[Link] = (textSize * 3) / 2;
[Link](layoutParams);
[Link]();
}
}
}
<LinearLayout xmlns:android="[Link]
xmlns:app="[Link]
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<[Link]
android:id="@+id/edt_search_emp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:c_e_d_drawableRightSVG="@drawable/ic_svg_search"
app:c_e_d_hint="@string/hint_search_here"
app:c_e_d_textColor="@color/text_color_dark_on_light_bg"
app:c_e_d_textSize="@dimen/text_size_small" />
</LinearLayout>
Activity : [Link]
[Link] 349
Responding to Touch Events
Many custom views need to accept user interaction in the form of touch events. You can get
access to touch events by overriding onTouchEvent. There are a number of actions you can filter
out. The main ones are
• ACTION_DOWN:
This is triggered once when your finger first touches the view.
• ACTION_MOVE: This is called every time your finger moves a little across the view. It gets called
many times.
• ACTION_UP: This is the last action to be called as you lift your finger off the screen.
You can add the following method to your view and then observe the log output when you touch
and move your finger around your view.
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.i("CustomView", "onTouchEvent: ACTION_DOWN: x = " + x + ", y = " + y);
break;
case MotionEvent.ACTION_MOVE:
Log.i("CustomView", "onTouchEvent: ACTION_MOVE: x = " + x + ", y = " + y);
break;
case MotionEvent.ACTION_UP:
Log.i("CustomView", "onTouchEvent: ACTION_UP: x = " + x + ", y = " + y);
break;
}
return true;
}
Further reading:
[Link] 350
Chapter 68: Creating Overlay (always-on-top)
Windows
Examples
Popup overlay
In order to put your view on top of every application, you have to assign your view to the
corresponding window manager. For that you need the system alert permission, which can be
requested by adding the following line to your manifest file:
Note: If your application gets destroyed, your view will be removed from the window manager.
Therefore, it is better to create the view and assign it to the window manager by a foreground
service.
In order to define the position of your view, you have to create some layout parameters as follows:
Now, you can assign your view together with the created layout parameters to the window
manager instance as follows:
[Link](yourView, mLayoutParams);
Voila! Your view has been successfully placed on top of all other applications.
[Link] 351
From android 6.0 this permission needs to grant dynamically,
<uses-permission android:name="[Link].SYSTEM_ALERT_WINDOW"/>
Solution :-
if(){
// ask for setting
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
[Link]("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OVERLAY_PERMISSION) {
if ([Link](this)) {
// permission granted...
}else{
// permission not granted...
}
}
}
[Link] 352
Chapter 69: Creating Splash screen
Remarks
The first example(a basic splash screen) is not the most efficient way to handle it. As such, it is
basic splash screen.
Examples
A basic splash screen
A splash screen is just like any other activity, but it can handle all of your startup-needs in the
background. Example:
Manifest:
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".Splash"
android:label="@string/app_name"
>
<intent-filter>
<action android:name="[Link]" />
</application>
</manifest>
Here is an example splashscreen that also handles some critical app elements:
[Link] 353
if ([Link](this, [Link].WAKE_LOCK) !=
PackageManager.PERMISSION_GRANTED ||
[Link](this,[Link]) !=
PackageManager.PERMISSION_GRANTED ||
[Link](this,
[Link].ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED) {//Can add
more as per requirement
[Link](this,
new String[]{[Link].WAKE_LOCK,
[Link],
[Link].ACCESS_NETWORK_STATE},
123);
}
}
@Override
protected void onCreate(Bundle sis){
[Link](sis);
//set the content view. The XML file can contain nothing but an image, such as a logo
or the app icon
setContentView([Link]);
//we want to display the splash screen for a few seconds before it automatically
//disappears and loads the game. So we create a thread:
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//request permissions. NOTE: Copying this and the manifest will cause the app
to crash as the permissions requested aren't defined in the manifest.
if ([Link].SDK_INT >= Build.VERSION_CODES.M ) {
checkPermission();
}
String lang = [load or determine the system language and set to default if
it isn't available.]
Locale locale = new Locale(lang);
[Link](locale);
Configuration config = new Configuration ();
[Link] = locale;
[Link]().updateConfiguration(config,
[Link]().getDisplayMetrics()) ;
[Link] 354
}
This example shows a simple but effective splash screen with animation that can be created by
using Android Studio.
[Link] 355
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
startActivity(new Intent(this,[Link]));
// [Link] is the activity to go after showing the splash screen.
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
[Link](anim);
}
}
<activity
android:name=".Splash"
android:theme="@style/[Link]">
<intent-filter>
<action android:name="[Link]" />
Then, remove the default launcher activity by removing the following code from the
[Link] 356
AndroidManifest file:
<intent-filter>
<action android:name="[Link]" />
[Link] 357
Chapter 70: Creating your own libraries for
Android applications
Examples
Creating library project
To create a libary , you should use File -> New -> New Module -> Android Library. This will create a
basic library project.
When that's done, you must have a project that is set up the following manner:
[libs]
[src]
[main]
[java]
[library package]
[test]
[java]
[library package]
[Link] //"app"-level
[Link]
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
minSdkVersion 14
targetSdkVersion 23
[Link] 358
}
}
To use the library, you must include it as a dependency with the following line:
3. Modify your library project's [Link] file by adding the following code:
...
artifacts {
archives sourcesJar
archives javadocJar
}
[Link] 359
6. Your library is now available by the following dependency:
[Link] 360
Chapter 71: Custom Fonts
Examples
Putting a custom font in your app
Initializing a font
[Link]:
[Link] 361
TypedArray a = [Link](attrs, [Link]);
String customFont = [Link]([Link].TextViewPlus_customFont);
setCustomFont(ctx, customFont);
[Link]();
}
setTypeface(typeface);
return true;
}
}
How to use:
<[Link]
android:id="@+id/textViewPlus1"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:text="@string/showingOffTheNewTypeface"
foo:customFont="my_font_name_regular.otf">
</[Link]>
</LinearLayout>
[Link] 362
Efficient Typeface loading
Loading custom fonts can be lead to a bad performance. I highly recommend to use this little
helper which saves/loads your already used fonts into a Hashtable.
/**
* Get typeface by filename from assets main directory
*
* @param context
* @param fileName the name of the font file in the asset main directory
* @return
*/
public static Typeface getTypeFace(final Context context, final String fileName) {
Typeface tempTypeface = [Link](fileName);
if (tempTypeface == null) {
tempTypeface = [Link]([Link](), fileName);
[Link](fileName, tempTypeface);
}
return tempTypeface;
}
Usage:
[Link] 363
Then in your activity, in onCreate() method:
Android O introduces a new feature, called Fonts in XML, which allows you to use fonts as
resources. This means, that there is no need to bundle fonts as assets. Fonts are now compiled in
an R file and are automatically available in the system as a resource.
You can also create your own font family by adding the following XML file into the res/font
directory:
You can use both the font file and the font family file in the same way:
• In an XML file, by using the android:fontFamily attribute, for example like this:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/myfont"/>
Or like this:
[Link] 364
Typeface typeface = getResources().getFont([Link]);
[Link](typeface);
[Link] 365
Chapter 72: Dagger 2
Syntax
• @Module
• @Component(dependencies={[Link]}, modules={[Link],
[Link]})
• [Link]()
• [Link]().myModule(newMyModule()).create()
Remarks
Not to confuse with dagger by square, the predecessor to dagger 2.
Examples
Component setup for Application and Activity injection
@Singleton
@Component(modules = [Link])
public interface AppComponent {
Context provideContext();
Gson provideGson();
}
A module to use together with the AppComponent which will provide its singleton objects, e.g. an
instance of Gson to reuse throughout the whole application.
@Module
public class AppModule {
@Singleton
@Provides
Gson provideGson() {
return new Gson();
}
[Link] 366
@Singleton
@Provides
Context provideContext() {
return mApplication;
}
}
@Inject
AppComponent mAppComponent;
@Override
public void onCreate() {
[Link]();
[Link]().appModule(new AppModule(this)).build().inject(this);
}
Now an activity scoped component that depends on the AppComponent to gain access to the
singleton objects.
@ActivityScope
@Component(dependencies = [Link], modules = [Link])
public interface MainActivityComponent {
And a reusable ActivityModule that will provide basic dependencies, like a FragmentManager
@Module
public class ActivityModule {
@ActivityScope
public AppCompatActivity provideActivity() {
return mActivity;
}
@ActivityScope
public FragmentManager provideFragmentManager(AppCompatActivity activity) {
return [Link]();
[Link] 367
}
}
Putting everything together we're set up and can inject our activity and be sure to use the same
Gson throughout out app!
@Inject
Gson mGson;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
[Link]()
.appComponent(((App)getApplication()).getAppComponent())
.activityModule(new ActivityModule(this))
.build().inject(this);
}
}
Custom Scopes
@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScope {
}
Scopes are just annotations and you can create your own ones where needed.
Constructor Injection
This class can be provided by any component. It has no dependencies itself and is not scoped.
There is no further code necessary.
Dependencies are declared as parameters in the constructor. Dagger will call the constructor and
supply the dependencies, as long as those dependencies can be provided.
[Link] 368
private Engine engine;
@Inject
public Car(Engine engine) {
[Link] = engine;
}
}
This class can be provided by every component iff this component can also provide all of its
dependencies—Engine in this case. Since Engine can also be constructor injected, any component
can provide a Car.
You can use constructor injection whenever all of the dependencies can be provided by the
component. A component can provide a dependency, if
@Singleton
@Component(modules = [Link])
public interface AppComponent {
void inject(App app);
Context provideContext();
Gson provideGson();
@ActivityScope
@Subcomponent(modules = [Link])
public interface MainActivityComponent {
void inject(MainActivity activity);
}
@Inject
Gson mGson;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
((App)getApplication()).getAppComponent()
.mainActivityComponent(new ActivityModule(this)).inject(this);
}
}
[Link] 369
Since the release of Gradle 2.2, the use of the android-apt plugin is no longer used. The following
method of setting up Dagger 2 should be used. For older version of Gradle, use the previous
method shown below.
dependencies {
// apt command comes from the android-apt plugin
annotationProcessor '[Link]:dagger-compiler:2.8'
compile '[Link]:dagger:2.8'
provided '[Link]:jsr250-api:1.0'
}
To use Dagger 2 it's necessary to add android-apt plugin, add this to the root [Link]:
buildscript {
dependencies {
classpath '[Link]:gradle:2.1.0'
classpath '[Link]:android-apt:1.8'
}
}
android {
…
}
compile "[Link]:dagger:${DAGGER_VERSION}"
apt "[Link]:dagger-compiler:${DAGGER_VERSION}"
}
Reference: [Link]
Dagger 2 supports creating a component from multiple modules. You can create your component
this way:
@Singleton
@Component(modules = {[Link], [Link]})
public interface MyMultipleModuleComponent {
void inject(MyFragment myFragment);
void inject(MyService myService);
[Link] 370
void inject(MyController myController);
void inject(MyActivity myActivity);
}
The two references modules GeneralPurposeModule and SpecificModule can then be implemented as
follows:
[Link]
@Module
public class GeneralPurposeModule {
@Provides
@Singleton
public Retrofit getRetrofit(PropertiesReader propertiesReader, RetrofitHeaderInterceptor
headerInterceptor){
// Logic here...
return retrofit;
}
@Provides
@Singleton
public PropertiesReader getPropertiesReader(){
return new PropertiesReader();
}
@Provides
@Singleton
public RetrofitHeaderInterceptor getRetrofitHeaderInterceptor(){
return new RetrofitHeaderInterceptor();
}
}
[Link]
@Singleton
@Module
public class SpecificModule {
@Provides @Singleton
public RetrofitController getRetrofitController(Retrofit retrofit){
RetrofitController retrofitController = new RetrofitController();
[Link](retrofit);
return retrofitController;
}
@Provides @Singleton
public MyService getMyService(RetrofitController retrofitController){
MyService myService = new MyService();
[Link](retrofitController);
return myService;
}
}
During the dependency injection phase, the component will take objects from both modules
according to the needs.
This approach is very useful in terms of modularity. In the example, there is a general purpose
[Link] 371
module used to instantiate components such as the Retrofit object (used to handle the network
communication) and a PropertiesReader (in charge of handling configuration files). There is also a
specific module that handles the instantiation of specific controllers and service classes in relation
to that specific application component.
[Link] 372
Chapter 73: Data Binding Library
Remarks
Setup
Before using data binding, you must enable the plugin in your [Link].
android {
....
dataBinding {
enabled = true
}
}
Note: Data binding was added to the Android Gradle plugin in version 1.5.0
The data binding plugin generates a binding class name by converting your layout's file name to
Pascal case and adding "Binding" to the end. Thus item_detail_activity.xml will generate a class
named ItemDetailActivityBinding.
Resources
• Official documentation
Examples
Basic text field binding
android {
....
dataBinding {
enabled = true
}
}
Data model
[Link] 373
}
}
Layout XML
The first step is wrapping your layout in a <layout> tag, adding a <data> element, and adding a
<variable> element for your data model.
Then you can bind XML attributes to fields in the data model using @{[Link]}, where model
is the variable's name and fieldname is the field you want to access.
item_detail_activity.xml:
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{[Link]}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{[Link]}"/>
</LinearLayout>
</layout>
For each XML layout file properly configured with bindings, the Android Gradle plugin generates a
corresponding class : bindings. Because we have a layout named item_detail_activity, the
corresponding generated binding class is called ItemDetailActivityBinding.
[Link] 374
If your model has private methods, the databinding library still allows you to access them in your
view without using the full name of the method.
Data model
Layout XML
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
</layout>
Referencing classes
Data model
Layout XML
[Link] 375
<import type="[Link]"/>
<variable name="item" type="[Link]"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- We reference the View class to set the visibility of this TextView -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{[Link]}"
android:visibility="@{[Link] == null ? [Link] : [Link]"/>
</LinearLayout>
</layout>
Note: The package [Link].* is imported automatically by the system. (The same is made by
JVM for Java)
Databinding in Fragment
Data Model
Layout XML
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{[Link]}"/>
[Link] 376
</LinearLayout>
</layout>
Fragment
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable
Bundle savedInstanceState) {
FragmentTest binding = [Link](inflater, [Link].fragment_test,
container, false);
Item item = new Item();
[Link]("Thomas");
[Link](item);
return [Link]();
}
Element Properties
AbsListView android:selectedItemPosition
CalendarView android:date
CompoundButton android:checked
• android:year
DatePicker • android:month
• android:day
EditText android:text
NumberPicker android:value
RadioGroup android:checkedButton
RatingBar android:rating
SeekBar android:progress
TabHost android:currentTab
TextView android:text
• android:hour
TimePicker
• android:minute
ToggleButton android:checked
Switch android:checked
[Link] 377
Usage
<layout ...>
<data>
<variable type="[Link]" name="user"/>
</data>
<RelativeLayout ...>
<EditText android:text="@={[Link]}" .../>
</RelativeLayout>
</layout>
Notice that the Binding expression @={} has an additional =, which is necessary for the two-way
Binding. It is not possible to use methods in two-way Binding expressions.
It's also possible to use data binding within your RecyclerView Adapter.
Data model
XML Layout
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{[Link]}"/>
Adapter class
@Override
public [Link] onCreateViewHolder(ViewGroup parent, int viewType) {
// inflate layout and retrieve binding
ListItemBinding binding = [Link]([Link](),
[Link] 378
[Link].list_item, parent, false);
@Override
public void onBindViewHolder([Link] holder, int position) {
Item item = [Link](position);
@Override
public int getItemCount() {
return [Link]();
}
ItemViewHolder(ListItemBinding binding) {
super([Link]());
[Link] = binding;
}
Layout XML
<data>
<variable
name="handler"
type="[Link]"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
[Link] 379
android:layout_height="wrap_content"
android:text="click me"
android:onClick="@{[Link]}"/>
</RelativeLayout>
</layout>
@Override
public void onButtonClick(View v) {
[Link](context,"Button clicked",Toast.LENGTH_LONG).show();
}
}
Define Interface
Layout XML
<layout xmlns:android="[Link]
<data>
[Link] 380
<variable
name="handler"
type="[Link]"/>
<variable
name="user"
type="[Link]"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{[Link]}"
android:onClick="@{() -> [Link](user)}"/>
</RelativeLayout>
</layout>
Activity code :
@Override
public void onButtonClick(User user) {
[Link]([Link],"Welcome " +
[Link](),Toast.LENGTH_LONG).show();
}
}
For some view listener which is not available in xml code but can be set in java code, it can be
bind with custom binding.
Custom class
[Link] 381
}
Handler class
XML
<layout
xmlns:android="[Link]
xmlns:bind="[Link] >
<data>
<variable
name="handler"
type="[Link]" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<AutoCompleteTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
bind:autoAdapter="@{[Link]}" />
</LinearLayout>
</layout>
The Preview pane displays default values for data binding expressions if provided.
For example :
android:layout_height="@{@dimen/main_layout_height, default=wrap_content}"
It will take wrap_content while designing and will act as a wrap_content in preview pane.
Another example is
[Link] 382
It will display Preview Text in preview pane but when you run it in device/emulator actual text
binded to it will be displayed
Sometimes we need to perform basic operations like hide/show view based on single value, for
that single variable we cannot create model or it is not good practice to create model for that.
DataBinding supports basic datatypes to perform those oprations.
<layout xmlns:android="[Link]
<data>
<variable
name="selected"
type="Boolean" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World"
android:visibility="@{selected ? [Link] : [Link]}" />
</RelativeLayout>
</layout>
[Link](true);
Databinding in Dialog
Layout XML
[Link] 383
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="[Link]
<data>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="100dp"
app:imageUrl="@{url}"
app:progressbar="@{progressBar}"/>
</LinearLayout>
</layout>
BindingAdapter method
@BindingAdapter({"imageUrl","progressbar"})
public static void loadImage(ImageView view, String imageUrl, ProgressBar progressBar){
[Link]([Link]()).load(imageUrl)
.listener(new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model,
Target<GlideDrawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, String model,
Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
[Link]([Link]);
return false;
}
}).into(view);
}
[Link] 384
Chapter 74: Data Encryption/Decryption
Introduction
This topic discusses how encryption and decryption works in Android.
Examples
AES encryption of data using password in a secure way
The following example encrypts a given data block using AES. The encryption key is derived in a
secure way (random salt, 1000 rounds of SHA-256). The encryption uses AES in CBC mode with
random IV.
Note that the data stored in the class EncryptedData (salt, iv, and encryptedData) can be
concatenated to a single byte array. You can then save the data or transmit it to the recipient.
private byte[] decrypt(String password, byte[] salt, byte[] iv, byte[] encryptedData) throws
NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException,
InvalidAlgorithmParameterException {
PBEKeySpec keySpec = new PBEKeySpec([Link](), salt, PBK_ITERATIONS);
SecretKeyFactory secretKeyFactory = [Link](PBE_ALGORITHM);
Key key = [Link](keySpec);
Cipher cipher = [Link]("AES/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
[Link](Cipher.DECRYPT_MODE, key, ivSpec);
return [Link](encryptedData);
[Link] 385
}
The following example code shows how to test encryption and decryption:
try {
String password = "test12345";
byte[] data = "plaintext11223344556677889900".getBytes("UTF-8");
EncryptedData encData = encrypt(password, data);
byte[] decryptedData = decrypt(password, [Link], [Link], [Link]);
String decDataAsString = new String(decryptedData, "UTF-8");
[Link](this, decDataAsString, Toast.LENGTH_LONG).show();
} catch (Exception e) {
[Link]();
}
[Link] 386
Chapter 75: Data Synchronization with Sync
Adapter
Examples
Dummy Sync Adapter with Stub Provider
SyncAdapter
/**
* Define a sync adapter for the app.
* <p/>
* <p>This class is instantiated in {@link SyncService}, which also binds SyncAdapter to the
system.
* SyncAdapter should only be initialized in SyncService, never anywhere else.
* <p/>
* <p>The system calls onPerformSync() via an RPC call through the IBinder object supplied by
* SyncService.
*/
class SyncAdapter extends AbstractThreadedSyncAdapter {
/**
* Constructor. Obtains handle to content resolver for later use.
*/
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
/**
* Constructor. Obtains handle to content resolver for later use.
*/
public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
//Jobs you want to perform in background.
Log.e("" + [Link], "Sync Start");
}
Sync Service
/**
* Define a Service that returns an IBinder for the
* sync adapter class, allowing the sync adapter framework to call
* onPerformSync().
*/
public class SyncService extends Service {
// Storage for an instance of the sync adapter
private static SyncAdapter sSyncAdapter = null;
// Object to use as a thread-safe lock
[Link] 387
private static final Object sSyncAdapterLock = new Object();
/*
* Instantiate the sync adapter object.
*/
@Override
public void onCreate() {
/*
* Create the sync adapter as a singleton.
* Set the sync adapter as syncable
* Disallow parallel syncs
*/
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
}
}
}
/**
* Return an object that allows the system to invoke
* the sync adapter.
*/
@Override
public IBinder onBind(Intent intent) {
/*
* Get the object that allows external processes
* to call onPerformSync(). The object is created
* in the base class code when the SyncAdapter
* constructors call super()
*/
return [Link]();
}
}
Authenticator
[Link] 388
// Ignore attempts to confirm credentials
@Override
public Bundle confirmCredentials(
AccountAuthenticatorResponse r,
Account account,
Bundle bundle) throws NetworkErrorException {
return null;
}
Authenticator Service
/**
* A bound Service that instantiates the authenticator
* when started.
*/
public class AuthenticatorService extends Service {
// Instance field that stores the authenticator object
private Authenticator mAuthenticator;
@Override
public void onCreate() {
// Create a new authenticator object
mAuthenticator = new Authenticator(this);
}
/*
* When the system binds to this Service to make the RPC call
[Link] 389
* return the authenticator's IBinder.
*/
@Override
public IBinder onBind(Intent intent) {
return [Link]();
}
}
[Link] additions
<service
android:name=".[Link]"
android:exported="true">
<intent-filter>
<action android:name="[Link]" />
</intent-filter>
<meta-data
android:name="[Link]"
android:resource="@xml/syncadapter" />
</service>
<service android:name=".[Link]">
<intent-filter>
<action android:name="[Link]" />
</intent-filter>
<meta-data
android:name="[Link]"
android:resource="@xml/authenticator" />
</service>
<provider
android:name=".[Link]"
android:authorities="[Link]"
android:exported="false"
android:syncable="true" />
res/xml/[Link]
res/xml/[Link]
[Link] 390
android:userVisible="false" />
StubProvider
/*
* Define an implementation of ContentProvider that stubs out
* all methods
*/
public class StubProvider extends ContentProvider {
/*
* Always return true, indicating that the
* provider loaded correctly.
*/
@Override
public boolean onCreate() {
return true;
}
/*
* Return no type for MIME type
*/
@Override
public String getType(Uri uri) {
return null;
}
/*
* query() always returns no results
*
*/
@Override
public Cursor query(
Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder) {
return null;
}
/*
* insert() always returns null (no URI)
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
/*
* delete() always returns "no rows affected" (0)
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
/*
* update() always returns "no rows affected" (0)
*/
public int update(
[Link] 391
Uri uri,
ContentValues values,
String selection,
String[] selectionArgs) {
return 0;
}
}
Call this function on successful login to create an account with the logged-in user ID
Forcing a Sync
[Link] 392
Chapter 76: Date and Time Pickers
Examples
Material DatePicker
add below dependencies to [Link] file in dependency section. (this is an unOfficial library for
date picker)
compile '[Link]:materialdatetimepicker:2.3.0'
<Button
android:id="@+id/dialog_bt_date"
android:layout_below="@+id/resetButton"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:textColor="#FF000000"
android:gravity="center"
android:text="DATE"/>
Button button;
Calendar calendar ;
DatePickerDialog datePickerDialog ;
int Year, Month, Day ;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
calendar = [Link]();
Year = [Link]([Link]) ;
Month = [Link]([Link]);
Day = [Link](Calendar.DAY_OF_MONTH);
[Link] 393
Month, Day);
[Link](false);
[Link](false);
[Link]([Link]("#0072BA"));
[Link](getFragmentManager(), "DatePickerDialog");
}
});
}
@Override
public void onDateSet(DatePickerDialog view, int Year, int Month, int Day) {
String date = "Selected Date : " + Day + "-" + Month + "-" + Year;
Output :
[Link] 394
Date Picker Dialog
It is a dialog which prompts user to select date using DatePicker. The dialog requires context, initial
year, month and day to show the dialog with starting date. When the user selects the date it
callbacks via [Link].
[Link] 395
{
DatePickerDialog datePickerDialog = new DatePickerDialog(context,
new [Link]() {
@Override
public void onDateSet(DatePicker datepicker,int year ,int month, int day)
{
//this condition is necessary to work properly on all android versions
if([Link]()){
//You now have the selected year, month and day
}
}
}, initialYear, initialMonth , initialDay);
Please note that month is a int starting from 0 for January to 11 for December
[Link] 396
Chapter 77: DayNight Theme (AppCompat
v23.2 / API 14+)
Examples
Adding the DayNight theme to an app
The DayNight theme gives an app the cool capability of switching color schemes based on the
time of day and the device's last known location.
The themes you can extend from to add day night theme switching capability are the following:
• "[Link]"
• "[Link]"
• "[Link]"
Apart from colorPrimary, colorPrimaryDark and colorAccent, you can also add any other colors that
you would like to be switched, e.g. textColorPrimary or textColorSecondary. You can add your app's
custom colors to this style as well.
For theme switching to work, you need to define a default [Link] in the res/values directory
and another [Link] in the res/values-night directory and define day/night colors appropriately.
To switch the theme, call the [Link](int) method from your Java
code. (This will change the color scheme for the whole app, not just any one activity or fragment.)
For example:
[Link](AppCompatDelegate.MODE_NIGHT_NO);
You can pass any of the following three according to your choice:
• AppCompatDelegate.MODE_NIGHT_NO:this sets the default theme for your app and takes the colors
defined in the res/values directory. It is recommended to use light colors for this theme.
• AppCompatDelegate.MODE_NIGHT_YES: this sets a night theme for your app and takes the colors
defined in the res/values-night directory. It is recommended to use dark colors for this
theme.
• AppCompatDelegate.MODE_NIGHT_AUTO: this auto switches the colors of the app based on the time
of the day and the colors you have defined in values and values-night directories.
[Link] 397
It is also possible to get the current night mode status using the getDefaultNightMode() method. For
example:
Please note, however, that the theme switch will not persist if you kill the app and reopen it. If you
do that, the theme will switch back to AppCompatDelegate.MODE_NIGHT_AUTO, which is the default value.
If you want the theme switch to persist, make sure you store the value in shared preferences and
load the stored value each time the app is opened after it has been destroyed.
[Link] 398
Chapter 78: Define step value (increment) for
custom RangeSeekBar
Introduction
A customization of the Android RangeSeekBar proposed by Alex Florescu at
[Link]
It allows to define a step value (increment), when moving the seek bar
Remarks
1- Add the increment attribute in [Link]
3- Init the increment value in private void init(Context context, AttributeSet attrs)
if (attrs == null)
increment = DEFAULT_INCREMENT;
else
increment = [Link]([Link].RangeSeekBar_increment, DEFAULT_INCREMENT);
4- Define the increment value in protected synchronized void onDraw(@NonNull Canvas canvas)
• minText = valueToString(getSelectedMinValue());
• maxText = valueToString(getSelectedMaxValue());
x = (int) ((getSelectedMinValue().intValue()+increment)/increment);
x = x*increment;
if (x<[Link]())
minText = ""+x;
else
minText=""+([Link]()-increment);
x = (int) ((getSelectedMaxValue().intValue()+increment)/increment);
x = x*increment;
maxText = ""+x;
[Link] 399
5 - Now you just have to use it. Hope it helps
Examples
Define a step value of 7
<RangeSeekBar
android:id="@+id/barPrice"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:barHeight="0.2dp"
app:barHeight2="4dp"
app:increment="7"
app:showLabels="false" />
[Link] 400
Chapter 79: Design Patterns
Introduction
Design patterns are formalized best practices that the programmer can use to solve common
problems when designing an application or system.
Design patterns can speed up the development process by providing tested, proven development
paradigms.
Reusing design patterns helps to prevent subtle issues that can cause major problems, and it also
improves code readability for coders and architects who are familiar with the patterns.
Examples
Singleton Class Example
To implement Singleton pattern, we have different approaches but all of them have following
common concepts.
/**
* Singleton class.
*/
public final class Singleton {
/**
* Private constructor so nobody can instantiate the class.
*/
private Singleton() {}
/**
* Static to class instance of the class.
*/
private static final Singleton INSTANCE = new Singleton();
/**
* To be called by user to obtain instance of the class.
*
* @return instance of the singleton.
*/
public static Singleton getInstance() {
return INSTANCE;
}
}
[Link] 401
Observer pattern
The observer pattern is a common pattern, which is widely used in many contexts. A real example
can be taken from YouTube: When you like a channel and want to get all news and watch new
videos from this channel, you have to subscribe to that channel. Then, whenever this channel
publishes any news, you (and all other subscribers) will receive a notification.
An observer will have two components. One is a broadcaster (channel) and the other is a receiver
(you or any other subscriber). The broadcaster will handle all receiver instances that subscribed to
it. When the broadcaster fires a new event, it will announce this to all receiver instances. When the
receiver receives an event, it will have to react to that event, for example, by turning on YouTube
and playing the new video.
class Channel{
private List<Subscriber> subscribers;
public void subscribe(Subscriber sub) {
// Add new subscriber.
}
public void unsubscribe(Subscriber sub) {
// Remove subscriber.
}
public void newEvent() {
// Notification event for all subscribers.
}
}
2. The receiver needs to implement a method that handles the event from the broadcaster:
interface Subscriber {
void doSubscribe(Channel channel);
void doUnsubscribe(Channel channel);
void handleEvent(); // Process the new event.
}
[Link] 402
Chapter 80: Detect Shake Event in Android
Examples
Shake Detector in Android Example
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// ignore
}
@Override
public void onSensorChanged(SensorEvent event) {
if (mListener != null) {
float x = [Link][0];
float y = [Link][1];
float z = [Link][2];
float gX = x / SensorManager.GRAVITY_EARTH;
float gY = y / SensorManager.GRAVITY_EARTH;
float gZ = z / SensorManager.GRAVITY_EARTH;
[Link] 403
mShakeTimestamp = now;
mShakeCount++;
[Link](mShakeCount);
}
}
}
}
Seismic is an Android device shake detection library by Square. To use it just start listening to the
shake events emitted by it.
@Override
protected void onCreate(Bundle savedInstanceState) {
sm = (SensorManager) getSystemService(SENSOR_SERVICE);
sd = new ShakeDetector(() -> { /* react to detected shake */ });
}
@Override
protected void onResume() {
[Link](sm);
}
@Override
protected void onPause() {
[Link]();
}
Installation
compile '[Link]:seismic:1.0.2'
[Link] 404
Chapter 81: Device Display Metrics
Examples
Get the screens pixel dimensions
To retreive the screens width and height in pixels, we can make use of the WindowManagers
display metrics.
These DisplayMetrics hold a series of information about the devices screen, like its density or size:
To get the screens density, we also can make use of the Windowmanagers DisplayMetrics. This is
a quick example:
DP to Pixel:
Pixel to DP:
[Link] 405
Chapter 82: Dialog
Parameters
Line Description
Remarks
• The dialog in the first example(Dialog) does not need to call show() when it is created as it is
handled in the constructor
• Alert Dialogs must be constructed through a new instance of the [Link]() class.
Following the Builder Pattern, all members of the [Link] can be method chained
to 'build up' the dialog instance.
• The Alert Dialog builder can directly show() the dialog -- you do not need to call create() then
show() on the AlertDialog instance
Examples
Alert Dialog
[Link]("Title Dialog");
alertDialogBuilder
.setMessage("Message Dialog")
.setCancelable(true)
.setPositiveButton("Yes",
new [Link]() {
}
})
.setNegativeButton("No",
new [Link]() {
[Link] 406
// Handle Negative Button
[Link]();
}
});
[Link] 407
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<DatePicker
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/datePicker"
android:layout_gravity="center_horizontal"
android:calendarViewShown="false"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ACCEPT"
android:id="@+id/buttonAccept" />
</LinearLayout>
Dialog Class:
public ChooseDate(){}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = [Link]([Link].dialog_year_picker, container);
getDialog().setTitle(getResources().getString("TITLE"));
if (isDateSetted) {
[Link](year, month, day);
}
return rootView;
}
@Override
public void onClick(View v) {
switch([Link]()){
case [Link]:
[Link] 408
int year = [Link]();
int month = [Link]() + 1; // months start in 0
int day = [Link]();
@Override
public void onAttach(Context context) {
[Link](context);
listener = (DateListener) context;
}
[Link] = year;
[Link] = month;
[Link] = day;
[Link] = true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
@Override
onDateSelected(int year, int month, int day){
[Link] = day;
[Link] = month;
[Link] = year;
}
}
DatePickerDialog
[Link] 409
DatePickerDialogis the simplest way to use DatePicker, because you can show dialog anywhere in
your app. You don't have to implement your own layout with DatePicker widget.
You can get DataPicker widget from dialog above, to get access to more functions, and for
example set minimum date in milliseconds:
DatePicker
DatePicker allows user to pick date. When we create new instance of DatePicker, we can set initial
date. If we don't set initial date, current date will be set by default.
We can show DatePicker to user by using DatePickerDialog or by creating our own layout with
DatePicker widget.
//In this case user can pick date only from future
[Link]([Link]());
//In this case user can pick date only, before following week.
[Link]([Link]() + [Link](7));
To receive information, about which date was picked by user, we have to use Listener.
If we are using DatePickerDialog, we can set OnDateSetListener in constructor when we are creating
new instance of DatePickerDialog:
@Override
public void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
[Link] 410
...
}
@Override
public void onDateSet(DatePicker datePicker, int year, int month, int day) {
}
}
Otherwise, if we are creating our own layout with DatePicker widget, we also have to create our
own listener as it was shown in other example
AlertDialog is a subclass of Dialog that can display one, two or three buttons. If you only want to
display a String in this dialog box, use the setMessage() method.
The AlertDialog from [Link] package displays differently on different Android OS Versions.
The Android V7 Appcompat library provides an AlertDialog implementation which will display with
Material Design on all supported Android OS versions, as shown below:
First you need to add the V7 Appcompat library to your project. you can do this in the app level
[Link] file:
dependencies {
compile '[Link]:appcompat-v7:24.2.1'
//........
}
[Link] 411
import [Link];
ListView in AlertDialog
We can always use ListView or RecyclerView for selection from list of items, but if we have small
amount of choices and among those choices we want user to select one, we can use
[Link] setAdapter.
Perhaps, if we don't need any particular ListView, we can use a basic way:
[Link] 412
void alertDialogDemo() {
// get alert_dialog.xml view
LayoutInflater li = [Link](getApplicationContext());
View promptsView = [Link]([Link].alert_dialog, null);
// show it
[Link]();
}
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Type Your Message : "
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="@+id/etUserInput"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<requestFocus />
</EditText>
[Link] 413
Fullscreen Custom Dialog with no background and no title
<RelativeLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent" >
</RelativeLayout>
Then in java file you can use it for an Activity or Dialog etc:
import [Link];
import [Link];
import [Link];
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
//You can set no content for the activity.
Dialog mDialog = new Dialog(this, [Link]);
[Link]([Link]);
[Link]();
}
}
The setCustomTitle() method of [Link] lets you specify an arbitrary view to be used
for the dialog title. One common use for this method is to build an alert dialog that has a long title.
[Link] 414
[Link](inflate(context, [Link].my_dialog_title, null))
.setView(inflate(context, [Link].my_dialog, null))
.setPositiveButton("OK", null);
my_dialog_title.xml:
<TextView
style="@android:style/[Link]"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur
tincidunt condimentum tristique. Vestibulum ante ante, pretium porttitor
iaculis vitae, congue ut sem. Curabitur ac feugiat ligula. Nulla
tincidunt est eu sapien iaculis rhoncus. Mauris eu risus sed justo
pharetra semper faucibus vel velit."
android:textStyle="bold"/>
</LinearLayout>
my_dialog.xml:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:scrollbars="vertical">
<TextView
style="@android:style/[Link]"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:text="Hello world!"/>
<TextView
style="@android:style/[Link]"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:text="Hello world again!"/>
<TextView
style="@android:style/[Link]"
[Link] 415
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:text="Hello world again!"/>
<TextView
style="@android:style/[Link]"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:text="Hello world again!"/>
</LinearLayout>
</ScrollView>
[Link] 416
Chapter 83: Displaying Google Ads
Examples
Basic Ad Setup
compile '[Link]:firebase-ads:10.2.1'
<string name="banner_ad_unit_id">ca-app-pub-####/####</string>
Next place an adview wherever you want it and style it just like any other view.
<[Link]
android:id="@+id/adView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
ads:adSize="BANNER"
ads:adUnitId="@string/banner_ad_unit_id">
</[Link]>
[Link](getApplicationContext(), "ca-app-pub-YOUR_ID");
AdView mAdView = (AdView) findViewById([Link]);
AdRequest adRequest = new [Link]().build();
[Link](adRequest);
If you copy-pasted exactly you should now have a small banner ad. Simply place more AdViews
wherever you need them for more.
Adding Interstitial Ad
Interstitial ads are full-screen ads that cover the interface of their host app. They're typically
displayed at natural transition points in the flow of an app, such as between activities or during the
pause between levels in a game.
[Link] 417
1. Go to your AdMob account.
5. Once the ad unit is created, you can notice the Ad unit ID on the dashboard. For example:
ca-app-pub-00000000000/000000000
6. Add dependencies
compile '[Link]:firebase-ads:10.2.1'
<string name="interstitial_full_screen">ca-app-pub-00000000/00000000</string>
<activity
android:name="[Link]"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScree
android:theme="@android:style/[Link]" />
and
<meta-data
android:name="[Link]"
android:value="@integer/google_play_services_version" />
Activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_second);
[Link] 418
// set the ad unit ID
[Link](getString([Link].interstitial_full_screen));
[Link](new AdListener() {
public void onAdLoaded() {
showInterstitial();
}
});
}
[Link] 419
Chapter 84: Doze Mode
Remarks
Doze Mode is a set of changes and rules that put your phone to sleep when idle.
On Android 6.0 Marshmallow: Doze mode gets activated after a while the screen is off, the device
is stationary and it's running on battery.
As you can see in the diagram above, when Doze Mode gets activated, the device doesn't get any
wakelocks, network access, jobs/syncs, Alarms, GPS/Wi-fi scans.
On Android 7.0 Nougat: Imagine if your phone is on your pocket (the screen is off, it's running on
battery, but it's not stationary) you might want to get the Doze Mode features as well, right? So
that's why Google announced the Extended Doze Mode: It runs when the screen is off, but not
stationary.
[Link] 420
As you can see in this diagram, only Network Access and jobs/syncs are disabled. Note that the
Extended Doze doesn't replace the first Doze Mode. They work together, depending on the phone
state (stationary or not). Here are the distinctions:
[Link] 421
Developers should be aware that:
• Doze might keep temporary wakelock and network access for High-priority GCM (Google
Cloud Messaging) messages (for cases wwhere the user needs an immediate notification);
• Foreground services (such as a music playback) will continue to work.
Examples
Exclude app from using doze mode
[Link] 422
Now this app will show under not optimized apps.
Whitelisting won't disable the doze mode for your app, but you can do that by using network and
hold-wake locks.
The result of starting the activity above can be verfied by the following code:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_IGNORE_OPTIMIZATION_REQUEST) {
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
boolean isIgnoringBatteryOptimizations =
[Link](getPackageName());
if(isIgnoringBatteryOptimizations){
// Ignoring battery optimization
}else{
// Not ignoring battery optimization
}
}
}
[Link] 423
Chapter 85: Drawables
Examples
Tint a drawable
A drawable can be tinted a certain color. This is useful for supporting different themes within your
application, and reducing the number of drawable resource files.
Drawable d = [Link]([Link].ic_launcher);
[Link]([Link]);
//NOTE: If your original drawableRes was in use somewhere (i.e. it was the result of
//a call to a `getBackground()` method then at this point you still need to replace
//the background. setTint does *not* alter the instance that drawableRes points to,
//but instead creates a new drawable instance
Please not that int color is not referring to a color Resource, however you are not limited to those
colours defined in the 'Color' class. When you have a colour defined in your XML which you want
to use you must just first get it's value.
getResources().getColor([Link].your_color);
Or on newer targets:
[Link](context, [Link].your_color);
[Link] 424
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="[Link]
android:shape="rectangle" >
<stroke
android:width="1dp"
android:color="@android:color/white" />
</shape>
[Link]([Link].custom_rectangle);
Reference screenshot:
Circular View
For a circular View (in this case TextView) create a drawble round_view.xml in drawble folder:
<TextView
android:id="@+id/game_score"
android:layout_width="60dp"
android:layout_height="60dp"
[Link] 425
android:background="@drawable/round_score"
android:padding="6dp"
android:text="100"
android:textColor="#fff"
android:textSize="20sp"
android:textStyle="bold"
android:gravity="center" />
Custom Drawable
/**
* Public constructor for the Icon drawable
*
* @param icon pass the drawable of the icon to be drawn at the center
* @param backgroundColor background color of the shape
*/
public IconDrawable(Drawable icon, int backgroundColor) {
[Link] = icon;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
[Link](backgroundColor);
desiredIconWidth = 50;
desiredIconHeight = 50;
}
@Override
public void draw(Canvas canvas) {
//if we are setting this drawable to a 80dpX80dp imageview
[Link] 426
//getBounds will return that measurements,we can draw according to that width.
Rect bounds = getBounds();
//drawing the circle with center as origin and center distance as radius
[Link]([Link](), [Link](), [Link](), paint);
//set the icon drawable's bounds to the center of the shape
[Link]([Link]() - (desiredIconWidth / 2), [Link]() -
(desiredIconHeight / 2), ([Link]() - (desiredIconWidth / 2)) + desiredIconWidth,
([Link]() - (desiredIconHeight / 2)) + desiredIconHeight);
//draw the icon to the bounds
[Link](canvas);
@Override
public void setAlpha(int alpha) {
//sets alpha to your whole shape
[Link](alpha);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
//sets color filter to your whole shape
[Link](colorFilter);
}
@Override
public int getOpacity() {
//give the desired opacity of the shape
return [Link];
}
}
<ImageView
android:layout_width="80dp"
android:id="@+id/imageView"
android:layout_height="80dp" />
IconDrawable iconDrawable=new
IconDrawable([Link](this,[Link].ic_media_play),[Link](th
[Link](iconDrawable);
Screenshot
[Link] 427
Chapter 86: EditText
Examples
Working with EditTexts
The EditText is the standard text entry widget in Android apps. If the user needs to enter text into
an app, this is the primary way for them to do that.
EditText
There are many important properties that can be set to customize the behavior of an EditText.
Several of these are listed below. Check out the official text fields guide for even more input field
details.
Usage
An EditText is added to a layout with all default behaviors with the following XML:
<EditText
android:id="@+id/et_simple"
android:layout_height="wrap_content"
android:layout_width="match_parent">
</EditText>
Note that an EditText is simply a thin extension of the TextView and inherits all of the same
properties.
<EditText
android:singleLine="true"
android:lines="1"
/>
You can limit the characters that can be entered into a field using the digits attribute:
<EditText
android:inputType="number"
android:digits="01"
[Link] 428
/>
This would restrict the digits entered to just "0" and "1". We might want to limit the total
number of characters with:
<EditText
android:maxLength="5"
/>
Using these properties we can define the expected input behavior for text fields.
Adjusting Colors
You can adjust the highlight background color of selected text within an EditText with the
android:textColorHighlight property:
<EditText
android:textColorHighlight="#7cff88"
/>
You may want to set the hint for the EditText control to prompt a user for specific input
with:
<EditText
...
android:hint="@string/my_hint">
</EditText>
Hints
Assuming you are using the AppCompat library, you can override the styles colorControlNormal,
colorControlActivated, and colorControlHighlight:
If you do not see these styles applied within a DialogFragment, there is a known bug when using
the LayoutInflater passed into the onCreateView() method.
The issue has already been fixed in the AppCompat v23 library. See this guide about how to
upgrade. Another temporary workaround is to use the Activity's layout inflater instead of the one
passed into the onCreateView() method:
[Link] 429
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
View view = getActivity().getLayoutInflater().inflate([Link].dialog_fragment,
container);
}
Check out the basic event listeners cliffnotes for a look at how to listen for changes to an EditText
and perform an action when those changes occur.
Traditionally, the EditText hides the hint message (explained above) after the user starts typing. In
addition, any validation error messages had to be managed manually by the developer.
With the TextInputLayout you can setup a floating label to display hints and error messages. You
can find more details here.
Text fields can have different input types, such as number, date, password, or email address. The
type determines what kind of characters are allowed inside the field, and may prompt the virtual
keyboard to optimize its layout for frequently used characters.
By default, any text contents within an EditText control is displayed as plain text. By setting the
inputType attribute, we can facilitate input of different types of information, like phone numbers and
passwords:
<EditText
...
android:inputType="phone">
</EditText>
Type Description
[Link] 430
Type Description
The android:inputType also allows you to specify certain keyboard behaviors, such as whether to
capitalize all new words or use features like auto-complete and spelling suggestions.
Here are some of the common input type values that define keyboard behaviors:
Type Description
Normal text keyboard that capitalizes the first letter for each new
textCapSentences
sentence
Normal text keyboard that capitalizes every word. Good for titles or
textCapWords
person names
<EditText
android:id="@+id/postal_address"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/postal_address_hint"
android:inputType="textPostalAddress|
textCapWords|
textNoSuggestions" />
`inputype` attribute
textFilter= Keyboard: alphabet/default. Enter button: Send/Next. Emotion: yes. Case: lowercase.
Suggestion: no. Add. chars: , and . and everything
[Link] 431
Sentence case. Suggestion: yes. Add. chars: , and . and everything
time= Keyboard: numeric. Enter button: Send/Next. Emotion: no. Case: -. Suggestion: no. Add.
chars: :
number= Keyboard: numeric. Enter button: Send/Next. Emotion: no. Case: -. Suggestion: no.
Add. chars: nothing
(No type)= Keyboard: alphabet/default. Enter button: nextline. Emotion: yes. Case: lowercase.
Suggestion: yes. Add. chars: , and . and everything
text= Keyboard: Keyboard: alphabet/default. Enter button: Send/Next. Emotion: yes. Case:
lowercase. Suggestion: yes. Add. chars: , and . and everything
textUri= Keyboard: alphabet/default. Enter button: Send/Next. Emotion: no. Case: lowercase.
Suggestion: no. Add. chars: / and . and everything
phone= Keyboard: numeric. Enter button: Send/Next. Emotion: no. Case: -. Suggestion: no.
Add. chars: *** # . - / () W P N , +**
Hiding SoftKeyboard
Hiding Softkeyboard is a basic requirement usually when working with EditText. The
softkeyboard by default can only be closed by pressing back button and so most developers use
InputMethodManager to force Android to hide the virtual keyboard calling
[Link] 432
hideSoftInputFromWindow and passing in the token of the window containing your focused view.
The code to do the following:
The code is direct, but another major problems that arises is that the hide function needs to be
called when some event occurs. What to do when you need the Softkeyboard hidden upon
pressing anywhere other than your EditText? The following code gives a neat function that needs
to be called in your onCreate() method just once.
[Link](new [Link]() {
});
}
setupUI(innerView);
}
}
}
Icon or button inside Custom Edit Text and its action and click listeners.
This example will help to have the Edit text with the icon at the right side.
[Link] 433
}
setIcon();
}
setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
setSelection(getText().length());
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final int right = getRight();
final int drawableSize = getCompoundPaddingRight();
final int x = (int) [Link]();
switch ([Link]()) {
case MotionEvent.ACTION_DOWN:
if (x + EXTRA_TOUCH_AREA >= right - drawableSize && x <= right +
EXTRA_TOUCH_AREA) {
touchDown = true;
return true;
}
break;
case MotionEvent.ACTION_UP:
if (x + EXTRA_TOUCH_AREA >= right - drawableSize && x <= right +
EXTRA_TOUCH_AREA && touchDown) {
touchDown = false;
if (mIconClickListener != null) {
[Link]();
[Link] 434
}
return true;
}
touchDown = false;
break;
}
return [Link](event);
}
}
If you want to change the touch area you can change the EXTRA_TOUCH_AREA
values default I gave as 50.
And for Enable the button and click listener you can call from your Activity or Fragment like this,
}
});
[Link] 435
Chapter 87: Email Validation
Examples
Email address validation
Add the following method to check whether an email address is valid or not:
The above method can easily be verified by converting the text of an EditText widget into a String:
if(isValidEmailId([Link]().toString().trim())){
[Link](getApplicationContext(), "Valid Email Address.", Toast.LENGTH_SHORT).show();
}else{
[Link](getApplicationContext(), "InValid Email Address.",
Toast.LENGTH_SHORT).show();
}
if (Patterns.EMAIL_ADDRESS.matcher(email).matches()){
Log.i("EmailCheck","It is valid");
}
[Link] 436
Chapter 88: Emulator
Remarks
AVD stands for Android Virtual Device
Examples
Taking screenshots
If you want to take a screenshot from the Android Emulator (2.0), then you just need to press Ctrl
+ S or you click on the camera icon on the side bar:
[Link] 437
[Link] 438
2. A drop shadow below the device frame.
3. A screen glare across device frame and screenshot.
[Link] 439
[Link] 440
.
You can also access AVD Manager from Android studio using Tools > Android > AVD Manager or by
clicking on the AVD Manager icon in the toolbar which is the second in the screenshot below.
Simulate call
To simulate a phone call, press the 'Extended controls' button indicated by three dots, choose
'Phone' and select 'Call'. You can also optionally change the phone number.
[Link] 441
First of all, ensure that you've enabled the 'Virtualization' in your BIOS setup.
Start the Android SDK Manager, select Extras and then select Intel Hardware Accelerated
Execution Manager and wait until your download completes. If it still doesn't work, open your
SDK folder and run /extras/intel/Hardware_Accelerated_Execution_Manager/[Link].
If your CPU does not support VT-x or SVM, you can not use x86-based Android
images. Please use ARM-based images instead.
After installation completed, confirm that the virtualization driver is operating correctly by opening a
command prompt window and running the following command: sc query intelhaxm
To run an x86-based emulator with VM acceleration: If you are running the emulator from the
command line, just specify an x86-based AVD: emulator -avd <avd_name>
If you follow all the steps mentioned above correctly, then surely you should be able to see your
AVD with HAXM coming up normally.
[Link] 442
Chapter 89: Enhancing Alert Dialogs
Introduction
This topic is about enhancing an AlertDialog with additional features.
Examples
Alert dialog containing a clickable link
In order to show an alert dialog containing a link which can be opened by clicking it, you can use
the following code:
[Link](false);
[Link]("ok", new [Link]() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
[Link] 443
Chapter 90: Enhancing Android Performance
Using Icon Fonts
Remarks
Icon Fonts are like normal font types that have symbols instead of letters. It can be used in your
application with at-most ease.
They are:
• Flexible
• Scalable
• Vectors
• Fast Processable
• Light Weight
• Accessible
Effect on Size
Exporting an image in various sizes for android devices would cost your app, additional asset size
of around 30kB per image. While adding a font file(.ttf) with around 36 icons would cost just 9kB.
Just imagine the case if you are adding 36 individual files of various configurations it would be
around 1000kB. It’s a reasonable amount of space that you will save by using icon fonts.
• Icon fonts can be used in navigation drawer. Using them in navigation views as icon of menu
items is not possible as the menu file cannot be created without specifying the title. So it is
advisable to use svg files as resources for these icons.
• Icon fonts cannot be used in floating action button. as they does not have a setText()
attribute.
• External fonts cannot be applied from xml. They must be specified using the java file. Or else
you need to extend the basic view and create a view as specified in this post
Examples
How to integrate Icon fonts
You may create your font icon file from online websites such as icomoon, where you can
upload SVG files of the required icons and then download the created icon font. Then, place
[Link] 444
the .ttf font file into a folder named fonts (name it as you wish) in the assets folder:
Now, create the following helper class, so that you can avoid repeating the initialisation code
for the font:
You may use the Typeface class in order to pick the font from the assets. This way you can
set the typeface to various views, for example, to a button:
Now, the button typeface has been changed to the newly created icon font.
Open the [Link] file attached to the icon font. There you will find the styles with Unicode
characters of your icons:
.icon-arrow-circle-down:before {
content: “\e001”;
}
.icon-arrow-circle-left:before {
content: “\e002”;
}
[Link] 445
.icon-arrow-circle-o-down:before {
content: “\e003”;
}
.icon-arrow-circle-o-left:before {
content: “\e004”;
}
This resource file will serve as a dictionary, which maps the Unicode character associated
with a specific icon to a human-readable name. Now, create the string resources as follows:
<resources>
<! — Icon Fonts -->
<string name=”icon_arrow_circle_down”> </string>
<string name=”icon_arrow_circle_left”> </string>
<string name=”icon_arrow_circle-o_down”> </string>
<string name=”icon_arrow_circle_o_left”> </string>
</resources>
Now, you may use your font in various views, for example, as follows:
[Link](getString([Link].icon_arrow_circle_left))
You may also create button text views using icon fonts:
[Link] 446
TabLayout with icon fonts
CustomTypefaceSpan fonte;
List<Fragment> fragments = new ArrayList<>(4);
private String[] icons = {"\ue001","\uE002","\uE003","\uE004"};
@Override
public Fragment getItem(int position) {
return [Link](position);
}
[Link] 447
@Override
public CharSequence getPageTitle(int position) {
SpannableStringBuilder ss = new SpannableStringBuilder(icons[position]);
[Link](fonte,0,[Link](), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
[Link](new RelativeSizeSpan(1.5f),0,[Link](), Spanned.SPAN_INCLUSIVE_INCLUSIVE );
return ss;
}
@Override
public int getCount() {
return 4;
}
//..
TabLayout tabs;
ViewPager tabs_pager;
public CustomTypefaceSpan fonte;
//..
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
//...
fm = getSupportFragmentManager();
fonte = new
CustomTypefaceSpan("icomoon",[Link](getAssets(),"[Link]"));
[Link] = ((TabLayout) [Link]([Link]));
this.tabs_pager = ((ViewPager) [Link]([Link].tabs_pager));
//...
}
@Override
protected void onStart() {
[Link]();
//..
tabs_pager.setAdapter(new TabAdapter(fm,fonte));
[Link](tabs_pager);
//..
[Link] 448
Chapter 91: Exceptions
Examples
NetworkOnMainThreadException
This is only thrown for applications targeting the Honeycomb SDK or higher.
Applications targeting earlier SDK versions are allowed to do networking on their main
event loop threads, but it's heavily discouraged.
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
Above code will throw NetworkOnMainThreadException for applications targeting Honeycomb SDK
(Android v3.0) or higher as the application is trying to perform a network operation on the main
thread.
[Link] 449
To avoid this exception, your network operations must always run in a background task via an
AsyncTask, Thread, IntentService, etc.
@Override
protected Void doInBackground(String[] params) {
[Link] builder = new [Link]().scheme("http").authority("[Link]");
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
URL url;
try {
url = new URL([Link]().toString());
urlConnection = (HttpURLConnection) [Link]();
[Link]("GET");
[Link]();
} catch (IOException e) {
Log.e("TAG","Connection error", e);
} finally{
if (urlConnection != null) {
[Link]();
}
if (reader != null) {
try {
[Link]();
} catch (final IOException e) {
Log.e("TAG", "Error closing stream", e);
}
}
}
return null;
}
}
ActivityNotFoundException
This is a very common Exception. It causes your application to stop during the start or execution of
your app. In the LogCat you see the message:
In this case, check if you have declared your activity in the [Link] file.
OutOfMemoryError
This is a runtime error that happens when you request a large amount of memory on the heap.
This is common when loading a Bitmap into an ImageView.
[Link] 450
You have some options:
Add the "largeHeap" option to the application tag in your [Link]. This will make more
memory available to your app but will likely not fix the root issue.
Avoid loading the entire bitmap into memory at once by sampling a reduced size, using
BitmapOptions and inSampleSize.
DexException
This error occurs because the app, when packaging, finds two .dex files that define the same set
of methods.
Usually this happens because the app has accidentally acquired 2 separate dependencies on the
same library.
For instance, say you have a project, and you want to rely on two libraries: A and B, which each
have their own dependencies. If library B already has a dependency on library A, this error will be
thrown if library A is added to the project by itself. Compiling library B already gave the set of code
from A, so when the compiler goes to bundle library A, it finds library A's methods already
packaged.
To resolve, make sure that none of your dependencies could accidentally be added twice in such
a manner
UncaughtException
If you want to handle uncaught exceptions try to catch them all in onCreate method of you
Application class:
[Link] 451
public class MyApp extends Application {
@Override
public void onCreate() {
[Link]();
try {
Thread
.setDefaultUncaughtExceptionHandler(
new [Link]() {
@Override
public void uncaughtException(Thread thread, Throwable e) {
Log.e(TAG,
"Uncaught Exception thread: "+[Link]()+"
"+[Link]());
handleUncaughtException (thread, e);
}
});
} catch (SecurityException e) {
Log.e(TAG,
"Could not set the Default Uncaught Exception Handler:"
+[Link]());
}
}
This is how you can react to exceptions which have not been catched, similar to the system's
standard "Application XYZ has crashed"
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
/**
* Application class writing unexpected exceptions to a crash file before crashing.
*/
public class MyApplication extends Application {
private static final String TAG = "ExceptionHandler";
@Override
public void onCreate() {
[Link]();
[Link] 452
[Link](new [Link]() {
@Override
public void uncaughtException(Thread thread, Throwable e) {
try {
handleUncaughtException(e);
[Link](1);
} catch (Throwable e2) {
Log.e(TAG, "Exception in custom exception handler", e2);
[Link](thread, e);
}
}
});
}
// You can (and probably should) also display a dialog to notify the user
}
}
[Link] 453
Chapter 92: ExoPlayer
Examples
Add ExoPlayer to the project
Via jCenter
compile '[Link]:exoplayer:rX.X.X'
where rX.X.X is the your preferred version. For the latest version, see the project's Releases. For
more details, see the project on Bintray.
Using ExoPlayer
Now you have to create a DataSource. When you want to stream mp3 you can use the
DefaultUriDataSource. You have to pass the Context and a UserAgent. To keep it simple play a
local file and pass null as userAgent:
uri points to your file, as an Extractor you can use a simple default Mp3Extractor if you want to
play mp3. requestedBufferSize can be tweaked again according to your requirements. Use 5000
for example.
Now you can create your audio track renderer using the sample source as follows:
[Link] 454
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
[Link](audioRenderer);
[Link](true);
Main steps to play video & audio using the standard TrackRenderer
implementations
[Link] 455
Chapter 93: Facebook SDK for Android
Syntax
• newInstance : To create single instance of Facebook helper class.
• loginUser : To login user.
• signOut : To log out user.
• getCallbackManager : To get callback for Facebook.
• getLoginCallback : To get callback for Login.
• getKeyHash : To generate Facebook Key Hash.
Parameters
Parameter Details
Activity A context
Examples
How to add Facebook Login in Android
// Facebook login
compile '[Link]:facebook-android-sdk:4.21.1'
/**
* Created by Andy
* An utility for Facebook
*/
public class FacebookSignInHelper {
private static final String TAG = [Link]();
private static FacebookSignInHelper facebookSignInHelper = null;
[Link] 456
private CallbackManager callbackManager;
private Activity mActivity;
private static final Collection<String> PERMISSION_LOGIN = (Collection<String>)
[Link]("public_profile", "user_friends","email");
private FacebookCallback<LoginResult> loginCallback;
@Override
public void onCancel() {
Log.d(TAG, "Facebook: Cancelled by user");
}
@Override
public void onError(FacebookException error) {
Log.d(TAG, "FacebookException: " + [Link]());
}
};
} catch (Exception e) {
[Link]();
}
}
/**
* To login user on facebook without default Facebook button
*/
public void loginUser() {
try {
[Link]().registerCallback(callbackManager, loginCallback);
[Link]().logInWithReadPermissions([Link],
PERMISSION_LOGIN);
} catch (Exception e) {
[Link]();
}
}
/**
* To log out user from facebook
*/
public void signOut() {
[Link] 457
// Facebook sign out
[Link]().logOut();
}
/**
* Attempts to log debug key hash for facebook
*
* @param context : A reference to context
* @return : A facebook debug key hash
*/
public static String getKeyHash(Context context) {
String keyHash = null;
try {
PackageInfo info = [Link]().getPackageInfo(
[Link](),
PackageManager.GET_SIGNATURES);
for (Signature signature : [Link]) {
MessageDigest md = [Link]("SHA");
[Link]([Link]());
keyHash = [Link]([Link](), [Link]);
Log.d(TAG, "KeyHash:" + keyHash);
}
} catch ([Link] e) {
[Link]();
} catch (NoSuchAlgorithmException e) {
[Link]();
} catch (Exception e) {
[Link]();
}
return keyHash;
}
}
FacebookSignInHelper facebookSignInHelper =
[Link]([Link], fireBaseAuthHelper);
[Link]();
If you want to retrieve the details of a user's Facebook profile, you need to set permissions for the
same:
[Link] 458
loginButton = (LoginButton)findViewById([Link].login_button);
[Link]([Link]("email", "user_about_me"));
You can keep adding more permissions like friends-list, posts, photos etc. Just pick the right
permission and add it the above list.
Note: You don't need to set any explicit permissions for accessing the public profile (first name,
last name, id, gender etc).
Once you first add the Facebook login/signup, the button looks something like:
Most of the times, it doesn't match with the design-specs of your app. And here's how you can
customize it:
<FrameLayout
android:layout_below="@+id/no_network_bar"
android:id="@+id/FrameLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<[Link]
android:id="@+id/login_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<Button
android:background="#3B5998"
android:layout_width="match_parent"
android:layout_height="60dp"
android:id="@+id/fb"
android:onClick="onClickFacebookButton"
android:textAllCaps="false"
android:text="Sign up with Facebook"
android:textSize="22sp"
android:textColor="#ffffff" />
</FrameLayout>
Just wrap the original [Link] into a FrameLayout and make its
visibility gone.
Next, add your custom button in the same FrameLayout. I've added some sample specs. You can
always make your own drawable background for the facebook button and set it as the background
of the button.
The final thing we do is simply convert the click on my custom button to a click on the facecbook
[Link] 459
button:
<activity
android:name="[Link]"
android:configChanges= "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:theme="@android:style/[Link]"
android:label="@string/app_name" />
<[Link]
android:id="@+id/login_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
4. Now you have the Facebook button. If the user clicks on it, the Facebook login dialog will
come up on top of the app's screen. Here the user can fill in their credentials and press the
Log In button. If the credentials are correct, the dialog grants the corresponding permissions
and a callback is sent to your original activity containing the button. The following code
shows how you can receive that callback:
@Override
public void onCancel() {
[Link] 460
// The user either cancelled the Facebook login process or didn't authorize the
app.
}
@Override
public void onError(FacebookException exception) {
// The dialog was closed with an error. The exception will help you recognize
what exactly went wrong.
}
});
[Link]().logOut();
For versions before 4.0, the logging out is gone by explicitly clearing the access token:
[Link] 461
Chapter 94: Fast way to setup Retrolambda
on an android project.
Introduction
Retrolambda is a library which allows to use Java 8 lambda expressions, method references and
try-with-resources statements on Java 7, 6 or 5.
The Gradle Retrolambda Plug-in allows to integrate Retrolambda into a Gradle based build. This
allows for example to use these constructs in an Android application, as standard Android
development currently does not yet support Java 8.
Examples
Setup and example how to use:
Setup Steps:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath '[Link]:gradle-retrolambda:3.2.3'
}
}
4. Add these lines to your application module’s [Link] to inform the IDE of the language
level:
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
[Link] 462
Example:
[Link](new [Link]() {
@Override
public void onClick(View v) {
log("Clicked");
}
});
Become this:
[Link] 463
Chapter 95: Fastjson
Introduction
Fastjson is a Java library that can be used to convert Java Objects into their JSON
representation. It can also be used to convert a JSON string to an equivalent Java object.
Fastjson Features:
Provide simple toJSONString() and parseObject() methods to convert Java objects to JSON and
vice-versa
Syntax
• Object parse(String text)
• JSONObject parseObject(String text)
• T parseObject(String text, Class<T> clazz)
• JSONArray parseArray(String text)
• <T> List<T> parseArray(String text, Class<T> clazz)
• String toJSONString(Object object)
• String toJSONString(Object object, boolean prettyFormat)
• Object toJSON(Object javaObject)
Examples
Parsing JSON with Fastjson
Encode
import [Link];
[Link] 464
[Link](3L);
[Link]("root");
[Link](guestUser);
[Link](rootUser);
[Link](jsonString);
Output
{"id":0,"name":"admin","users":[{"id":2,"name":"guest"},{"id":3,"name":"root"}]}
Decode
[Link]
[Link]
[Link] 465
public class User {
Code
Output
{1:"No.1",2:"No.2",3:[{"id":2,"name":"Liu"},{"id":3,"name":"Yue"}]}
[Link] 466
Chapter 96: fastlane
Remarks
fastlane is a tool for iOS, Mac, and Android developers to automate tedious tasks like generating
screenshots, dealing with provisioning profiles, and releasing your application.
Docs: [Link]
Examples
Fastfile to build and upload multiple flavors to Beta by Crashlytics
This is a sample Fastfile setup for a multi-flavor app. It gives you an option to build and deploy all
flavors or a single flavor. After the deployment, it reports to Slack the status of the deployment,
and sends a notification to testers in Beta by Crashlytics testers group.
Using a single Fastlane file, you can manage iOS, Android, and Mac apps. If you are using this file
just for one app platform is not required.
How It Works
[Link] 467
and throw an error. In this scenario, I capture it and report to Slack as a failure, so you will
know which app is inactive.
7. If deployment is successful, fastlane will send a success message to Slack.
8. #{/([^\/]*)$/.match(apk)} this regex is used to get flavor name from APK path. You can
remove it if it does not work for you.
9. get_version_name and get_version_code are two Fastlane plugins to retrieve app version name
and code. You have to install these gems if you want to use, or you can remove them. Read
more about Plugins here.
10. The else statement will be executed if you are building and deploying a single APK. We don't
have to provide apk_path to Crashlytics since we have only one app.
11. error do block at the end is used to get notified if anything else goes wrong during execution.
Note
Don't forget to replace SLACK_URL, API_TOKEN, GROUP_NAME and BUILD_SECRET with your own credentials.
fastlane_version "1.46.1"
default_platform :android
platform :android do
before_all do
ENV["SLACK_URL"] = "[Link]
end
gradle(task: "clean")
gradle(task: "assemble",
build_type: "Release",
flavor: options[:app])
# If user calls `fastlane android beta` command, it will build all projects and push
them to Crashlytics
if options[:app].nil?
lane_context[SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS].each do | apk |
begin
crashlytics(
api_token: "[API_TOKEN]",
build_secret: "[BUILD_SECRET]",
groups: "[GROUP_NAME]",
apk_path: apk,
notifications: "true"
)
slack(
message: "Successfully deployed new build for #{/([^\/]*)$/.match(apk)}
#{get_version_name} - #{get_version_code}",
success: true,
default_payloads: [:git_branch, :lane, :test_result]
[Link] 468
)
rescue => ex
# If the app is inactive in Crashlytics, deployment will fail. Handle it
here and report to slack
slack(
message: "Error uploading => #{/([^\/]*)$/.match(apk)}
#{get_version_name} - #{get_version_code}: #{ex}",
success: false,
default_payloads: [:git_branch, :lane, :test_result]
)
end
end
after_all do |lane|
# This block is called, only if the executed lane was successful
slack(
message: "Operation completed for
#{lane_context[SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS].size} app(s) for #{get_version_name}
- #{get_version_code}",
default_payloads: [:git_branch, :lane, :test_result],
success: true
)
end
else
# Single APK upload to Beta by Crashlytics
crashlytics(
api_token: "[API_TOKEN]",
build_secret: "[BUILD_SECRET]",
groups: "[GROUP_NAME]",
notifications: "true"
)
after_all do |lane|
# This block is called, only if the executed lane was successful
slack(
message: "Successfully deployed new build for #{options[:app]}
#{get_version_name} - #{get_version_code}",
default_payloads: [:git_branch, :lane, :test_result],
success: true
)
end
end
Fastfile lane to build and install all flavors for given build type to a device
Add this lane to your Fastfile and run fastlane installAll type:{BUILD_TYPE} in command line.
Replace BUILD_TYPE with the build type you want to build.
[Link] 469
This command will build all flavors of given type and install it to your device. Currently, it doesn't
work if you have more than one device attached. Make sure you have only one. In the future I'm
planning to add option to select target device.
gradle(task: "clean")
gradle(task: "assemble",
build_type: options[:type])
lane_context[SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS].each do | apk |
begin
adb(
command: "install -r #{apk}"
)
rescue => ex
puts ex
end
end
end
[Link] 470
Chapter 97: FileIO with Android
Introduction
Reading and writing files in Android are not different from reading and writing files in standard
Java. Same [Link] package can be used. However, there is some specific related to the folders
where you are allowed to write, permissions in general and MTP work arounds.
Remarks
Android provides means for sharing the file between multiple applications as documented here.
This is not required if there is only one app that creates and uses the file.
Android provides alternative storage options like shared and private preferences, saved bundles
and built-in database. In some cases, they are better choice than just using plain files.
Android activity does have few specific methods that look like replacements of the Java standard
File IO methods. For instance, instead for [Link]() you can call [Link](), and
instead of applying [Link]() recursively you can call [Link]() to get the list of all
your app specific files with somewhat less code. However, they do not provide extra functionality
beyond standard [Link] package.
Examples
Obtaining the working folder
You can get your working folder by calling the method getFilesDir() on your Activity (Activity is the
central class in your application that inherits from Context. See here). Reading is not different.
Only your application will have access to this folder.
There is nothing Android specific with this code. If you write lots of small values often, use
BufferedOutputStream to reduce the wear of the device internal SSD.
[Link] 471
Serializing the object
The old good Java object serialization is available for you in Android. you can define Serializable
classes like:
[Link]()
Java object serialization may be either perfect or really bad choice, depending on what do you
want to do with it - outside the scope of this tutorial and sometimes opinion based. Read about the
versioning first if you decide to use it.
You can also read and write from/to memory card (SD card) that is present in many Android
devices. Files in this location can be accessed by other programs, also directly by the user after
connecting device to PC via USB cable and enabling MTP protocol.
Finding the SD card location is somewhat more problematic. The Environment class contains
static methods to get "external directories" that should normally be inside the SD card, also
information if the SD card exists at all and is writable. This question contains valuable answers
how to make sure the right location will be found.
For older versions of Android putting permissions it is enough to put these permissions into
manifest (the user must approve during installation). However starting from Android 6.0 Android
asks the user for approval at the time of the first access, and you must support this new approach.
Otherwise access is denied regardless of your manifest.
[Link] 472
In Android 6.0, first you need to check for permission, then, if not granted, request it. The code
examples can be found inside this SO question.
If you create files for exporting via USB cable to desktop using MTP protocol, may be a problem
that newly created files are not immediately visible in the file explorer running on the connected
desktop PC. To to make new files visible, you need to call MediaScannerConnection:
[Link]()
[Link](this, new String[] {[Link]()}, null, null);
[Link](new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
[Link](file)));
This MediaScannerConnection call code works for files only, not for directories. The problem is
described in this Android bug report. This may be fixed for some version in the future, or on some
devices.
Small files are processed in a fraction of second and you can read / write them in place of the
code where you need this. However if the file is bigger or otherwise slower to process, you may
need to use AsyncTask in Android to work with the file in the background:
@Override
protected File doInBackground(String... params) {
try {
File file = new File([Link](
Environment.DIRECTORY_DOCUMENTS), "[Link]");
FileOutputStream out = new FileOutputStream(file)
[Link]()
return file;
} catch (IOException ex) {
Log.e("Unable to write", ex);
return null;
}
}
@Override
protected void onPostExecute(File result) {
// This is called when we finish
}
@Override
[Link] 473
protected void onPreExecute() {
// This is called before we begin
}
@Override
protected void onProgressUpdate(Void... values) {
// Unlikely required for this example
}
}
}
and then
This SO question contains the complete example on how to create and call the AsyncTask. Also
see the question on error handling on how to handle IOExceptions and other errors.
[Link] 474
Chapter 98: FileProvider
Examples
Sharing a file
In this example you'll learn how to share a file with other apps. We'll use a pdf file in this example
although the code works with every other format as well.
The roadmap:
1. Create a new XML file that will contain the paths, e.g. res/xml/[Link]
<paths xmlns:android="[Link]
<files-path name="pdf_folder" path="documents/"/>
</paths>
<manifest>
...
<application>
...
<provider
android:name="[Link]"
android:authorities="[Link]"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="[Link].FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
...
</application>
[Link] 475
...
</manifest>
As you can see in the code we first make a new File class representing the file. To get a URI we
ask FileProvider to get us one. The second argument is important: it passes the authority of a
FileProvider. It must be equal to the authority of the FileProvider defined in the manifest.
[Link](intent);
A chooser is a menu from which the user can choose with which app he/she wants to share the
file. The flag Intent.FLAG_GRANT_READ_URI_PERMISSION is needed to grant temporary read
access permission to the URI.
[Link] 476
Chapter 99: Fingerprint API in android
Remarks
see also
Examples
Adding the Fingerprint Scanner in Android application
To use this feature in your app, first add the USE_FINGERPRINT permission in your
manifest.
<uses-permission
android:name="[Link].USE_FINGERPRINT" />
First you need to create a symmetric key in the Android Key Store using KeyGenerator
which can be only be used after the user has authenticated with fingerprint and pass a
KeyGenParameterSpec.
[Link](KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
[Link](
new [Link](KEY_NAME,
KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.setUserAuthenticationRequired(true)
.build());
[Link]();
[Link] 477
KeyStore keyStore = [Link]("AndroidKeyStore");
[Link](null);
PrivateKey key = (PrivateKey) [Link](KEY_NAME, null);
getContext().getSystemService([Link])
onAuthenticationError
onAuthenticationHelp
onAuthenticationSucceeded
onAuthenticationFailed
To Start
fingerprintManager
.authenticate(cryptoObject, mCancellationSignal, 0 , this, null);
Cancel
[Link];
@Override
This example helper class interacts with the finger print manager and performs encryption and
decryption of password. Please note that the method used for encryption in this example is AES.
This is not the only way to encrypt and other examples exist. In this example the data is encrypted
[Link] 478
and decrypted in the following manner:
Encryption:
Decryption:
@TargetApi(Build.VERSION_CODES.M)
public boolean init() {
if ([Link].SDK_INT < Build.VERSION_CODES.M) {
setError("This Android version does not support fingerprint authentication");
return false;
[Link] 479
}
if (![Link]()) {
setError("User hasn't enabled Lock Screen");
return false;
}
if (!hasPermission()) {
setError("User hasn't granted permission to use Fingerprint");
return false;
}
if (![Link]()) {
setError("User hasn't registered any fingerprints");
return false;
}
if (!initKeyStore()) {
return false;
}
return false;
}
@Nullable
@RequiresApi(api = Build.VERSION_CODES.M)
private Cipher createCipher(int mode) throws NoSuchPaddingException,
NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, InvalidKeyException,
InvalidAlgorithmParameterException {
Cipher cipher = [Link](KeyProperties.KEY_ALGORITHM_AES + "/" +
KeyProperties.BLOCK_MODE_CBC + "/" +
KeyProperties.ENCRYPTION_PADDING_PKCS7);
@NonNull
@RequiresApi(api = Build.VERSION_CODES.M)
private KeyGenParameterSpec createKeyGenParameterSpec() {
return new [Link](MY_APP_ALIAS, KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build();
}
[Link] 480
@RequiresApi(api = Build.VERSION_CODES.M)
private boolean initKeyStore() {
try {
keyStore = [Link]("AndroidKeyStore");
keyGenerator = [Link](KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore");
[Link](null);
if (getLastIv() == null) {
KeyGenParameterSpec keyGeneratorSpec = createKeyGenParameterSpec();
[Link](keyGeneratorSpec);
[Link]();
}
} catch (Throwable t) {
setError("Failed init of keyStore & keyGenerator: " + [Link]());
return false;
}
return true;
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void authenticate(CancellationSignal cancellationSignal,
FingerPrintAuthenticationListener authListener, int mode) {
try {
if (hasPermission()) {
Cipher cipher = createCipher(mode);
[Link] crypto = new
[Link](cipher);
[Link](crypto, cancellationSignal, 0, authListener,
null);
} else {
[Link]().onFailure("User hasn't granted permission to use
Fingerprint");
}
} catch (Throwable t) {
[Link]().onFailure("An error occurred: " + [Link]());
}
}
if (ivString != null) {
return decodeBytes(ivString);
}
[Link] 481
}
return null;
}
@RequiresApi(api = Build.VERSION_CODES.M)
private boolean hasPermission() {
return [Link](context,
[Link].USE_FINGERPRINT) == PackageManager.PERMISSION_GRANTED;
}
@RequiresApi(api = Build.VERSION_CODES.M)
public void savePassword(@NonNull String password, CancellationSignal cancellationSignal,
Callback callback) {
authenticate(cancellationSignal, new FingerPrintEncryptPasswordListener(callback,
password), Cipher.ENCRYPT_MODE);
}
@RequiresApi(api = Build.VERSION_CODES.M)
public void getPassword(CancellationSignal cancellationSignal, Callback callback) {
authenticate(cancellationSignal, new FingerPrintDecryptPasswordListener(callback),
Cipher.DECRYPT_MODE);
}
@RequiresApi(api = Build.VERSION_CODES.M)
public boolean encryptPassword(Cipher cipher, String password) {
try {
// Encrypt the text
if([Link]()) {
setError("Password is empty");
return false;
}
if (cipher == null) {
setError("Could not create cipher");
return false;
}
[Link] 482
return true;
}
out[i/2] = (byte)(h*16+l);
}
return out;
}
@NonNull
private String decipher(Cipher cipher) throws IOException, IllegalBlockSizeException,
BadPaddingException {
String retVal = null;
String savedEncryptedPassword = getSavedEncryptedPassword();
if (savedEncryptedPassword != null) {
byte[] decodedPassword = decodeBytes(savedEncryptedPassword);
CipherInputStream cipherInputStream = new CipherInputStream(new
ByteArrayInputStream(decodedPassword), cipher);
[Link] 483
for (int i = 0; i < [Link](); i++) {
bytes[i] = [Link](i).byteValue();
}
@RequiresApi(Build.VERSION_CODES.M)
protected class FingerPrintAuthenticationListener extends
[Link] {
/**
* Called when a recoverable error has been encountered during authentication. The
help
* string is provided to give the user guidance for what went wrong, such as
* "Sensor dirty, please clean it."
* @param helpCode An integer identifying the error message
* @param helpString A human-readable string that can be shown in UI
*/
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
[Link](helpCode, [Link]());
}
/**
* Called when a fingerprint is recognized.
* @param result An object containing authentication-related data
*/
public void onAuthenticationSucceeded([Link] result)
{
}
/**
* Called when a fingerprint is valid but not recognized.
*/
public void onAuthenticationFailed() {
[Link]("Authentication failed");
}
public @NonNull
Callback getCallback() {
return callback;
}
[Link] 484
@RequiresApi(api = Build.VERSION_CODES.M)
private class FingerPrintEncryptPasswordListener extends FingerPrintAuthenticationListener
{
} catch (Exception e) {
[Link]("Encryption failed " + [Link]());
}
}
}
@RequiresApi(Build.VERSION_CODES.M)
protected class FingerPrintDecryptPasswordListener extends
FingerPrintAuthenticationListener {
} catch (Exception e) {
[Link]("Deciphering failed " + [Link]());
}
}
}
}
This activity below is a very basic example of how to get a user saved password and interact with
the helper.
[Link] 485
private FingerPrintAuthHelper fingerPrintAuthHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
passwordTextView = (TextView) findViewById([Link]);
errorTextView = (TextView) findViewById([Link]);
// Start the finger print helper. In case this fails show error to user
private void startFingerPrintAuthHelper() {
fingerPrintAuthHelper = new FingerPrintAuthHelper(this);
if (![Link]()) {
[Link]([Link]());
}
}
@NonNull
private [Link] getAuthListener(final boolean isGetPass) {
return new [Link]() {
@Override
public void onSuccess(String result) {
if (isGetPass) {
[Link]("Success!!! Pass = " + result);
} else {
[Link]("Encrypted pass = " + result);
}
}
@Override
public void onFailure(String message) {
[Link]("Failed - " + message);
}
@Override
public void onHelp(int helpCode, String helpString) {
[Link]("Help needed - " + helpString);
}
};
[Link] 486
}
}
[Link] 487
Chapter 100: Firebase
Introduction
Firebase is a mobile and web application platform with tools and infrastructure designed to help
developers build high-quality apps.
Features
Firebase Cloud Messaging, Firebase Auth, Realtime Database, Firebase Storage, Firebase
Hosting, Firebase Test Lab for Android, Firebase Crash Reporting.
Remarks
Examples
Create a Firebase user
@BindView([Link])
EditText mEditEmail;
@BindView([Link])
EditText mEditPassword;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
[Link](savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@OnClick([Link])
void signUp() {
[Link](mEditEmail, mEditPassword);
if ([Link](mEditEmail)) {
[Link] 488
[Link]("Please enter email");
return;
}
if () {
[Link]("Please enter valid email");
return;
}
if ([Link]([Link]())) {
[Link]("Please enter password");
return;
}
createUserWithEmailAndPassword([Link]().toString(),
[Link]().toString());
}
@Override
protected int getLayoutResourceId() {
return [Link].activity_sign_up;
}
}
@BindView([Link])
EditText mEditEmail;
@BindView([Link])
EditText mEditPassword;
@Override
protected void onResume() {
[Link] 489
[Link]();
FirebaseUser firebaseUser = [Link]();
if (firebaseUser != null)
startActivity(new Intent(this, [Link]));
}
@Override
protected int getLayoutResourceId() {
return [Link].activity_login;
}
@OnClick([Link])
void onSignInClick() {
[Link](mEditEmail, mEditPassword);
if ([Link](mEditEmail)) {
[Link](null, mEditEmail, "Please enter email");
return;
}
if () {
[Link](null, mEditEmail, "Please enter valid email");
return;
}
if ([Link]([Link]())) {
[Link](null, mEditPassword, "Please enter password");
return;
}
signInWithEmailAndPassword([Link]().toString(),
[Link]().toString());
}
[Link]();
if ([Link]()) {
[Link]([Link], "Login Successful",
Toast.LENGTH_SHORT).show();
startActivity(new Intent([Link], [Link]));
finish();
} else {
[Link]([Link],
[Link]().getMessage(),
Toast.LENGTH_SHORT).show();
}
}
});
}
@OnClick([Link])
void onSignUpClick() {
[Link] 490
startActivity(new Intent(this, [Link]));
}
@OnClick([Link])
void forgotPassword() {
startActivity(new Intent(this, [Link]));
}
}
@BindView([Link])
EditText mEditEmail;
private FirebaseAuth mFirebaseAuth;
private [Link] mAuthStateListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_forgot_password);
[Link](this);
mFirebaseAuth = [Link]();
}
}
};
}
@Override
protected void onStart() {
[Link]();
[Link](mAuthStateListener);
}
@Override
protected void onStop() {
[Link]();
if (mAuthStateListener != null) {
[Link](mAuthStateListener);
}
}
@OnClick([Link])
void onSubmitClick() {
if ([Link](mEditEmail)) {
[Link](null, mEditEmail, "Please enter email");
[Link] 491
return;
}
if () {
[Link](null, mEditEmail, "Please enter valid email");
return;
}
@BindView([Link].et_change_email)
EditText mEditText;
private FirebaseUser mFirebaseUser;
@OnClick([Link].btn_change_email)
void onChangeEmailClick() {
[Link](mEditText);
if ([Link](mEditText)) {
[Link](null, mEditText, "Please enter email");
return;
}
if () {
[Link](null, mEditText, "Please enter valid email");
return;
}
changeEmail([Link]().toString());
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
[Link](savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mFirebaseUser = [Link]();
[Link] 492
}
if ([Link]() instanceof
FirebaseAuthRecentLoginRequiredException) {
FragmentManager fm = getSupportFragmentManager();
ReAuthenticateDialogFragment reAuthenticateDialogFragment = new
ReAuthenticateDialogFragment();
[Link](fm,
[Link]().getSimpleName());
}
}
});
}
@Override
protected int getLayoutResourceId() {
return [Link].activity_change_email;
}
@Override
public void onReauthenticateSuccess() {
changeEmail([Link]().toString());
}
}
Change Password
@OnClick([Link].btn_change_password)
void onChangePasswordClick() {
[Link](mEditText);
if ([Link](mEditText)) {
[Link](null, mEditText, "Please enter password");
return;
}
changePassword([Link]().toString());
}
[Link] 493
[Link](this, "Changing Password", "Please wait...", false);
[Link](password)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
[Link]();
if ([Link]()) {
showToast("Password updated successfully.");
return;
}
if ([Link]() instanceof
FirebaseAuthRecentLoginRequiredException) {
FragmentManager fm = getSupportFragmentManager();
ReAuthenticateDialogFragment reAuthenticateDialogFragment = new
ReAuthenticateDialogFragment();
[Link](fm,
[Link]().getSimpleName());
}
}
});
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
[Link](savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mFirebaseUser = [Link]();
}
@Override
protected int getLayoutResourceId() {
return [Link].activity_change_password;
}
@Override
public void onReauthenticateSuccess() {
changePassword([Link]().toString());
}
}
@BindView([Link].et_dialog_reauthenticate_email)
EditText mEditTextEmail;
@BindView([Link].et_dialog_reauthenticate_password)
EditText mEditTextPassword;
private OnReauthenticateSuccessListener mOnReauthenticateSuccessListener;
@OnClick([Link].btn_dialog_reauthenticate)
void onReauthenticateClick() {
[Link](mEditTextEmail, mEditTextPassword);
if ([Link](mEditTextEmail)) {
[Link](null, mEditTextEmail, "Please enter email");
return;
[Link] 494
}
if () {
[Link](null, mEditTextEmail, "Please enter valid email");
return;
}
if ([Link]([Link]())) {
[Link](null, mEditTextPassword, "Please enter password");
return;
}
reauthenticateUser([Link]().toString(),
[Link]().toString());
}
@Override
public void onAttach(Context context) {
[Link](context);
mOnReauthenticateSuccessListener = (OnReauthenticateSuccessListener) context;
}
@OnClick([Link].btn_dialog_reauthenticate_cancel)
void onCancelClick() {
dismiss();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = [Link]([Link].dialog_reauthenticate, container);
[Link](this, view);
return view;
}
@Override
public void onResume() {
[Link]();
Window window = getDialog().getWindow();
[Link]([Link].MATCH_PARENT,
[Link] 495
[Link].WRAP_CONTENT);
}
interface OnReauthenticateSuccessListener {
void onReauthenticateSuccess();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_CODE_PICK_IMAGE) {
String filePath = [Link](this, [Link]());
mUri = [Link](new File(filePath));
[Link] 496
uploadFile(mUri);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
[Link](requestCode, permissions, grantResults);
if (requestCode == PERMISSION_READ_WRITE_EXTERNAL_STORAGE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
pickImage();
}
}
}
/**
* Step 1: Create a Storage
*
* @param view
[Link] 497
*/
public void onCreateReferenceClick(View view) {
mStorageReference =
[Link]("gs://**something**.[Link]");
showToast("Reference Created Successfully.");
findViewById([Link].button_step_2).setEnabled(true);
}
/**
* Step 2: Create a directory named "Images"
*
* @param view
*/
public void onCreateDirectoryClick(View view) {
mStorageReferenceImages = [Link]("images");
showToast("Directory 'images' created Successfully.");
findViewById([Link].button_step_3).setEnabled(true);
}
/**
* Step 3: Upload an Image File and display it on ImageView
*
* @param view
*/
public void onUploadFileClick(View view) {
if ([Link]([Link],
[Link].READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
[Link]([Link],
[Link].WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
[Link]([Link], new
String[]{[Link].READ_EXTERNAL_STORAGE,
[Link].WRITE_EXTERNAL_STORAGE}, PERMISSION_READ_WRITE_EXTERNAL_STORAGE);
else {
pickImage();
}
}
/**
* Step 4: Download an Image File and display it on ImageView
*
* @param view
*/
public void onDownloadFileClick(View view) {
downloadFile(mUri);
}
/**
* Step 5: Delete am Image File and remove Image from ImageView
*
* @param view
*/
public void onDeleteFileClick(View view) {
deleteFile(mUri);
}
if (okListener == null) {
okListener = new [Link]() {
[Link] 498
public void onClick(DialogInterface dialog, int which) {
[Link]();
}
};
}
if () {
[Link](title);
}
[Link]();
}
StorageReference uploadStorageReference =
[Link]([Link]());
final UploadTask uploadTask = [Link](uri);
showHorizontalProgressDialog("Uploading", "Please wait...");
uploadTask
.addOnSuccessListener(new OnSuccessListener<[Link]>() {
@Override
public void onSuccess([Link] taskSnapshot) {
hideProgressDialog();
Uri downloadUrl = [Link]();
Log.d("MainActivity", [Link]());
showAlertDialog([Link], "Upload Complete",
[Link](), new [Link]() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
findViewById([Link].button_step_3).setEnabled(false);
findViewById([Link].button_step_4).setEnabled(true);
}
});
[Link]([Link])
.load(downloadUrl)
.into(mImageView);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
[Link]();
// Handle unsuccessful uploads
hideProgressDialog();
}
})
.addOnProgressListener([Link], new
OnProgressListener<[Link]>() {
@Override
public void onProgress([Link] taskSnapshot) {
int progress = (int) (100 * (float) [Link]()
/ [Link]());
Log.i("Progress", progress + "");
updateProgress(progress);
[Link] 499
}
});
}
[Link]([Link])
.load(localFile)
.into(mImageView);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
// Handle any errors
hideProgressDialog();
[Link]();
}
}).addOnProgressListener(new OnProgressListener<[Link]>() {
@Override
public void onProgress([Link] taskSnapshot) {
int progress = (int) (100 * (float) [Link]() /
[Link]());
Log.i("Progress", progress + "");
updateProgress(progress);
}
});
}
[Link] 500
showProgressDialog("Deleting", "Please wait...");
StorageReference storageReferenceImage =
[Link]([Link]());
[Link]().addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
hideProgressDialog();
showAlertDialog([Link], "Success", "File deleted successfully.",
new [Link]() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
[Link]([Link].placeholder_image);
findViewById([Link].button_step_3).setEnabled(true);
findViewById([Link].button_step_4).setEnabled(false);
findViewById([Link].button_step_5).setEnabled(false);
}
});
File mediaStorageDir = new File([Link](
Environment.DIRECTORY_PICTURES), "Firebase Storage");
if (![Link]()) {
if (![Link]()) {
Log.d("MainActivity", "failed to create Firebase Storage directory");
}
}
deleteFiles(mediaStorageDir);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
hideProgressDialog();
[Link]();
}
});
}
By default, Firebase Storage rules applies Authentication restriction. If user is authenticated, only
then, he can perform operations on Firebase Storage, else he cannot. I have disabled the
authentication part in this demo by updating Storage rules. Previously, rules were looking like:
service [Link] {
match /b/**something**.[Link]/o {
match /{allPaths=**} {
allow read, write: if [Link] != null;
}
}
}
service [Link] {
match /b/**something**.[Link]/o {
[Link] 501
match /{allPaths=**} {
allow read, write;
}
}
}
First of all you need to setup your project adding Firebase to your Android project following the
steps described in this topic.
dependencies {
compile '[Link]:firebase-messaging:11.0.4'
}
For example:
<service
android:name=".MyInstanceIdListenerService">
<intent-filter>
<action android:name="[Link].INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<service
android:name=".MyFcmListenerService">
<intent-filter>
<action android:name="[Link].MESSAGING_EVENT" />
</intent-filter>
</service>
[Link] 502
Here are simple implementations of the 2 services.
To retrieve the current registration token extend the FirebaseInstanceIdService class and override
the onTokenRefresh() method:
// Called if InstanceID token is updated. Occurs if the security of the previous token had
been
// compromised. This call is initiated by the InstanceID provider.
@Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = [Link]().getToken();
To receive messages, use a service that extends FirebaseMessagingService and override the
onMessageReceived method.
/**
* Called when message is received.
*
* @param remoteMessage Object representing the message received from Firebase Cloud
Messaging.
*/
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
String from = [Link]();
// do whatever you want with this, post your own notification, or update local state
}
in Firebase can grouped user by their behavior like "AppVersion,free user,purchase user,or any
specific rules" and then send notification to specific group by send Topic Feature in fireBase.
to register user in topic use
[Link]().subscribeToTopic("Free");
[Link] 503
More info in the dedicated topic Firebase Cloud Messaging.
Here are simplified steps (based on the official documentation) required to create a Firebase
project and connect it with an Android app.
2. Click Add Firebase to your Android app and follow the setup steps.
4. At the end, you'll download a [Link] file. You can download this file again at
any time.
5. If you haven't done so already, copy the [Link] file into your project's module
folder, typically app/.
The next step is to Add the SDK to integrate the Firebase libraries in the project.
1. Add rules to your root-level [Link] file, to include the google-services plugin:
buildscript {
// ...
dependencies {
// ...
classpath '[Link]:google-services:3.1.0'
}
}
Then, in your module Gradle file (usually the app/[Link]), add the apply plugin line at the
bottom of the file to enable the Gradle plugin:
android {
// ...
[Link] 504
}
dependencies {
// ...
compile '[Link]:firebase-core:11.0.4'
}
The final step is to add the dependencies for the Firebase SDK using one or more libraries
available for the different Firebase features.
[Link]:firebase-core:11.0.4 Analytics
[Link]:firebase-storage:11.0.4 Storage
[Link]:firebase-auth:11.0.4 Authentication
[Link]:firebase-ads:11.0.4 AdMob
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Once it is done, create a child by editing your database address. For example:
[Link] to [Link]
We will put data to this location from our Android device. You don't have to create the database
[Link] 505
structure (tabs, fields... etc), it will be automatically created when you'll send Java object to
Firebase!
Create a Java object that contains all the attributes you want to send to the database:
if ([Link]().getCurrentUser() == null) {
[Link]().signInAnonymously().addOnCompleteListener(new
OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if ([Link]() && [Link]()){
FirebaseDatabase database = [Link]();
DatabaseReference reference = [Link]("chat"); // reference
is 'chat' because we created the database at /chat
}
}
});
}
To send a value:
[Link](new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
ChatMessage msg = [Link]([Link]);
Log.d(TAG, [Link]()+" "+[Link]());
}
[Link] 506
public void onChildRemoved(DataSnapshot dataSnapshot) {}
public void onChildMoved(DataSnapshot dataSnapshot, String s) {}
public void onCancelled(DatabaseError databaseError) {}
});
This example shows how to use the Firebase Cloud Messaging(FCM) platform. FCM is a
successor of Google Cloud Messaging(GCM). It does not require C2D_MESSAGE permissions
from the app users.
1. Create sample hello world project in Android Studio Your Android studio screen would look
like the following picture.
[Link] 507
[Link] 508
2. Next step is to set up firebase project. Visit [Link] and create a
project with an identical name, so that you can track it easily.
and create a project with an identical name, so that you can track it easily.
[Link] 509
3. Now it is time to add firebase to your sample android project you have just created. You will
need package name of your project and Debug signing certificate SHA-1(optional).
a. Package name - It can be found from the android manifest XML file.
b. Debug signing SHA-1 certificate - It can be found by running following command in the
terminal.
[Link] 510
keypass android
Enter this information in the firebase console and add the app to firebase project. Once you click
on add app button, your browser would automatically download a JSON file named "google-
[Link]".
4. Now copy the [Link] file you have just downloaded into your Android app
module root directory.
[Link] 511
[Link] 512
5. Follow the instructions given on the firebase console as you proceed ahead. a. Add following
code line to your project level [Link]
b. Add following code line at the end of your app level [Link].
c. Android studio would ask you to sync project. Click on Sync now.
6. Next task is to add two services. a. One extending FirebaseMessagingService with intent-
filter as following
<intent-filter>
<action android:name="[Link].MESSAGING_EVENT"/>
</intent-filter>
<intent-filter>
<action android:name="[Link].INSTANCE_ID_EVENT"/>
</intent-filter>
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
[Link] 513
9. Now it is time to capture the device registration token. Add following line of code to
MainActivity's onCreate method.
10. Once we have the access token, we can use firebase console to send out the notification.
Run the app on your android handset.
[Link] 514
[Link] 515
Chapter 101: Firebase App Indexing
Remarks
• When you opt to implement App Indexing then you may find lots of blogs, documentation out
there which may confuse you, in this case, I suggest you to stick to official docs provided by
Firebase-Google. Even if you want to use third party to do this, first try follow this
documentation because this will give you a clear idea how things are working.
• Google will take around 24 hours to index your content. So be patient. You can do testing to
make every thing is fine on your side.
• First example lets you support HTTP URL of your website to redirect in your App. This will
work such as, you have searched a query in the google search, results show one of your
website URL, whose app links are present in your app which is already installed. On clicking
this URL it will redirect you directly in your App Screen corresponding to that search result.
That's it I have discovered for this.
• Adding AppIndexing API indexes your content and used in Auto completions in Google
search Bar. Lets take example of inShorts Application for each page there is a headline and
small description. After reading 2 or 3 headlines, close the application and move to google
searchBar.
[Link] 516
Try entering headline you just went through, you will get App page suggestion with that Headline
as Title. This is different from App suggestions you get while searching for Apps. This happens
because you have written AppIndexing API code for this particular page and title is same as you
have initialized in onCreate().
[Link] 517
[Link] 518
Specify the ACTION_VIEW intent action so that the intent filter can be reached from Google
Search.
< data> Add one or more tags, where each tag represents a URI format that resolves to the
activity. At minimum, the tag must include the android:scheme attribute. You can add additional
attributes to further refine the type of URI that the activity accepts. For example, you might have
multiple activities that accept similar URIs, but which differ simply based on the path name. In this
case, use the android:path attribute or its variants (pathPattern or pathPrefix) to differentiate which
activity the system should open for different URI paths.
< category> Include the BROWSABLE category. The BROWSABLE category is required in order
for the intent filter to be accessible from a web browser. Without it, clicking a link in a browser
cannot resolve to your app. The DEFAULT category is optional, but recommended. Without this
category, the activity can be started only with an explicit intent, using your app component name.
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_schedule);
onNewIntent(getIntent());
}
Step 5 :- You can test this by using Android Debug Bridge command or studio configurations. Adb
command:- Launch your application and then run this command:-
Android Studio Configurations:- Android studio > Build > Edit Configuration >Launch
options>select URL>then type in your Url here >Apply and [Link] your application if “Run”
window shows error then you need to check your URL format with your applinks mentioned in
manifest otherwise it will successfully run,and redirect to page mentioned your URL if specified.
For Adding this to project you can find official doc easily but in this example I'm going to highlight
some of the key areas to be taken care of.
[Link] 519
dependencies {
...
compile '[Link]:play-services-appindexing:9.4.0'
...
}
import [Link];
import [Link];
import [Link];
//If you know the values that to be indexed then you can initialize these variables in
onCreate()
@Override
protected void onCreate(Bundle savedInstanceState) {
mClient = new [Link](this).addApi([Link]).build();
mUrl = "[Link]
mTitle = "Standard Poodle";
mDescription = "The Standard Poodle stands at least 18 inches at the withers";
}
//If your data is coming from a network request, then initialize these value in onResponse()
and make checks for NPE so that your code won’t fall apart.
[Link]();
[Link](mClient, getAction());
@Override
protected void onStop() {
if (mTitle != null && mDescription != null && mUrl != null) //if your response fails then
check whether these are initialized or not
if (getAction() != null) {
[Link](mClient, getAction());
[Link]();
}
[Link]();
}
[Link] 520
.setObject(object)
.setActionStatus(Action.STATUS_TYPE_COMPLETED)
.build();
}
[Link] 521
Chapter 102: Firebase Cloud Messaging
Introduction
Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably
deliver messages at no cost.
Using FCM, you can notify a client app that new email or other data is available to sync. You can
send notification messages to drive user reengagement and retention. For use cases such as
instant messaging, a message can transfer a payload of up to 4KB to a client app.
Examples
Set Up a Firebase Cloud Messaging Client App on Android
1. Complete the Installation and setup part to connect your app to Firebase.
This will create the project in Firebase.
2. Add the dependency for Firebase Cloud Messaging to your module-level [Link] file:
dependencies {
compile '[Link]:firebase-messaging:10.2.1'
}
FCM clients require devices running Android 2.3 or higher that also have the Google Play Store
app installed, or an emulator running Android 2.3 with Google APIs.
<service
android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="[Link].MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="[Link].INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
Registration token
On initial startup of your app, the FCM SDK generates a registration token for the client app
[Link] 522
instance.
If you want to target single devices or create device groups, you'll need to access this token by
extending FirebaseInstanceIdService.
The onTokenRefresh callback fires whenever a new token is generated and you can use the method
[Link]() to retrieve the current token.
Example:
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID
token
* is initially generated so this is where you would retrieve the token.
*/
@Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = [Link]().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
This code that i have implemnted in my app for pushing image,message and
also link for opening in your webView
This is my FirebaseMessagingService
/**
* Create and show a simple notification containing the received FCM message.
*/
[Link] 523
[Link]("LINK",link);
PendingIntent pendingIntent = [Link](this, 0 /* Request code */,
intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = [Link](RingtoneManager.TYPE_NOTIFICATION);
[Link] notificationBuilder = new [Link](this)
.setLargeIcon(image)/*Notification icon image*/
.setSmallIcon([Link])
.setContentTitle(messageBody)
.setStyle(new [Link]()
.bigPicture(image))/*Notification with Image*/
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
} catch (Exception e) {
// TODO Auto-generated catch block
[Link]();
return null;
}
}}
And this is MainActivity to open link in my WebView or other browser depand on your requirement
through intents.
if (getIntent().getExtras() != null) {
if (getIntent().getStringExtra("LINK")!=null) {
Intent i=new Intent(this,[Link]);
[Link]("link",getIntent().getStringExtra("LINK"));
[Link]("PUSH","yes");
[Link](i);
finish();
}}
Receive Messages
To receive messages, use a service that extends FirebaseMessagingService and override the
onMessageReceived method.
/**
[Link] 524
* Called when message is received.
*
* @param remoteMessage Object representing the message received from Firebase Cloud
Messaging.
*/
@Override
public void onMessageReceived(RemoteMessage message) {
String from = [Link]();
//.....
}
When the app is in the background, Android directs notification messages to the system tray. A
user tap on the notification opens the app launcher by default.
This includes messages that contain both notification and data payload (and all messages sent
from the Notifications console). In these cases, the notification is delivered to the device's system
tray, and the data payload is delivered in the extras of the intent of your launcher Activity.
Subscribe to a topic
Client apps can subscribe to any existing topic, or they can create a new topic. When a client app
subscribes to a new topic name, a new topic of that name is created in FCM and any client can
subsequently subscribe to it.
To subscribe to a topic use the subscribeToTopic() method specifying the topic name:
[Link]().subscribeToTopic("myTopic");
[Link] 525
Chapter 103: Firebase Crash Reporting
Examples
How to add Firebase Crash Reporting to your app
In order to add Firebase Crash Reporting to your app, perform the following steps:
• Copy the [Link] file from your project into your in app/ directory.
• Add the following rules to your root-level [Link] file in order to include the google-
services plugin:
buildscript {
// ...
dependencies {
// ...
classpath '[Link]:google-services:3.0.0'
}
}
• In your module Gradle file, add the apply plugin line at the bottom of the file to enable the
Gradle plugin:
• Add the dependency for Crash Reporting to your app-level [Link] file:
compile '[Link]:firebase-crash:10.2.1'
• You can then fire a custom exception from your application by using the following line:
• If you want to add custom logs to a console, you can use the following code:
[Link]("Level 2 completed.");
• Official documentation
• Stack Overflow dedicated topic
[Link] 526
How to report an error
Firebase Crash Reporting automatically generates reports for fatal errors (or uncaught
exceptions).
You can check in the log when FirebaseCrash initialized the module:
[Link]("Activity created");
[Link] 527
Chapter 104: Firebase Realtime DataBase
Remarks
Examples
Firebase Realtime DataBase event handler
[Link]("Hello, World!");
@Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", [Link]());
}
});
[Link] 528
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + [Link]());
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + [Link]());
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + [Link]());
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "postComments:onCancelled", [Link]());
[Link](mContext, "Failed to load comments.",
Toast.LENGTH_SHORT).show();
}
};
[Link](childEventListener);
Quick setup
1. Complete the Installation and setup part to connect your app to Firebase.
This will create the project in Firebase.
2. Add the dependency for Firebase Realtime Database to your module-level [Link] file:
compile '[Link]:firebase-database:10.2.1'
Now you are ready to work with the Realtime Database in Android.
For example you write a Hello World message to the database under the message key.
[Link]("Hello, World!");
Designing and understanding how to retrieve realtime data from the Firebase
Database
This example assumes that you have already set up a Firebase Realtime Database. If you are a
starter, then please inform yourself here on how to add Firebase to your Android project.
[Link] 529
First, add the dependency of the Firebase Database to the app level [Link] file:
compile '[Link]:firebase-database:9.4.0'
Now, let us create a chat app which stores data into the Firebase Database.
[
{
"name":"John Doe",
"message":"My first Message"
},
{
"name":"John Doe",
"message":"Second Message"
},
{
"name":"John Doe",
"message":"Third Message"
}
]
[Link](new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
// This function is called for every child id chat in this case, so using the above
[Link] 530
// example, this function is going to be called 3 times.
// Use the getValue function in the dataSnapshot and pass the object's class name to
// which you want to convert and get data. In this case it is [Link].
chat = [Link]([Link]);
// Now you can use this chat object and add it into an ArrayList or something like
// that and show it in the recycler view.
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
// This function is called when any of the node value is changed, dataSnapshot will
// get the data with the key of the child, so you can swap the new value with the
// old one in the ArrayList or something like that.
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
// This function is called when any of the child node is removed. dataSnapshot will
// get the data with the key of the child.
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
// This function is called when any of the child nodes is moved to a different
position.
@Override
public void onCancelled(DatabaseError databaseError) {
// If anything goes wrong, this function is going to be called.
Now get a reference to the chats node as done in the retrieving session:
[Link] 531
DatabaseReference chatDb = [Link]().getReference().child("chats");
Before you start adding data, keep in mind that you need one more deep reference since a chat
node has several more nodes and adding a new chat means adding a new node containing the
chat details. We can generate a new and unique name of the node using the push() function on
the DatabaseReference object, which will return another DatabaseReference, which in turn points to a
newly formed node to insert the chat data.
Example
// The parameter is the chat object that was newly created a few lines above.
[Link]().setValue(chat);
The setValue() function will make sure that all of the application's onDataChanged functions are
getting called (including the same device), which happens to be the attached listener of the "chats"
node.
Denormalization and a flat database structure is neccessary to efficiently download separate calls.
With the following structure, it is also possible to maintain two-way relationships. The
disadvantage of this approach is, that you always need to update the data in multiple places.
For an example, imagine an app which allows the user to store messages to himself (memos).
|--database
|-- memos
|-- memokey1
|-- title: "Title"
|-- content: "Message"
|-- memokey2
|-- title: "Important Title"
|-- content: "Important Message"
|-- users
|-- userKey1
|-- name: "John Doe"
|-- memos
|-- memokey1 : true //The values here don't matter, we only need the keys.
|-- memokey2 : true
|-- userKey2
|-- name: "Max Doe"
[Link] 532
//toMap() is necessary for the push process
private Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
[Link]("title", title);
[Link]("content", content);
return result;
}
}
@Override
public void onCancelled(DatabaseError databaseError) { }
});
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) { }
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) { }
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) { }
@Override
[Link] 533
public void onCancelled(DatabaseError databaseError) { }
}
Creating a memo
[Link]().getReference().updateChildren(childUpdates);
|--database
|-- memos
|-- memokey1
|-- title: "Title"
|-- content: "Message"
|-- memokey2
|-- title: "Important Title"
|-- content: "Important Message"
|-- generatedMemokey3
|-- title: "Important numbers"
|-- content: "1337, 42, 3.14159265359"
|-- users
|-- userKey1
|-- name: "John Doe"
|-- memos
|-- memokey1 : true //The values here don't matter, we only need the keys.
|-- memokey2 : true
|-- generatedMemokey3 : true
|-- userKey2
|-- name: "Max Doe"
Before we get our hands dirty with code, I feel it is necessary to understand how data is stored in
firebase. Unlike relational databases, firebase stores data in JSON format. Think of each row in a
relational database as a JSON object (which is basically unordered key-value pair). So the column
name becomes key and the value stored in that column for one particular row is the value. This
[Link] 534
way the entire row is represented as a JSON object and a list of these represent an entire
database table. The immediate benefit that I see for this is schema modification becomes much
more cheaper operation compared to old RDBMS. It is easier to add a couple of more attributes to
a JSON than altering a table structure.
{
"user_base" : {
"342343" : {
"email" : "[Link]@[Link]",
"authToken" : "some string",
"name" : "Kaushal",
"phone" : "+919916xxxxxx",
"serviceProviderId" : "firebase",
"signInServiceType" : "google",
},
"354895" : {
"email" : "[Link]@[Link]",
"authToken" : "some string",
"name" : "devil",
"phone" : "+919685xxxxxx",
"serviceProviderId" : "firebase",
"signInServiceType" : "github"
},
"371298" : {
"email" : "[Link]@[Link]",
"authToken" : "I am batman",
"name" : "Bruce Wayne",
"phone" : "+14085xxxxxx",
"serviceProviderId" : "firebase",
"signInServiceType" : "shield"
}
},
"user_prefs": {
"key1":{
"data": "for key one"
},
"key2":{
"data": "for key two"
},
"key3":{
"data": "for key three"
}
},
//other structures
}
This clearly shows how data that we used to store in relational databases can be stored in JSON
format. Next let's see how to read this data in android devices.
I am gonna assume you already know about adding gradle dependencies firebase in android
studio. If you don't just follow the guide from here. Add your app in firebase console, gradle sync
android studio after adding dependencies. All dependencies are not needed just firebase database
[Link] 535
and firebase auth.
Now that we know how data is stored and how to add gradle dependencies let's see how to use
the imported firebase android SDK to retrieve data.
from here you can chain multiple child() method calls to point to the data you are interested in. For
example if data is stored as depicted in previous section and you want to point to Bruce Wayne
user you can use:
Now that we have the reference of the data we want to fetch, we can use listeners to fetch data in
android apps. Unlike the traditional calls where you fire REST API calls using retrofit or volley,
here a simple callback listener is required to get the data. Firebase sdk calls the callback methods
and you are done.
There are basically two types of listeners you can attach, one is ValueEventListener and the other
one is ChildEventListener (described in next section). For any change in data under the node we
have references and added listeners to, value event listeners return the entire JSON structure and
child event listener returns specific child where the change has happened. Both of these are useful
in their own way. To fetch the data from firebase we can add one or more listeners to a firebase
database reference (list userDBRef we created earlier).
[Link](new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
User bruceWayne = [Link]("371298").getValue([Link]);
// Do something with the retrieved data or Bruce Wayne
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.e("UserListActivity", "Error occured");
// Do something about the error
});
[Link] 536
Did you notice the Class type passed. DataSnapshot can convert JSON data into our defined
POJOs, simple pass the right class type.
If your use case does not require the entire data (in our case user_base table) every time some
little change occurs or say you want to fetch the data only once, you can use
addListenerForSingleValueEvent() method of Database reference. This fires the callback only
once.
[Link](new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Do something
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Do something about the error
});
Above samples will give you the value of the JSON node. To get the key simply call:
Take a use case, like a chat app or a collaborative grocery list app (that basically requires a list of
objects to be synced across users). If you use firebase database and add a value event listener to
the chat parent node or grocery list parent node, you will end with entire chat structure from the
beginning of time (i meant beginning of your chat) every time a chat node is added (i.e. anyone
says hi). That we don't want to do, what we are interested in is only the new node or only the old
node that got deleted or modified, the unchanged ones should not be returned.
In this case we can use ChildEvenListener. Without any further adieu, here is code sample (see
prev sections for sample JSON data):
[Link](new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
//If not dealing with ordered data forget about this
}
[Link] 537
@Override
public void onCancelled(DatabaseError databaseError) {
});
Method names are self explanatory. As you can see whenever a new user is added or some
property of existing user is modified or user is deleted or removed appropriate callback method of
child event listener is called with relevant data. So if you are keeping UI refreshed for say chat
app, get the JSON from onChildAdded() parse into POJO and fit it in your UI. Just remember to
remove your listener when user leaves the screen.
onChildChanged() gives the entire child value with changed properties (new ones).
When you have a huge JSON database, adding a value event listener doesn't make sense. It will
return the huge JSON and parsing it would be time consuming. In such cases we can use
pagination and fetch part of data and display or process it. Kind of like lazy loading or like fetching
old chats when user clicks on show older chat. In this case Query can used.
Let's take the our old example in previous sections. The user base contains 3 users, if it grows to
say 3 hundred thousand user and you want to fetch the user list in batches of 50:
// class level
final int limit = 50;
int start = 0;
// event level
Query userListQuery = [Link]("email").limitToFirst(limit)
.startAt(start)
[Link](new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Do something
start += (limit+1);
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Do something about the error
});
Here value or child events can be added and listened to. Call query again to fetch next 50. Make
sure to add the orderByChild() method, this will not work without that. Firebase needs to know
the order by which you are paginating.
[Link] 538
Chapter 105: FloatingActionButton
Introduction
Floating action button is used for a special type of promoted action,it animates onto the screen as
an expanding piece of material, by default. The icon within it may be animated,also FAB may
move differently than other UI elements because of their relative importance. A floating action
button represents the primary action in an application which can simply trigger an action or
navigate somewhere.
Parameters
Parameter Detail
Remarks
Floating action buttons are used for a special type of promoted action. They are distinguished by a
circled icon floating above the UI and have special motion behaviors related to morphing,
launching, and the transferring anchor point.
Only one floating action button is recommended per screen to represent the most common action.
Before using the FloatingActionButton you must add the design support library dependency in the
[Link] file:
dependencies {
compile '[Link]:design:25.1.0'
}
Official Documentation:
[Link]
[Link] 539
Material Design Specifications:
[Link]
Examples
How to add the FAB to the layout
To use a FloatingActionButton just add the dependency in the [Link] file as described in the
remarks section.
<[Link]
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/my_icon" />
An example:
Color
The background color of this view defaults to the your theme's colorAccent.
In the above image if the src only points to + icon (by default 24x24 dp),to get the background
color of full circle you can use app:backgroundTint="@color/your_colour"
[Link] 540
[Link](your color in int);
Positioning
It is recommended to place 16dp minimum from the edge on mobile,and 24dp minimum on
tablet/desktop.
Note : Once you set an src excepting to cover the full area of FloatingActionButton make sure you
have the right size of that image to get the best result.
If you only want to change only the Interior icon use a 24 x 24dp icon for default size
To show and hide a FloatingActionButton with the default animation, just call the methods show()
and hide(). It's good practice to keep a FloatingActionButton in the Activity layout instead of putting
it in a Fragment, this allows the default animations to work when showing and hiding.
• Three Tabs
• Show FloatingActionButton for the first and third Tab
• Hide the FloatingActionButton on the middle Tab
FloatingActionButton fab;
ViewPager viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
[Link](new [Link]() {
@Override
public void onPageSelected(int position) {
if (position == 0) {
[Link]([Link].ic_dialog_email);
[Link]();
[Link] 541
} else if (position == 2) {
[Link]([Link].ic_dialog_map);
[Link]();
} else {
[Link]();
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int
positionOffsetPixels) {}
@Override
public void onPageScrollStateChanged(int state) {}
});
}
}
Result:
[Link] 542
Show and Hide FloatingActionButton on Scroll
Starting with the Support Library version 22.2.1, it's possible to show and hide a
FloatingActionButton from scrolling behavior using a [Link] sublclass that
takes advantage of the show() and hide() methods.
Note that this only works with a CoordinatorLayout in conjunction with inner Views that support
Nested Scrolling, such as RecyclerView and NestedScrollView.
This ScrollAwareFABBehavior class comes from the Android Guides on Codepath (cc-wiki with attribution
required)
@Override
public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final
FloatingActionButton child,
final View directTargetChild, final View target, final
int nestedScrollAxes) {
// Ensure we react to vertical scrolling
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
|| [Link](coordinatorLayout, child, directTargetChild,
target, nestedScrollAxes);
}
[Link] 543
@Override
public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final
FloatingActionButton child,
final View target, final int dxConsumed, final int dyConsumed,
final int dxUnconsumed, final int dyUnconsumed) {
[Link](coordinatorLayout, child, target, dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed);
if (dyConsumed > 0 && [Link]() == [Link]) {
// User scrolled down and the FAB is currently visible -> hide the FAB
[Link]();
} else if (dyConsumed < 0 && [Link]() != [Link]) {
// User scrolled up and the FAB is currently not visible -> show the FAB
[Link]();
}
}
}
In the FloatingActionButton layout xml, specify the app:layout_behavior with the fully-qualified-
class-name of ScrollAwareFABBehavior:
app:layout_behavior="[Link]"
<[Link]
android:id="@+id/main_layout"
xmlns:android="[Link]
xmlns:app="[Link]
xmlns:tools="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<[Link]
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="6dp">
<[Link]
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="@style/[Link]"
app:popupTheme="@style/[Link]"
app:elevation="0dp"
app:layout_scrollFlags="scroll|enterAlways"
/>
<[Link]
android:id="@+id/tab_layout"
app:tabMode="fixed"
android:layout_below="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
[Link] 544
android:background="?attr/colorPrimary"
app:elevation="0dp"
app:tabTextColor="#d3d3d3"
android:minHeight="?attr/actionBarSize"
/>
</[Link]>
<[Link]
android:id="@+id/viewpager"
android:layout_below="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
<[Link]
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
app:layout_behavior="[Link]"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email" />
</[Link]>
[Link] 545
Setting behaviour of FloatingActionButton
For example:
<[Link]
app:layout_behavior=".MyBehavior" />
[Link] 546
Chapter 106: Formatting phone numbers with
pattern.
Introduction
This example show you how to format phone numbers with a patter
compile '[Link]:libphonenumber:7.2.2'
Examples
Patterns + 1 (786) 1234 5678
Given a normalized phone number like +178612345678 we will get a formatted number with the
provided pattern.
[Link] = "(\\d{3})(\\d{3})(\\d{4})";
[Link](numberFormat);
try {
phoneNumberPN = [Link](phoneNumber, [Link]());
phoneNumber = [Link](phoneNumberPN,
[Link], newNumberFormats);
} catch (NumberParseException e) {
[Link]();
}
return phoneNumber;
}
[Link] 547
Chapter 107: Formatting Strings
Examples
Format a string resource
You can add wildcards in string resources and populate them at runtime:
1. Edit [Link]
Data types like int, float, double, long, boolean can be formatted to string using [Link]().
[Link] 548
Chapter 108: Fragments
Introduction
Introduction about Fragments and their intercommunication mechanism
Syntax
• void onActivityCreated(Bundle savedInstanceState) // Called when the fragment's activity
has been created and this fragment's view hierarchy instantiated.
• void onActivityResult(int requestCode, int resultCode, Intent data) // Receive the result from
a previous call to startActivityForResult(Intent, int).
• void onAttach(Activity activity) // This method was deprecated in API level 23. Use
onAttach(Context) instead.
• void onAttach(Context context) // Called when a fragment is first attached to its context.
• void onDetach() // Called when the fragment is no longer attached to its activity.
• void onResume() // Called when the fragment is visible to the user and actively running.
[Link] 549
• void onSaveInstanceState(Bundle outState) // Called to ask the fragment to save its current
dynamic state, so it can later be reconstructed in a new instance of its process is restarted.
Remarks
A Fragment represents a behavior or a portion of user interface in an Activity. You can combine
multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple
activities. You can think of a fragment as a modular section of an activity, which has its own
lifecycle, receives its own input events, and which you can add or remove while the activity is
running (sort of like a "sub activity" that you can reuse in different activities).
Constructor
Every fragment must have an empty constructor, so it can be instantiated when restoring its
activity's state. It is strongly recommended that subclasses do not have other constructors with
parameters, since these constructors will not be called when the fragment is re-instantiated;
instead, arguments can be supplied by the caller with setArguments(Bundle) and later retrieved by
the Fragment with getArguments().
Examples
The newInstance() pattern
Although it is possible to create a fragment constructor with parameters, Android internally calls
the zero-argument constructor when recreating fragments (for example, if they are being restored
after being killed for Android's own reasons). For this reason, it is not advisable to rely on a
constructor that has parameters.
To ensure that your expected fragment arguments are always present you can use a static
newInstance() method to create the fragment, and put whatever parameters you want in to a
bundle that will be available when creating a new instance.
import [Link];
import [Link];
[Link] 550
private String mName;
// Required
public MyFragment(){}
// The static constructor. This is the only way that you should instantiate
// the fragment yourself
public static MyFragment newInstance(final String name) {
final MyFragment myFragment = new MyFragment();
// The 1 below is an optimization, being the number of arguments that will
// be added to this bundle. If you know the number of arguments you will add
// to the bundle it stops additional allocations of the backing map. If
// unsure, you can construct Bundle without any arguments
final Bundle args = new Bundle(1);
// This stores the argument as an argument in the bundle. Note that even if
// the 'name' parameter is NULL then this will work, so you should consider
// at this point if the parameter is mandatory and if so check for NULL and
// throw an appropriate error if so
[Link](NAME_ARG, name);
[Link](args);
return myFragment;
}
@Override
public void onCreate(final Bundle savedInstanceState) {
[Link](savedInstanceState);
final Bundle arguments = getArguments();
if (arguments == null || ) {
// Set a default or error as you see fit
} else {
mName = [Link](NAME_ARG);
}
}
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
MyFragment mFragment = [Link]("my name");
[Link]([Link], mFragment);
//[Link] is where we want to load our fragment
[Link]();
This pattern is a best practice to ensure that all the needed arguments will be passed to fragments
on creation. Note that when the system destroys the fragment and re-creates it later, it will
automatically restore its state - but you must provide it with an onSaveInstanceState(Bundle)
implementation.
First of all, we need to add our first Fragment at the beginning, we should do it in the onCreate()
method of our Activity:
if (null == savedInstanceState) {
[Link] 551
getSupportFragmentManager().beginTransaction()
.addToBackStack("fragmentA")
.replace([Link], [Link](), "fragmentA")
.commit();
}
Next, we need to manage our backstack. The easiest way is using a function added in our activity
that is used for all FragmentTransactions.
//If fragment is already on stack, we can pop back stack to prevent stack infinite growth
if (getSupportFragmentManager().findFragmentByTag(tag) != null) {
getSupportFragmentManager().popBackStack(tag,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
Finally, we should override onBackPressed() to exit the application when going back from the last
Fragment available in the backstack.
@Override
public void onBackPressed() {
int fragmentsInStack = getSupportFragmentManager().getBackStackEntryCount();
if (fragmentsInStack > 1) { // If we have more than one fragment, pop back stack
getSupportFragmentManager().popBackStack();
} else if (fragmentsInStack == 1) { // Finish activity, if only one fragment left, to
prevent leaving empty screen
finish();
} else {
[Link]();
}
}
Execution in activity:
replaceFragment([Link](), "fragmentB");
[Link] 552
Pass data from Activity to Fragment using Bundle
All fragments should have an empty constructor (i.e. a constructor method having no input
arguments). Therefore, in order to pass your data to the Fragment being created, you should use
the setArguments() method. This methods gets a bundle, which you store your data in, and stores
the Bundle in the arguments. Subsequently, this Bundle can then be retrieved in onCreate() and
onCreateView() call backs of the Fragment.
Activity:
Fragment:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
String myValue = [Link]().getString("message");
...
}
If you need to send events from fragment to activity, one of the possible solutions is to define
callback interface and require that the host activity implement it.
Example
Send callback to an activity, when fragment's button clicked
First of all, define callback interface:
@Override
[Link] 553
public void onAttach(Context context) {
[Link](context);
if (context instanceof SampleCallback) {
callback = (SampleCallback) context;
} else {
throw new RuntimeException([Link]()
+ " must implement SampleCallback");
}
}
@Override
public void onDetach() {
[Link]();
callback = null;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
final View view = [Link]([Link], container, false);
// Add button's click listener
[Link]([Link]).setOnClickListener(new [Link]() {
public void onClick(View v) {
[Link](); // Invoke callback here
}
});
return view;
}
}
// ... Skipped code with settings content view and presenting the fragment
@Override
public void onButtonClicked() {
// Invoked when fragment's button has been clicked
}
}
To animate the transition between fragments, or to animate the process of showing or hiding a
fragment you use the FragmentManager to create a FragmentTransaction.
For a single FragmentTransaction, there are two different ways to perform animations: you can use
a standard animation or you can supply your own custom animations.
FragmentTransaction.TRANSIT_NONE
FragmentTransaction.TRANSIT_FRAGMENT_OPEN
[Link] 554
FragmentTransaction.TRANSIT_FRAGMENT_CLOSE
FragmentTransaction.TRANSIT_FRAGMENT_FADE
getSupportFragmentManager()
.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace([Link], new MyFragment(), "MyFragmentTag")
.commit();
The enter and exit animations will be played for FragmentTransactions that do not involve popping
fragments off of the back stack. The popEnter and popExit animations will be played when popping
a fragment off of the back stack.
The following code shows how you would replace a fragment by sliding out one fragment and
sliding the other one in it's place.
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations([Link].slide_in_left, [Link].slide_out_right)
.replace([Link], new MyFragment(), "MyFragmentTag")
.commit();
The XML animation definitions would use the objectAnimator tag. An example of slide_in_left.xml
might look something like this:
Additional Resources
[Link] 555
In this sample, we have a MainActivity that hosts two fragments, SenderFragment and
ReceiverFragment, for sending and receiving a message (a simple String in this case) respectively.
A Button in SenderFragment initiates the process of sending the message. A TextView in the
ReceiverFragment is updated when the message is received by it.
Following is the snippet for the MainActivity with comments explaining the important lines of code:
// Our MainActivity implements the interface defined by the SenderFragment. This enables
// communication from the fragment to the activity
public class MainActivity extends AppCompatActivity implements
[Link] {
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
}
/**
* This method is called when we click on the button in the SenderFragment
* @param message The message sent by the SenderFragment
*/
@Override
public void onSendMessage(String message) {
// Find our ReceiverFragment using the SupportFragmentManager and the fragment's id
ReceiverFragment receiverFragment = (ReceiverFragment)
getSupportFragmentManager().findFragmentById([Link].fragment_receiver);
The layout file for the MainActivity hosts two fragments inside a LinearLayout :
<fragment
android:id="@+id/fragment_sender"
android:name="[Link]"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
[Link] 556
tools:layout="@layout/fragment_sender" />
<fragment
android:id="@+id/fragment_receiver"
android:name="[Link]"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
tools:layout="@layout/fragment_receiver" />
</LinearLayout>
The SenderFragment exposes an interface SendMessageListener that helps the MainActivity know
when Button in the SenderFragment was clicked.
Following is the code snippet for the SenderFragment explaining the important lines of code:
/**
* This interface is created to communicate between the activity and the fragment. Any
activity
* which implements this interface will be able to receive the message that is sent by this
* fragment.
*/
public interface SendMessageListener {
void onSendMessage(String message);
}
/**
* API LEVEL >= 23
* <p>
* This method is called when the fragment is attached to the activity. This method here will
* help us to initialize our reference variable, 'commander' , for our interface
* 'SendMessageListener'
*
* @param context
*/
@Override
public void onAttach(Context context) {
[Link](context);
// Try to cast the context to our interface SendMessageListener i.e. check whether the
// activity implements the SendMessageListener. If not a ClassCastException is thrown.
try {
commander = (SendMessageListener) context;
} catch (ClassCastException e) {
throw new ClassCastException([Link]()
+ "must implement the SendMessageListener interface");
}
}
/**
* API LEVEL < 23
* <p>
* This method is called when the fragment is attached to the activity. This method here will
* help us to initialize our reference variable, 'commander' , for our interface
* 'SendMessageListener'
*
[Link] 557
* @param activity
*/
@Override
public void onAttach(Activity activity) {
[Link](activity);
// Try to cast the context to our interface SendMessageListener i.e. check whether the
// activity implements the SendMessageListener. If not a ClassCastException is thrown.
try {
commander = (SendMessageListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException([Link]()
+ "must implement the SendMessageListener interface");
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// Inflate view for the sender fragment.
View view = [Link]([Link].fragment_receiver, container, false);
// Call our interface method. This enables us to call the implemented method
// in the activity, from where we can send the message to the
ReceiverFragment.
[Link]("HELLO FROM SENDER FRAGMENT!");
}
}
});
return view;
}
}
<Button
android:id="@+id/bSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SEND"
android:layout_gravity="center_horizontal" />
</LinearLayout>
[Link] 558
The ReceiverFragment is simple and exposes a simple public method to updates its TextView.
When the MainActivity receives the message from the SenderFragment it calls this public method of
the ReceiverFragment
Following is the code snippet for the ReceiverFragment with comments explaining the important
lines of code :
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// Inflate view for the sender fragment.
View view = [Link]([Link].fragment_receiver, container, false);
return view;
}
/**
* Method that is called by the MainActivity when it receives a message from the
SenderFragment.
* This method helps update the text in the TextView to the message sent by the
SenderFragment.
* @param message Message sent by the SenderFragment via the MainActivity.
*/
public void showMessage(String message) {
[Link](message);
}
}
[Link] 559
Chapter 109: Fresco
Introduction
Fresco is a powerful system for displaying images in Android applications.
In Android 4.x and lower, Fresco puts images in a special region of Android memory (called
ashmem). This lets your application run faster - and suffer the dreaded OutOfMemoryError much
less often.
Remarks
How to set up dependencies in the app level [Link] file:
dependencies {
// Your app's other dependencies.
compile '[Link]:fresco:0.14.1' // Or a newer version if available.
}
Examples
Getting Started with Fresco
If you need additional features, like animated GIF or WebP support, you have to add the
corresponding Fresco artifacts as well.
Fresco needs to be initialized. You should only do this 1 time, so placing the initialization in your
Application is a good idea. An example for this would be:
If you want to load remote images from a server, your app needs the internt permission. Simply
add it to your [Link]:
[Link] 560
Then, add a SimpleDraweeView to your XML layout. Fresco does not support wrap_content for image
dimensions since you might have multiple images with different dimensions (placeholder image,
error image, actual image, ...).
So you can either add a SimpleDraweeView with fixed dimensions (or match_parent):
<[Link]
android:id="@+id/my_image_view"
android:layout_width="120dp"
android:layout_height="120dp"
fresco:placeholderImage="@drawable/placeholder" />
<[Link]
android:id="@+id/my_image_view"
android:layout_width="120dp"
android:layout_height="wrap_content"
fresco:viewAspectRatio="1.33"
fresco:placeholderImage="@drawable/placeholder" />
That's it! You should see your placeholder drawable until the network image has been fetched.
First, in addition to the normal Fresco Gradle dependency, you have to add the OkHttp 3
dependency to your [Link]:
When you initialize Fresco (usually in your custom Application implementation), you can now
specify your OkHttp client:
This example assumes that you have already added Fresco to your app (see this example):
[Link] 561
SimpleDraweeView img = new SimpleDraweeView(context);
ImageRequest request = ImageRequestBuilder
.newBuilderWithSource([Link]("[Link]
.setProgressiveRenderingEnabled(true) // This is where the magic happens.
.build();
[Link] 562
Chapter 110: Genymotion for android
Introduction
Genymotion is a fast third-party emulator that can be used instead of the default Android emulator.
In some cases it's as good as or better than developing on actual devices!
Examples
Installing Genymotion, the free version
Note: you will need to create a new account OR log-in with your account.
Genymotion, can be integrated with Android Studio via a plugin, here the steps to install it in Android
Studio
[Link] 563
• Select Plugins and click Browse Repositories.
• Right-click on Genymotion and click Download and install.
You should now be able to see the plugin icon, see this image
Note, you might want to display the toolbar by clicking View > Toolbar.
Now you should be able to run Genymotion's emulator by pressing the plugin icon and selecting an
installed emulator and then press start button!
If developers want to test Google Maps or any other Google service like Gmail,Youtube, Google
drive etc. then they first need to install Google framework on Genymotion. Here are the steps:-
4.4 Kitkat
5.0 Lollipop
5.1 Lollipop
6.0 Marshmallow
7.0 Nougat
7.1 Nougat (webview patch)
Reference:-
Stack overflow question on this topic
[Link] 564
Chapter 111: Gesture Detection
Remarks
Official Documentation: Detecting Common Gestures
Examples
Swipe Detection
@Override
public boolean onTouch(View v, MotionEvent event) {
return [Link](event);
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float
velocityY) {
float diffY = [Link]() - [Link]();
float diffX = [Link]() - [Link]();
if ([Link](diffX) > [Link](diffY)) {
if ([Link](diffX) > SWIPE_THRESHOLD && [Link](velocityX) >
SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
}
} else if ([Link](diffY) > SWIPE_THRESHOLD && [Link](velocityY) >
SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom();
} else {
onSwipeTop();
}
}
[Link] 565
return true;
}
}
Applied to a view...
[Link](new OnSwipeListener(context) {
public void onSwipeTop() {
Log.d("OnSwipeListener", "onSwipeTop");
}
public void onSwipeRight() {
Log.d("OnSwipeListener", "onSwipeRight");
}
public void onSwipeLeft() {
Log.d("OnSwipeListener", "onSwipeLeft");
}
public void onSwipeBottom() {
Log.d("OnSwipeListener", "onSwipeBottom");
}
});
@Override
public void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_main);
mGestureDetector = new GestureDetector(this, this);
[Link](this);
}
@Override
public boolean onTouchEvent(MotionEvent event){
[Link](event);
return [Link](event);
}
[Link] 566
@Override
public boolean onDown(MotionEvent event) {
Log.d("GestureDetector","onDown");
return true;
}
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float
velocityY) {
Log.d("GestureDetector","onFling");
return true;
}
@Override
public void onLongPress(MotionEvent event) {
Log.d("GestureDetector","onLongPress");
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
{
Log.d("GestureDetector","onScroll");
return true;
}
@Override
public void onShowPress(MotionEvent event) {
Log.d("GestureDetector","onShowPress");
}
@Override
public boolean onSingleTapUp(MotionEvent event) {
Log.d("GestureDetector","onSingleTapUp");
return true;
}
@Override
public boolean onDoubleTap(MotionEvent event) {
Log.d("GestureDetector","onDoubleTap");
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent event) {
Log.d("GestureDetector","onDoubleTapEvent");
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
Log.d("GestureDetector","onSingleTapConfirmed");
return true;
}
[Link] 567
Chapter 112: Getting Calculated View
Dimensions
Remarks
Note that a ViewTreeObserver instance associated with a View instance can become invalid while
that View is still alive. From the [Link] javadocs:
Thus, if you have previously added a listener to a ViewTreeObserver instance and now wish to
remove it, it is easiest to call getViewTreeObserver on the corresponding View instance again to
receive a fresh ViewTreeObserver instance. (Checking isAlive on an existing instance is more work
for little benefit; if the ViewTreeObserver is no longer alive, you'll be fetching that fresh reference
anyway!)
Examples
Calculating initial View dimensions in an Activity
package [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_example);
[Link]().addOnPreDrawListener(new
[Link]() {
@Override
public boolean onPreDraw() {
// viewToMeasure is now measured and laid out, and displayed dimensions are
known.
[Link] 568
logComputedViewDimensions([Link](),
[Link]());
[Link] 569
Chapter 113: Getting started with OpenGL ES
2.0+
Introduction
This topic is about setting up and using OpenGL ES 2.0+ on Android. OpenGL ES is the standard
for 2D and 3D accelerated graphics on embedded systems - including consoles, smartphones,
appliances and vehicles.
Examples
Setting up GLSurfaceView and OpenGL ES 2.0+
To use OpenGL ES in your application you must add this to the manifest:
import static [Link].GLES20.*; // To use all OpenGL ES 2.0 methods and constants
statically
[Link] 570
<[Link]
android:id="@+id/gles_renderer"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
To use newer version of OpenGL ES just change the version number in your manifest, in the static
import and change setEGLContextClientVersion.
The Assets folder is the most common place to store your GLSL-ES shader files. To use them in
your OpenGL ES application you need to load them to a string in the first place. This functions
creates a string from the asset file:
Now you need to create a function that compiles a shader stored in a sting:
[Link] 571
// Load shaders from file
String vertexShaderString = loadStringFromAssetFile(context, "your_vertex_shader.glsl");
String fragmentShaderString = loadStringFromAssetFile(context, "your_fragment_shader.glsl");
// Compile shaders
int vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderString);
int fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderString);
glUseProgram(shaderProgram);
[Link] 572
Chapter 114: Getting system font names and
using the fonts
Introduction
The following examples show how to retrieve the default names of the system fonts that are store
in the /system/fonts/ directory and how to use a system font to set the typeface of a TextView
element.
Examples
Getting system font names
In the following code you need to replace fontsname by the name of the font you would like to use:
Read Getting system font names and using the fonts online:
[Link]
[Link] 573
Chapter 115: Glide
Introduction
**** WARNING This documentation is unmaintained and frequently inaccurate ****
Remarks
Glide is a fast and efficient open source media management and image loading framework for
Android that wraps media decoding, memory and disk caching, and resource pooling into a simple
and easy to use interface.
Glide supports fetching, decoding, and displaying video stills, images, and animated GIFs. Glide
includes a flexible API that allows developers to plug in to almost any network stack.
By default Glide uses a custom HttpUrlConnection based stack, but also includes utility libraries
plug in to Google's Volley project or Square's OkHttp library instead.
Glide's primary focus is on making scrolling any kind of a list of images as smooth and fast as
possible, but Glide is also effective for almost any case where you need to fetch, resize, and
display a remote image.
Examples
Add Glide to your project
With Gradle:
repositories {
mavenCentral() // jcenter() works as well because it pulls from Maven Central
}
dependencies {
compile '[Link]:glide:4.0.0'
compile '[Link]:support-v4:25.3.1'
annotationProcessor '[Link]:compiler:4.0.0'
}
With Maven:
[Link] 574
<dependency>
<groupId>[Link]</groupId>
<artifactId>glide</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>support-v4</artifactId>
<version>r7</version>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>compiler</artifactId>
<version>4.0.0</version>
<optional>true</optional>
</dependency>
Depending on your ProGuard (DexGuard) config and usage, you may also need to include the
following lines in your [Link] (See Glide's wiki for more info):
Loading an image
ImageView
To load an image from a specified URL, Uri, resource id, or any other model into an ImageView:
[Link](context)
.load(yourUrl)
.into(imageView);
For Uris, replace yourUrl with your Uri (content://media/external/images/1). For Drawables replace
yourUrl with your resource id ([Link]).
@Override
public void onBindViewHolder([Link] viewHolder, int position) {
MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
[Link] 575
String currentUrl = [Link](position);
[Link](context)
.load(currentUrl)
.into([Link]);
}
If you don't want to start a load in onBindViewHolder, make sure you clear() any ImageView Glide
may be managing before modifying the ImageView:
@Override
public void onBindViewHolder([Link] viewHolder, int position) {
MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
String currentUrl = [Link](position);
if ([Link](currentUrl)) {
[Link]([Link]);
// Now that the view has been cleared, you can safely set your own resource
[Link]([Link].missing_image);
} else {
[Link](context)
.load(currentUrl)
.into([Link]);
}
}
[Link] 576
[Link](new BitmapShader(squared, [Link],
[Link]));
[Link](true);
float r = size / 2f;
[Link](r, r, r, paint);
return result;
}
Usage:
[Link](context)
.load(yourimageurl)
.transform(new CircleTransform(context))
.into(userImageView);
Default transformations
Glide includes two default transformations, fit center and center crop.
Fit center:
[Link](context)
.load(yourUrl)
.fitCenter()
.into(yourView);
Center crop:
[Link](context)
.load(yourUrl)
.centerCrop()
.into(yourView);
[Link] 577
@Override
protected void setResource(final Bitmap resource) {
RoundedBitmapDrawable circularBitmapDrawable =
[Link]([Link](), resource);
[Link](radius);
[Link](circularBitmapDrawable);
}
};
}
Loading image:
[Link](context)
.load(imageUrl)
.asBitmap()
.into([Link](context, imageView, radius));
Because you use asBitmap() the animations will be removed though. You can use your own
animation in this place using the animate() method.
[Link](context)
.load(imageUrl)
.asBitmap()
.animate([Link].abc_fade_in)
.into([Link](context, imageView, radius));
Please note this animation is support library private resource - it is unrecommended to use as it
can change or even be removed.
Preloading images
To preload remote images and ensure that the image is only downloaded once:
[Link](context)
.load(yourUrl)
.diskCacheStrategy([Link])
.preload();
Then:
[Link](context)
.load(yourUrl)
.diskCacheStrategy([Link]) // ALL works here too
.into(imageView);
To preload local images and make sure a transformed copy is in the disk cache (and maybe the
memory cache):
[Link] 578
[Link](context)
.load(yourFilePathOrUri)
.fitCenter() // Or whatever transformation you want
.preload(200, 200); // Or whatever width and height you want
Then:
[Link](context)
.load(yourFilePathOrUri)
.fitCenter() // You must use the same transformation as above
.override(200, 200) // You must use the same width and height as above
.into(imageView);
If you want to add a Drawable be shown during the load, you can add a placeholder:
[Link](context)
.load(yourUrl)
.placeholder([Link])
.into(imageView);
If you want a Drawable to be shown if the load fails for any reason:
[Link](context)
.load(yourUrl)
.error([Link])
.into(imageView);
If you want a Drawable to be shown if you provide a null model (URL, Uri, file path etc):
[Link](context)
.load(maybeNullUrl)
.fallback([Link])
.into(imageView);
@Override
[Link] 579
protected void setResource(Bitmap resource)
{
RoundedBitmapDrawable bitmapDrawable =
[Link]([Link](), resource);
[Link](true);
[Link](bitmapDrawable);
}
}
Usage:
Glide
.with(context)
.load(yourimageidentifier)
.asBitmap()
.into(new CircularBitmapImageViewTarget(context, imageView));
Glide
.with(context)
.load(currentUrl)
.into(new BitmapImageViewTarget(profilePicture) {
@Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable circularBitmapDrawable =
[Link]([Link](), resource);
[Link](radius);
[Link](circularBitmapDrawable);
}
@Override
public void onLoadFailed(@NonNull Exception e, Drawable errorDrawable) {
[Link](e, SET_YOUR_DEFAULT_IMAGE);
Log.e(TAG, [Link](), e);
}
});
Here at SET_YOUR_DEFAULT_IMAGE place you can set any default Drawable. This image will be shown if
Image loading is failed.
[Link] 580
Chapter 116: Google Awareness APIs
Remarks
Remember, the Snapshot API is used to request current state while the Fence API continuously
checks for a specified state and sends callbacks when an app isn't running.
Overall, there are a few basic steps in order to use the Snapshot API or Fence API:
<!-- Replace with your actual API key from console -->
<meta-data android:name="[Link].API_KEY"
android:value="YOUR_API_KEY"/>
• Parse result
An easy way to check for the needed user permission is a method such as this:
Examples
Get current user activity using Snapshot API
[Link] 581
For one-time, non-constant requests for a user's physical activity, use the Snapshot API:
[Link] 582
}
}
});
As for getting the data in those places, here are some options:
If you want to detect when your user starts or finishes an activity such as walking, running, or any
other activity of the DetectedActivityFence class, you can create a fence for the activity that you
want to detect, and get notified when your user starts/finishes this activity. By using a
BroadcastReceiver, you will get an Intent with data that contains the activity:
// Your own action filter, like the ones used in the Manifest.
private static final String FENCE_RECEIVER_ACTION = BuildConfig.APPLICATION_ID +
"FENCE_RECEIVER_ACTION";
private static final String FENCE_KEY = "walkingFenceKey";
private FenceReceiver mFenceReceiver;
private PendingIntent mPendingIntent;
// The 0 is a standard Activity request code that can be changed to your needs.
mPendingIntent = [Link](this, 0,
new Intent(FENCE_RECEIVER_ACTION), 0);
[Link] 583
registerReceiver(mFenceReceiver, new IntentFilter(FENCE_RECEIVER_ACTION));
Now you can receive the intent with a BroadcastReceiver to get callbacks when the user changes
the activity:
@Override
public void onReceive(Context context, Intent intent) {
// Get the fence state
FenceState fenceState = [Link](intent);
switch ([Link]()) {
case [Link]:
Log.i(TAG, "User is walking");
break;
case [Link]:
Log.i(TAG, "User is not walking");
break;
case [Link]:
Log.i(TAG, "User is doing something unknown");
break;
}
}
}
Get changes for location within a certain range using Fence API
If you want to detect when your user enters a specific location, you can create a fence for the
specific location with a radius you want and be notified when your user enters or leaves the
location.
// Your own action filter, like the ones used in the Manifest
private static final String FENCE_RECEIVER_ACTION = BuildConfig.APPLICATION_ID +
"FENCE_RECEIVER_ACTION";
private static final String FENCE_KEY = "locationFenceKey";
[Link] 584
private FenceReceiver mFenceReceiver;
private PendingIntent mPendingIntent;
// The 0 is a standard Activity request code that can be changed for your needs
mPendingIntent = [Link](this, 0,
new Intent(FENCE_RECEIVER_ACTION), 0);
registerReceiver(mFenceReceiver, new IntentFilter(FENCE_RECEIVER_ACTION));
@Override
public void onReceive(Context context, Intent intent) {
// Get the fence state
FenceState fenceState = [Link](intent);
switch ([Link]()) {
case [Link]:
Log.i(TAG, "User is in location");
break;
case [Link]:
Log.i(TAG, "User is not in location");
break;
case [Link]:
Log.i(TAG, "User is doing something unknown");
break;
}
}
}
[Link] 585
Chapter 117: Google Drive API
Introduction
Google Drive is a file hosting service created by Google. It provides file storage service and
allows the user to upload files in the cloud and also share with other people. Using Google Drive
API, we can synchronize files between computer or mobile device and Google Drive Cloud.
Remarks
Legal
If you use the Google Drive Android API in your application, you must include the Google Play
Services attribution text as part of a "Legal Notices" section in your application.
It’s recommended that you include legal notices as an independent menu item, or as part of an
"About" menu item.
Examples
Integrate Google Drive in Android
To integrate Android application with Google Drive, create the credentials of project in the Google
Developers Console. So, we need to create a project on Google Developer console.
• Go to Google Developer Console for Android. Fill your project name in the input field and
click on the create button to create a new project on Google Developer console.
[Link] 586
• We need to create credentials to access API. So, click on the Create credentials button.
• Now, a pop window will open. Click on API Key option in the list to create API key.
[Link] 587
• We need an API key to call Google APIs for Android. So, click on the Android Key to
identify your Android Project.
• Next, we need to add Package Name of the Android Project and SHA-1 fingerprint in the
input fields to create API key.
[Link] 588
• We need to generate SHA-1 fingerprint. So, open your terminal and run Keytool utility to
get the SHA1 fingerprint. While running Keytool utility, you need to provide keystore
password. Default development keytool password is “android”. keytool -exportcert -alias
androiddebugkey -keystore ~/.android/[Link] -list -v
[Link] 589
• Now, add Package name and SHA-1 fingerprint in input fields on credentials page. Finally,
click on create button to create API key.
[Link] 590
• This will create API key for Android. We will use the this API key to integrate Android
application with Google Drive.
[Link] 591
Enable Google Drive API
We need to enable Google Drive Api to access files stored on Google Drive from Android
application. To enable Google Drive API, follow below steps:
• Go to your Google Developer console Dashboard and click on Enable APIs get credentials
like keys then you will see popular Google APIs.
[Link] 592
• Click on Drive API link to open overview page of Google Drive API.
[Link] 593
• Click on the Enable button to enable Google drive API. It allows client access to Google
Drive.
App needs Internet access Google Drive files. Use the following code to set up Internet
[Link] 594
permissions in [Link] file :
We will use Google play services API which includes the Google Drive Android API. So, we
need to setup Google play services SDK in Android Application. Open your [Link](app
module) file and add Google play services SDK as a dependencies.
dependencies {
....
compile '[Link]:play-services:<latest_version>'
....
}
To use Google API in Android application, we need to add API key and version of the Google Play
Service in the [Link] file. Add the correct metadata tags inside the tag of the
[Link] file.
We need to authenticate and connect Google Drive Android API with Android application.
Authorization of Google Drive Android API is handled by the GoogleApiClient. We will use
GoogleApiClient within onResume() method.
/**
* Called when the activity will start interacting with the user.
* At this point your activity is at the top of the activity stack,
* with user input going to it.
*/
@Override
protected void onResume() {
[Link]();
if (mGoogleApiClient == null) {
/**
* Create the API client and bind it to an instance variable.
* We use this instance as the callback for connection and connection failures.
* Since no account name is passed, the user is prompted to choose.
*/
mGoogleApiClient = new [Link](this)
.addApi([Link])
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
[Link]();
}
[Link] 595
Disconnect Google Deive Android API
When activity stops, we will disconnected Google Drive Android API connection with Android
application by calling disconnect() method inside activity’s onStop() method.
@Override
protected void onStop() {
[Link]();
if (mGoogleApiClient != null) {
We will implement Connection Callbacks and Connection Failed Listener of Google API client in
[Link] file to know status about connection of Google API client. These listeners provide
onConnected(), onConnectionFailed(), onConnectionSuspended() method to handle the
connection issues between app and Drive.
If user has authorized the application, the onConnected() method is invoked. If user has not
authorized application, onConnectionFailed() method is invoked and a dialog is displayed to user
that your app is not authorized to access Google Drive. In case connection is suspended,
onConnectionSuspended() method is called.
@Override
public void onConnectionFailed(ConnectionResult result) {
if (![Link]()) {
/**
* The failure has a resolution. Resolve it.
* Called typically when the app is not yet authorized, and an authorization
* dialog is displayed to the user.
*/
try {
[Link](this, REQUEST_CODE_RESOLUTION);
[Link] 596
} catch (SendIntentException e) {
/**
* It invoked when Google API client connected
* @param connectionHint
*/
@Override
public void onConnected(Bundle connectionHint) {
/**
* It invoked when connection suspended
* @param cause
*/
@Override
public void onConnectionSuspended(int cause) {
We will add a file on Google Drive. We will use the createFile() method of a Drive object to create
file programmatically on Google Drive. In this example we are adding a new text file in the user’s
root folder. When a file is added, we need to specify the initial set of metadata, file contents, and
the parent folder.
We need to create a CreateMyFile() callback method and within this method, use the Drive object
to retrieve a DriveContents resource. Then we pass the API client to the Drive object and call the
driveContentsCallback callback method to handle result of DriveContents.
A DriveContents resource contains a temporary copy of the file's binary stream which is only
available to the application.
We will create a result handler of DriveContents. Within this method, we call the
[Link] 597
CreateFileOnGoogleDrive() method and pass the result of DriveContentsResult:
/**
* This is the Result result handler of Drive contents.
* This callback method calls the CreateFileOnGoogleDrive() method.
*/
final ResultCallback<DriveContentsResult> driveContentsCallback =
new ResultCallback<DriveContentsResult>() {
@Override
public void onResult(DriveContentsResult result) {
if ([Link]().isSuccess()) {
if (fileOperation == true){
CreateFileOnGoogleDrive(result);
}
}
}
};
We use the following code to create a new text file in the user's root folder:
/**
* Create a file in the root folder using a MetadataChangeSet object.
* @param result
*/
public void CreateFileOnGoogleDrive(DriveContentsResult result){
[Link] 598
.createFile(mGoogleApiClient, changeSet, driveContents)
setResultCallback(fileCallback);
}
}.start();
}
/**
* Handle result of Created file
*/
final private ResultCallback<[Link]> fileCallback = new
ResultCallback<[Link]>() {
@Override
public void onResult([Link] result) {
if ([Link]().isSuccess()) {
[Link](getApplicationContext(), "file created: "+
[Link]().getDriveId(), Toast.LENGTH_LONG).show();
}
return;
}
};
[Link] 599
Chapter 118: Google Maps API v2 for Android
Parameters
Parameter Details
MarkerOptions is the builder class of a Marker, and is used to add one marker
MarkerOptions
to a map.
Remarks
Requirements
Examples
Default Google Map Activity
This Activity code will provide basic functionality for including a Google Map using a
SupportMapFragment.
Activities now have to implement the OnMapReadyCallBack interface, which comes with a
onMapReady() method override that is executed everytime we run SupportMapFragment.
getMapAsync(OnMapReadyCallback); and the call is successfully completed.
Maps use Markers , Polygons and PolyLines to show interactive information to the user.
[Link]:
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].activity_maps);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById([Link]);
[Link](this);
[Link] 600
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
Notice that the code above inflates a layout, which has a SupportMapFragment nested inside the
container Layout, defined with an ID of [Link]. The layout file is shown below:
activity_maps.xml
<fragment xmlns:android="[Link]
xmlns:tools="[Link]
xmlns:map="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/map"
tools:context="[Link]"
android:name="[Link]"/>
</LinearLayout>
Map Style
Google Maps come with a set of different styles to be applied, using this code :
Normal
[Link](GoogleMap.MAP_TYPE_NORMAL);
Typical road map. Roads, some man-made features, and important natural features such as rivers
are shown. Road and feature labels are also visible.
[Link] 601
Hybrid
[Link](GoogleMap.MAP_TYPE_HYBRID);
Satellite photograph data with road maps added. Road and feature labels are also visible.
[Link] 602
Satellite
[Link](GoogleMap.MAP_TYPE_SATELLITE);
Satellite photograph data. Road and feature labels are not visible.
[Link] 603
Terrain
[Link](GoogleMap.MAP_TYPE_TERRAIN);
Topographic data. The map includes colors, contour lines and labels, and perspective shading.
Some roads and labels are also visible.
[Link] 604
None
[Link](GoogleMap.MAP_TYPE_NONE);
No tiles. The map will be rendered as an empty grid with no tiles loaded.
[Link] 605
OTHER STYLE OPTIONS
Indoor Maps
At high zoom levels, the map will show floor plans for indoor spaces. These are called indoor
maps, and are displayed only for the 'normal' and 'satellite' map types.
[Link](true).
[Link](false).
mMap = googleMap;
try {
// Customise the styling of the base map using a JSON object defined
// in a raw resource file.
boolean success = [Link](
[Link](
[Link], [Link].style_json));
[Link] 606
if (!success) {
Log.e(TAG, "Style parsing failed.");
}
} catch ([Link] e) {
Log.e(TAG, "Can't find style.", e);
}
under res folder create a folder name raw and add the styles json file. Sample [Link] file
[
{
"featureType": "all",
"elementType": "geometry",
"stylers": [
{
"color": "#242f3e"
}
]
},
{
"featureType": "all",
"elementType": "[Link]",
"stylers": [
{
"lightness": -80
}
]
},
{
"featureType": "administrative",
"elementType": "[Link]",
"stylers": [
{
"color": "#746855"
}
]
},
{
"featureType": "[Link]",
"elementType": "[Link]",
"stylers": [
{
"color": "#d59563"
}
]
},
{
"featureType": "poi",
"elementType": "[Link]",
"stylers": [
{
"color": "#d59563"
}
]
},
{
"featureType": "[Link]",
"elementType": "geometry",
"stylers": [
{
[Link] 607
"color": "#263c3f"
}
]
},
{
"featureType": "[Link]",
"elementType": "[Link]",
"stylers": [
{
"color": "#6b9a76"
}
]
},
{
"featureType": "road",
"elementType": "[Link]",
"stylers": [
{
"color": "#2b3544"
}
]
},
{
"featureType": "road",
"elementType": "[Link]",
"stylers": [
{
"color": "#9ca5b3"
}
]
},
{
"featureType": "[Link]",
"elementType": "[Link]",
"stylers": [
{
"color": "#38414e"
}
]
},
{
"featureType": "[Link]",
"elementType": "[Link]",
"stylers": [
{
"color": "#212a37"
}
]
},
{
"featureType": "[Link]",
"elementType": "[Link]",
"stylers": [
{
"color": "#746855"
}
]
},
{
"featureType": "[Link]",
"elementType": "[Link]",
[Link] 608
"stylers": [
{
"color": "#1f2835"
}
]
},
{
"featureType": "[Link]",
"elementType": "[Link]",
"stylers": [
{
"color": "#f3d19c"
}
]
},
{
"featureType": "[Link]",
"elementType": "[Link]",
"stylers": [
{
"color": "#38414e"
}
]
},
{
"featureType": "[Link]",
"elementType": "[Link]",
"stylers": [
{
"color": "#212a37"
}
]
},
{
"featureType": "transit",
"elementType": "geometry",
"stylers": [
{
"color": "#2f3948"
}
]
},
{
"featureType": "[Link]",
"elementType": "[Link]",
"stylers": [
{
"color": "#d59563"
}
]
},
{
"featureType": "water",
"elementType": "geometry",
"stylers": [
{
"color": "#17263c"
}
]
},
{
[Link] 609
"featureType": "water",
"elementType": "[Link]",
"stylers": [
{
"color": "#515c6d"
}
]
},
{
"featureType": "water",
"elementType": "[Link]",
"stylers": [
{
"lightness": -20
}
]
}
]
[Link] 610
[Link] 611
Objects, we can do it this way.
Here is a method that would take a list of MyLocation Objects and place a Marker for each one:
Note: For the purpose of this example, mMap is a class member variable of the Activity, where we've
assigned it to the map reference received in the onMapReady() override.
It is possible to treat a GoogleMap as an Android view if we make use of the provided MapView
class. Its usage is very similar to MapFragment.
<[Link]
xmlns:android="[Link]
xmlns:map="[Link]
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
<!--
map:mapType="0" Specifies a change to the initial map type
map:zOrderOnTop="true" Control whether the map view's surface is placed on top of its
window
map:useVieLifecycle="true" When using a MapFragment, this flag specifies whether the
lifecycle of the map should be tied to the fragment's view or the fragment itself
map:uiCompass="true" Enables or disables the compass
map:uiRotateGestures="true" Sets the preference for whether rotate gestures should be
enabled or disabled
map:uiScrollGestures="true" Sets the preference for whether scroll gestures should be
enabled or disabled
map:uiTiltGestures="true" Sets the preference for whether tilt gestures should be enabled
or disabled
map:uiZoomGestures="true" Sets the preference for whether zoom gestures should be enabled
or disabled
map:uiZoomControls="true" Enables or disables the zoom controls
[Link] 612
map:liteMode="true" Specifies whether the map should be created in lite mode
map:uiMapToolbar="true" Specifies whether the mapToolbar should be enabled
map:ambientEnabled="true" Specifies whether ambient-mode styling should be enabled
map:cameraMinZoomPreference="0.0" Specifies a preferred lower bound for camera zoom
map:cameraMaxZoomPreference="1.0" Specifies a preferred upper bound for camera zoom -->
/>
/**
* This shows how to create a simple activity with a raw MapView and add a marker to it. This
* requires forwarding all the important lifecycle methods onto MapView.
*/
public class RawMapViewDemoActivity extends AppCompatActivity implements OnMapReadyCallback {
@Override
protected void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link].raw_mapview_demo);
[Link](this);
}
@Override
protected void onResume() {
[Link]();
[Link]();
}
@Override
public void onMapReady(GoogleMap map) {
[Link](new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
@Override
protected void onPause() {
[Link]();
[Link]();
}
@Override
protected void onDestroy() {
[Link]();
[Link]();
}
@Override
public void onLowMemory() {
[Link]();
[Link]();
}
@Override
public void onSaveInstanceState(Bundle outState) {
[Link](outState);
[Link] 613
[Link](outState);
}
}
Here is a full Activity class that places a Marker at the current location, and also moves the
camera to the current position.
GoogleMap mGoogleMap;
SupportMapFragment mapFrag;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
@Override
protected void onCreate(Bundle savedInstanceState)
{
[Link](savedInstanceState);
setContentView([Link].activity_main);
@Override
public void onPause() {
[Link]();
@Override
public void onMapReady(GoogleMap googleMap)
{
mGoogleMap=googleMap;
[Link](GoogleMap.MAP_TYPE_HYBRID);
[Link] 614
//Initialize Google Play Services
if ([Link].SDK_INT >= Build.VERSION_CODES.M) {
if ([Link](this,
[Link].ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Location Permission already granted
buildGoogleApiClient();
[Link](true);
} else {
//Request Location Permission
checkLocationPermission();
}
}
else {
buildGoogleApiClient();
[Link](true);
}
}
@Override
public void onConnected(Bundle bundle) {
mLocationRequest = new LocationRequest();
[Link](1000);
[Link](1000);
[Link](LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if ([Link](this,
[Link].ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
[Link](mGoogleApiClient,
mLocationRequest, this);
}
}
@Override
public void onConnectionSuspended(int i) {}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {}
@Override
public void onLocationChanged(Location location)
{
mLastLocation = location;
if (mCurrLocationMarker != null) {
[Link]();
}
[Link] 615
[Link]([Link](BitmapDescriptorFactory.HUE_M
AGENTA));
mCurrLocationMarker = [Link](markerOptions);
} else {
// No explanation needed, we can request the permission.
[Link](this,
new String[]{[Link].ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION );
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if ([Link] > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
[Link] 616
// permission was granted, yay! Do the
// location-related task you need to do.
if ([Link](this,
[Link].ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if (mGoogleApiClient == null) {
buildGoogleApiClient();
}
[Link](true);
}
} else {
activity_main.xml:
<fragment xmlns:android="[Link]
xmlns:tools="[Link]
xmlns:map="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/map"
tools:context="[Link]"
android:name="[Link]"/>
</LinearLayout>
Result:
Show explanation if needed on Marshmallow and Nougat using an AlertDialog (this case happens
when the user had previously denied a permission request, or had granted the permission and
then later revoked it in the settings):
[Link] 617
Prompt the user for Location permission on Marshmallow and Nougat by calling
[Link]():
[Link] 618
Move camera to current location and place Marker when the Location permission is granted:
[Link] 619
Obtaining the SH1-Fingerprint of your certificate keystore file
In order to obtain a Google Maps API key for your certificate, you must provide the API console
with the SH1-fingerprint of your debug/release keystore.
You can obtain the keystore by using the JDK's keytool program as described here in the docs.
Another approach is to obtain the fingerprint programmatically by running this snippet with your
app signed with the debug/release certificate and printing the hash to the log.
PackageInfo info;
try {
info = getPackageManager().getPackageInfo("[Link]",
PackageManager.GET_SIGNATURES);
for (Signature signature : [Link]) {
MessageDigest md;
md = [Link]("SHA");
[Link]([Link]());
String hash= new String([Link]([Link](), 0));
Log.e("hash", hash);
}
} catch (NameNotFoundException e1) {
Log.e("name not found", [Link]());
} catch (NoSuchAlgorithmException e) {
Log.e("no such an algorithm", [Link]());
[Link] 620
} catch (Exception e) {
Log.e("exception", [Link]());
}
Do not launch Google Maps when the map is clicked (lite mode)
When a Google Map is displayed in lite mode clicking on a map will open the Google Maps
application. To disable this functionality you must call setClickable(false) on the MapView, e.g.:
UISettings
[Link](GoogleMap.MAP_TYPE_HYBRID);
[Link]().setMapToolbarEnabled(true);
[Link]().setZoomControlsEnabled(true);
[Link]().setCompassEnabled(true);
Result:
[Link] 621
Get debug SHA1 fingerprint
[Link] 622
InfoWindow Click Listener
Here is an example of how to define a different action for each Marker's InfoWindow click event.
[Link] 623
Use a HashMap in which the marker ID is the key, and the value is the corresponding action it
should take when the InfoWindow is clicked.
Then, use a OnInfoWindowClickListener to handle the event of a user clicking the InfoWindow, and
use the HashMap to determine which action to take.
In this simple example we will open up a different Activity based on which Marker's InfoWindow
was clicked.
Then, each time you add a Marker, make an entry in the HashMap with the Marker ID and the
action it should take when it's InfoWindow is clicked.
For example, adding two Markers and defining an action to take for each:
In the InfoWindow click listener, get the action from the HashMap, and open up the corresponding
Activity based on the action of the Marker:
[Link](new [Link]() {
@Override
public void onInfoWindowClick(Marker marker) {
if ([Link]("action_one")) {
Intent i = new Intent([Link], [Link]);
startActivity(i);
} else if ([Link]("action_two")) {
Intent i = new Intent([Link], [Link]);
startActivity(i);
}
}
});
Change Offset
[Link] 624
By changing mappoint x and y values as you need you can change offset possition of google
map,by default it will be in the center of the map view. Call below method where you want to
change it! Better to use it inside your onLocationChanged like
changeOffsetCenter([Link](),[Link]());