100% found this document useful (6 votes)
5K views1,595 pages

Android

Basic Android ebook

Uploaded by

Tuyen Do Van
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (6 votes)
5K views1,595 pages

Android

Basic Android ebook

Uploaded by

Tuyen Do Van
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1595

Android

#android
Table of Contents
About 1

Chapter 1: Getting started with Android 2

Remarks 2

Versions 2

Examples 3

Setting up Android Studio 3

Configure Android Studio 4

Change/add theme 4

Compiling Apps 4

Creating a New Project 4

Set up Android Studio 4

Configure Your Project 4

Basic Configuration 4

Select Form Factors and API Level 6

Add an activity 9

Inspecting the Project 10

Running the Application 14

Setting up an Android device 14

Running from Android Studio 14

APK file location 15

Android programming without an IDE 15

Requirements and assumptions 16

Setting up the Android SDK 16

Coding the app 16

Building the code 17

Installing and running 19

Declaring a resource 19

Uninstalling the app 20

See also 20
Application Fundamentals 20

App Components 20

Context 21

Setting up an AVD (Android Virtual Device) 22

Chapter 2: 9-Patch Images 28

Remarks 28

Examples 28

Basic rounded corners 28

Basic spinner 29

Optional padding lines 29

Chapter 3: Accessing SQLite databases using the ContentValues class 31

Examples 31

Inserting and updating rows in a SQLite database 31

Inserting data 31

Updating data 31

Chapter 4: Accounts and AccountManager 32

Examples 32

Understanding custom accounts/authentication 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

Exclude an activity from back-stack history 38

Android Activity LifeCycle Explained 39

Activity launchMode 42

Standard: 43

SingleTop: 43

SingleTask: 43

SingleInstance: 43

Presenting UI with setContentView 43

Examples 44

Set content from resource file: 44

Set content to an explicit view: 44

Clear your current Activity stack and launch a new Activity 45

End Application with exclude from Recents 45

Up Navigation for Activities 46

Chapter 7: Activity Recognition 48

Introduction 48

Examples 48

Google Play ActivityRecognitionAPI 48

PathSense Activity Recognition 50

Chapter 8: ADB (Android Debug Bridge) 53

Introduction 53

Remarks 53

Examples 53

Print verbose list of connected devices 53

Example Output 53

Read device information 54

Full Example Output 54

Connect ADB to a device via WiFi 57

Not rooted device 57

Rooted device 58
When you have a rooted device but don't have access to a USB cable 58

Avoid timeout 59

Pull (push) files from (to) the device 59

Reboot device 59

Turn on/off Wifi 60

View available devices 60

Connect device by IP 60

Start/stop adb 61

View logcat 61

Direct ADB command to specific device in a multi-device setting 62

Taking a screenshot and video (for kitkat only) from a device display 63

Screen shot: Option 1 (pure adb) 63

Screen shot:Option 2 (faster) 63

Video 64

Clear application data 64

Sending broadcast 64

Install and run an application 65

Backup 66

Install ADB on Linux system 66

List all permissions that require runtime grant from users on Android 6.0 67

View an app's internal data (data/data/) on a device 67

View activity stack 67

View and pull cache files of an app 68

Chapter 9: adb shell 69

Introduction 69

Syntax 69

Parameters 69

Examples 69

Send text, key pressed and touch events to Android Device via ADB 69

List packages 71

Granting & revoking API 23+ permissions 71

Print application data 72


Recording the display 72

Changing file permissions using chmod command 73

Set Date/Time via adb 74

Open Developer Options 75

Generating a "Boot Complete" broadcast 75

View external/secondary storage content 75

kill a process inside an Android device 75

Chapter 10: Adding a FuseView to an Android Project 77

Introduction 77

Examples 77

hikr app, just another android.view.View 77

Chapter 11: AdMob 86

Syntax 86

Parameters 86

Remarks 86

Examples 86

Implementing 86

Build.gradle on app level 86

Manifest 86

XML 87

Java 87

Chapter 12: AIDL 89

Introduction 89

Examples 89

AIDL Service 89

Chapter 13: AlarmManager 91

Examples 91

Run an intent at a later time 91

How to Cancel an Alarm 91

Creating exact alarms on all Android versions 92

API23+ Doze mode interferes with AlarmManager 92


Chapter 14: Android Architecture Components 94

Introduction 94

Examples 94

Add Architecture Components 94

Using Lifecycle in AppCompatActivity 94

ViewModel with LiveData transformations 95

Room peristence 96

Custom LiveData 98

Custom Lifecycle-aware component 99

Chapter 15: Android Authenticator 101

Examples 101

Basic Account Authenticator Service 101

Chapter 16: Android game development 104

Introduction 104

Remarks 104

Examples 104

Game using Canvas and SurfaceView 104

Chapter 17: Android Java Native Interface (JNI) 111

Introduction 111

Examples 111

How to call functions in a native library via the JNI interface 111

How to call a Java method from native code 112

Utility method in JNI layer 113

Chapter 18: Android Kernel Optimization 114

Examples 114

Low RAM Configuration 114

How to add a CPU Governor 114

I/O Schedulers 116

Chapter 19: Android NDK 118

Examples 118

Building native executables for Android 118

How to clean the build 119


How to use a makefile other than Android.mk 119

How to log in ndk 119

Chapter 20: Android Paypal Gateway Integration 121

Remarks 121

Examples 121

Setup paypal in your android code 121

Chapter 21: Android Places API 123

Examples 123

Place Picker Usage Example 123

Getting Current Places by Using Places API 124

Place Autocomplete Integration 125

Adding more than one google auto complete activity. 126

Setting place type filters for PlaceAutocomplete 127

Chapter 22: Android programming with Kotlin 129

Introduction 129

Remarks 129

Examples 129

Installing the Kotlin plugin 129

Configuring an existing Gradle project with Kotlin 130

Creating a new Kotlin Activity 132

Converting existing Java code to Kotlin 134

Starting a new Activity 134

Chapter 23: Android Sound and Media 135

Examples 135

How to pick image and video for api >19 135

Play sounds via SoundPool 136

Chapter 24: Android Studio 138

Examples 138

Filter logs from UI 138

Create filters configuration 139

Custom colors of logcat message based on message importance 141

Enable/Disable blank line copy 142


Android Studio useful shortcuts 143

Android Studio Improve performance tip 145

Setup Android Studio 145

View And Add Shortcuts in Android Studio 146

Gradle build project takes forever 147

Create assets folder 148

Chapter 25: Android Things 150

Examples 150

Controlling a Servo Motor 150

Chapter 26: Android Versions 152

Remarks 152

Examples 153

Checking the Android Version on device at runtime 153

Chapter 27: Android Vk Sdk 155

Examples 155

Initialization and login 155

Chapter 28: Android-x86 in VirtualBox 157

Introduction 157

Examples 157

Virtual Machine setup 157

Virtual hard drive Setup for SDCARD Support 157

Installation in partition 160

Chapter 29: Animated AlertDialog Box 164

Introduction 164

Examples 164

Put Below code for Animated dialog... 164

Chapter 30: Animators 167

Examples 167

Shake animation of an ImageView 167

Fade in/out animation 168

TransitionDrawable animation 168

ValueAnimator 169
ObjectAnimator 170

ViewPropertyAnimator 171

Expand and Collapse animation of View 171

Chapter 31: Annotation Processor 173

Introduction 173

Examples 173

@NonNull Annotation 173

Types of Annotations 173

Creating and Using Custom Annotations 174

Chapter 32: AsyncTask 176

Parameters 176

Examples 176

Basic Usage 176

Example 176

Usage: 177

Note 177

Canceling AsyncTask 178

Note 179

Publishing progress 179

Download Image using AsyncTask in Android 179

Understanding Android AsyncTask 179

Downloading image using Android AsyncTask 180

Pass Activity as WeakReference to avoid memory leaks 183

Order of execution 184

AsyncTask: Serial Execution and Parallel Execution of Task 184

THREAD_POOL_EXECUTOR 185

SERIAL_EXECUTOR 185

Task Executed in thread pool(1) 186

Chapter 33: AudioManager 188

Examples 188

Requesting Transient Audio Focus 188

Requesting Audio Focus 188


Chapter 34: AudioTrack 189

Examples 189

Generate tone of a specific frequency 189

Chapter 35: AutoCompleteTextView 190

Remarks 190

Examples 190

Simple, hard-coded AutoCompleteTextView 190

AutoComplete with CustomAdapter, ClickListener and Filter 190

Main layout : activity_main.xml 190

Row layout row.xml 191

strings.xml 191

MainActivity.java 191

Model class : People.java 192

Adapter class : PeopleAdapter.java 193

Chapter 36: Autosizing TextViews 195

Introduction 195

Examples 195

Granularity 195

Preset Sizes 195

Chapter 37: Barcode and QR code reading 197

Remarks 197

Examples 197

Using QRCodeReaderView (based on Zxing) 197

Adding the library to your project 197

First use 197

Chapter 38: Bitmap Cache 199

Introduction 199

Syntax 199

Parameters 199

Examples 199

Bitmap Cache Using LRU Cache 199


Chapter 39: Bluetooth and Bluetooth LE API 201

Remarks 201

Examples 201

Permissions 201

Check if bluetooth is enabled 201

Make device discoverable 202

Find nearby bluetooth devices 202

Connect to Bluetooth device 203

Find nearby Bluetooth Low Energy devices 204

Chapter 40: Bluetooth Low Energy 210

Introduction 210

Examples 210

Finding BLE Devices 210

Connecting to a GATT Server 211

Writing and Reading from Characteristics 211

Subscribing to Notifications from the Gatt Server 212

Advertising a BLE Device 213

Using a Gatt Server 213

Chapter 41: Bottom Sheets 216

Introduction 216

Remarks 216

Examples 216

BottomSheetBehavior like Google maps 216

Quick Setup 223

Persistent Bottom Sheets 223

Modal bottom sheets with BottomSheetDialogFragment 225

Modal bottom sheets with BottomSheetDialog 225

Open BottomSheet DialogFragment in Expanded mode by default. 225

Chapter 42: BottomNavigationView 227

Introduction 227

Remarks 227

Links: 227
Examples 227

Basic implemetation 227

Customization of BottomNavigationView 228

Handling Enabled / Disabled states 229

Allowing more than 3 menus 229

Chapter 43: BroadcastReceiver 231

Introduction 231

Examples 231

Introduction to Broadcast receiver 231

BroadcastReceiver Basics 232

Using LocalBroadcastManager 232

Bluetooth Broadcast receiver 233

add permission in your manifest file 233

In your Fragment(or Activity) 233

Register broadcast 233

Unregister broadcast 234

Enabling and disabling a Broadcast Receiver programmatically 234

BroadcastReceiver to handle BOOT_COMPLETED events 234

Example of a LocalBroadcastManager 235

Communicate two activities through custom Broadcast receiver 236

Sticky Broadcast 237

Using ordered broadcasts 237

Android stopped state 238

Chapter 44: Building Backwards Compatible Apps 239

Examples 239

How to handle deprecated API 239

Easier alternative: Use the Support Library 240

Chapter 45: ButterKnife 242

Introduction 242

Remarks 242

ButterKnife 242

Examples 242
Configuring ButterKnife in your project 242

Binding Views using ButterKnife 245

Binding Views 245

Binding Views in Activity 245

Binding Views in Fragments 245

Binding Views in Dialogs 245

Binding Views in ViewHolder 246

Binding Resources 246

Binding View Lists 246

Optional Bindings 247

Binding Listeners using ButterKnife 247

Unbinding views in ButterKnife 248

Android Studio ButterKnife Plugin 249

Chapter 46: Button 250

Syntax 250

Examples 250

inline onClickListener 250

Using the layout to define a click action 250

Using the same click event for one or more Views in the XML 251

Listening to the long click events 251

Defining external Listener 251

When should I use it 252

Custom Click Listener to prevent multiple fast clicks 252

Customizing Button style 253

Chapter 47: Callback URL 258

Examples 258

Callback URL example with Instagram OAuth 258

Chapter 48: Camera 2 API 259

Parameters 259

Remarks 259

Examples 260
Preview the main camera in a TextureView 260

Chapter 49: Camera and Gallery 269

Examples 269

Taking full-sized photo from camera 269

AndroidManifest.xml 269

Take photo 271

How to start camera or gallery and save camera result to storage 274

Set camera resolution 277

Decode bitmap correctly rotated from the uri fetched with the intent 277

Chapter 50: Canvas drawing using SurfaceView 281

Remarks 281

Examples 281

SurfaceView with drawing thread 281

Chapter 51: Capturing Screenshots 287

Examples 287

Capturing Screenshot via Android Studio 287

Capturing Screenshot via Android Device Monitor 287

Capturing Screenshot via ADB 288

Capturing Screenshot via ADB and saving directly in your PC 288

Taking a screenshot of a particular view 288

Chapter 52: CardView 290

Introduction 290

Parameters 290

Remarks 291

Official Documentation: 291

Examples 291

Getting Started with CardView 291

Customizing the CardView 292

Adding Ripple animation 293

Using Images as Background in CardView (Pre-Lollipop device issues) 293

Animate CardView background color with TransitionDrawable 295

Chapter 53: Check Data Connection 297


Examples 297

Check data connection 297

Check connection using ConnectivityManager 297

Use network intents to perform tasks while data is allowed 297

Chapter 54: Check Internet Connectivity 298

Introduction 298

Syntax 298

Parameters 298

Remarks 298

Examples 298

Check if device has internet connectivity 298

How to check network strength in android? 299

How to check network strength 299

Chapter 55: CleverTap 303

Introduction 303

Remarks 303

Examples 303

Get an instance of the SDK to record events 303

Setting the debug level 303

Chapter 56: Colors 304

Examples 304

Color Manipulation 304

Chapter 57: ConstraintLayout 305

Introduction 305

Syntax 305

Parameters 305

Remarks 306

Fore More About Constraint Layout: 306

Examples 306

Adding ConstraintLayout to your project 306

Chains 307
Chapter 58: ConstraintSet 309

Introduction 309

Examples 309

ConstraintSet with ContraintLayout Programmatically 309

Chapter 59: ContentProvider 310

Remarks 310

Examples 310

Implementing a basic content provider class 310

Chapter 60: Context 314

Introduction 314

Syntax 314

Remarks 314

Examples 314

Basic Examples 314

Chapter 61: Convert vietnamese string to english string Android 316

Examples 316

example: 316

Chuyn chui Ting Vit thành chui không du 316

Chapter 62: CoordinatorLayout and Behaviors 317

Introduction 317

Remarks 317

Examples 317

Creating a simple Behavior 317

Extend the CoordinatorLayout.Behavior 317

Attach a Behavior programmatically 318

Attach a Behavior in XML 318

Attach a Behavior automatically 318

Using the SwipeDismissBehavior 318

Create dependencies between Views 319

Chapter 63: Count Down Timer 321

Parameters 321
Remarks 321

Examples 321

Creating a simple countdown timer 321

A More Complex Example 321

Chapter 64: Crash Reporting Tools 324

Remarks 324

Examples 324

Fabric - Crashlytics 324

How to Configure Fabric-Crashlytics 324

Using the Fabric IDE plugin 325

Crash Reporting with ACRA 329

Force a Test Crash With Fabric 330

Capture crashes using Sherlock 331

Chapter 65: Create Android Custom ROMs 333

Examples 333

Making Your Machine Ready for Building! 333

Installing Java 333

Installing Additional Dependencies 333

Preparing the system for development 333

Chapter 66: Create Singleton Class for Toast Message 335

Introduction 335

Syntax 335

Parameters 335

Remarks 335

Examples 336

Create own singleton class for toast massages 336

Chapter 67: Creating Custom Views 338

Examples 338

Creating Custom Views 338

Adding attributes to views 340

Creating a compound view 342


CustomView performance tips 346

Compound view for SVG/VectorDrawable as drawableRight 347

Module Name : custom_edit_drawable (short name for prefix- c_d_e) 347

build.gradle 347

Layout file : c_e_d_compound_view.xml 347

Custom Attributes : attrs.xml 348

Code : EditTextWithDrawable.java 348

Example : How to use above view 349

Layout : activity_main.xml 349

Activity : MainActivity.java 349

Responding to Touch Events 350

Chapter 68: Creating Overlay (always-on-top) Windows 351

Examples 351

Popup overlay 351

Assigning a view to the WindowManager 351

Granting SYSTEM_ALERT_WINDOW Permission on android 6.0 and above 351

Chapter 69: Creating Splash screen 353

Remarks 353

Examples 353

A basic splash screen 353

Splash screen with animation 355

Step 1: Create an animation 355

Step 2: Create an activity 355

Step 3: Replace the default launcher 356

Chapter 70: Creating your own libraries for Android applications 358

Examples 358

Creating library project 358

Using library in project as a module 359

Create a library available on Jitpack.io 359

Chapter 71: Custom Fonts 361

Examples 361

Putting a custom font in your app 361


Initializing a font 361

Using a custom font in a TextView 361

Apply font on TextView by xml (Not required Java code) 361

Custom font in canvas text 362

Efficient Typeface loading 363

Custom font to whole activity 363

Working with fonts in Android O 364

Chapter 72: Dagger 2 366

Syntax 366

Remarks 366

Examples 366

Component setup for Application and Activity injection 366

Custom Scopes 368

Constructor Injection 368

Using @Subcomponent instead of @Component(dependencies={...}) 369

How to add Dagger 2 in build.gradle 369

Creating a component from multiple modules 370

Chapter 73: Data Binding Library 373

Remarks 373

Examples 373

Basic text field binding 373

Binding with an accessor method 374

Referencing classes 375

Databinding in Fragment 376

Built-in two-way Data Binding 377

Data binding in RecyclerView Adapter 378

Data model 378

XML Layout 378

Adapter class 378

Click listener with Binding 379

Custom event using lambda expression 380

Default value in Data Binding 382


DataBinding with custom variables(int,boolean) 383

Databinding in Dialog 383

Pass widget as reference in BindingAdapter 383

Chapter 74: Data Encryption/Decryption 385

Introduction 385

Examples 385

AES encryption of data using password in a secure way 385

Chapter 75: Data Synchronization with Sync Adapter 387

Examples 387

Dummy Sync Adapter with Stub Provider 387

Chapter 76: Date and Time Pickers 393

Examples 393

Material DatePicker 393

Date Picker Dialog 395

Chapter 77: DayNight Theme (AppCompat v23.2 / API 14+) 397

Examples 397

Adding the DayNight theme to an app 397

Chapter 78: Define step value (increment) for custom RangeSeekBar 399

Introduction 399

Remarks 399

Examples 400

Define a step value of 7 400

Chapter 79: Design Patterns 401

Introduction 401

Examples 401

Singleton Class Example 401

Observer pattern 402

Implementing the observer pattern 402

Chapter 80: Detect Shake Event in Android 403

Examples 403

Shake Detector in Android Example 403


Using Seismic shake detection 404

Installation 404

Chapter 81: Device Display Metrics 405

Examples 405

Get the screens pixel dimensions 405

Get screen density 405

Formula px to dp, dp to px conversation 405

Chapter 82: Dialog 406

Parameters 406

Remarks 406

Examples 406

Alert Dialog 406

A Basic Alert Dialog 407

Date Picker within DialogFragment 407

DatePickerDialog 409

DatePicker 410

Sample use of DatePickerDialog 410

Adding Material Design AlertDialog to your app using Appcompat 411

ListView in AlertDialog 412

Custom Alert Dialog with EditText 412

Fullscreen Custom Dialog with no background and no title 414

Alert Dialog with Multi-line Title 414

Chapter 83: Displaying Google Ads 417

Examples 417

Basic Ad Setup 417

Adding Interstitial Ad 417

Chapter 84: Doze Mode 420

Remarks 420

Examples 422

Exclude app from using doze mode 422

Whitelisting an Android application programmatically 423


Chapter 85: Drawables 424

Examples 424

Tint a drawable 424

Make View with rounded corners 424

Circular View 425

Custom Drawable 426

Chapter 86: EditText 428

Examples 428

Working with EditTexts 428

Customizing the InputType 430

`inputype` attribute 431

Hiding SoftKeyboard 432

Icon or button inside Custom Edit Text and its action and click listeners. 433

Chapter 87: Email Validation 436

Examples 436

Email address validation 436

Email Address validation with using Patterns 436

Chapter 88: Emulator 437

Remarks 437

Examples 437

Taking screenshots 437

Open the AVD Manager 440

Simulate call 441

Resolving Errors while starting emulator 441

Chapter 89: Enhancing Alert Dialogs 443

Introduction 443

Examples 443

Alert dialog containing a clickable link 443

Chapter 90: Enhancing Android Performance Using Icon Fonts 444

Remarks 444

Examples 444

How to integrate Icon fonts 444


TabLayout with icon fonts 447

Chapter 91: Exceptions 449

Examples 449

NetworkOnMainThreadException 449

ActivityNotFoundException 450

OutOfMemoryError 450

DexException 451

UncaughtException 451

Registering own Handler for unexpected exceptions 452

Chapter 92: ExoPlayer 454

Examples 454

Add ExoPlayer to the project 454

Using ExoPlayer 454

Main steps to play video & audio using the standard TrackRenderer implementations 455

Chapter 93: Facebook SDK for Android 456

Syntax 456

Parameters 456

Examples 456

How to add Facebook Login in Android 456

Setting permissions to access data from the Facebook profile 458

Create your own custom button for Facebook login 459

A minimalistic guide to Facebook login/signup implementation 460

Logging out of Facebook 461

Chapter 94: Fast way to setup Retrolambda on an android project. 462

Introduction 462

Examples 462

Setup and example how to use: 462

Chapter 95: Fastjson 464

Introduction 464

Syntax 464

Examples 464

Parsing JSON with Fastjson 464


Convert the data of type Map to JSON String 466

Chapter 96: fastlane 467

Remarks 467

Examples 467

Fastfile to build and upload multiple flavors to Beta by Crashlytics 467

Fastfile lane to build and install all flavors for given build type to a device 469

Chapter 97: FileIO with Android 471

Introduction 471

Remarks 471

Examples 471

Obtaining the working folder 471

Writing raw array of bytes 471

Serializing the object 472

Writing to external storage (SD card) 472

Solving "Invisible MTP files" problem. 473

Working with big files 473

Chapter 98: FileProvider 475

Examples 475

Sharing a file 475

Specify the directories in which the files you want to share are placed 475

Define a FileProvider and link it with the file paths 475

Generate the URI for the file 476

Share the file with other apps 476

Chapter 99: Fingerprint API in android 477

Remarks 477

Examples 477

Adding the Fingerprint Scanner in Android application 477

How to use Android Fingerprint API to save user passwords 478

Chapter 100: Firebase 488

Introduction 488

Remarks 488
Firebase - Extended documentation: 488

Other related topics: 488

Examples 488

Create a Firebase user 488

Sign In Firebase user with email and password 489

Send Firebase password reset email 491

Updating a Firebase users's email 492

Change Password 493

Re-Authenticate Firebase user 494

Firebase Storage Operations 496

Firebase Cloud Messaging 502

Set up Firebase and the FCM SDK 502

Edit your app manifest 502

Add Firebase to Your Android Project 504

Add Firebase to your app 504

Add the SDK 504

Firebase Realtime Database: how to set/get data 505

Demo of FCM based notifications 507

Firebase Sign Out 515

Chapter 101: Firebase App Indexing 516

Remarks 516

Examples 518

Supporting Http URLs 518

Add AppIndexing API 519

Chapter 102: Firebase Cloud Messaging 522

Introduction 522

Examples 522

Set Up a Firebase Cloud Messaging Client App on Android 522

Registration token 522

This code that i have implemnted in my app for pushing image,message and also link for ope 523

Receive Messages 524

Subscribe to a topic 525


Chapter 103: Firebase Crash Reporting 526

Examples 526

How to add Firebase Crash Reporting to your app 526

How to report an error 527

Chapter 104: Firebase Realtime DataBase 528

Remarks 528

Other related topics: 528

Examples 528

Firebase Realtime DataBase event handler 528

Quick setup 529

Designing and understanding how to retrieve realtime data from the Firebase Database 529

Step 1: Create a class named Chat 530

Step 2: Create some JSON data 530

Step 3: Adding the listeners 530

Step 4: Add data to the database 531

Example 532

Denormalization: Flat Database Structure 532

Understanding firebase JSON database 534

Retrieving data from firebase 535

Listening for child updates 537

Retrieving data with pagination 538

Chapter 105: FloatingActionButton 539

Introduction 539

Parameters 539

Remarks 539

Official Documentation: 539

Material Design Specifications: 540

Examples 540

How to add the FAB to the layout 540

Show and Hide FloatingActionButton on Swipe 541

Show and Hide FloatingActionButton on Scroll 543


Setting behaviour of FloatingActionButton 546

Chapter 106: Formatting phone numbers with pattern. 547

Introduction 547

Examples 547

Patterns + 1 (786) 1234 5678 547

Chapter 107: Formatting Strings 548

Examples 548

Format a string resource 548

Format a timestamp to string 548

Formatting data types to String and vise versa 548

Chapter 108: Fragments 549

Introduction 549

Syntax 549

Remarks 550

Constructor 550

Examples 550

The newInstance() pattern 550

Navigation between fragments using backstack and static fabric pattern 551

Pass data from Activity to Fragment using Bundle 553

Sending events back to an activity with callback interface 553

Example 553

Send callback to an activity, when fragment's button clicked 553

Animate the transition between fragments 554

Communication between Fragments 555

Chapter 109: Fresco 560

Introduction 560

Remarks 560

Examples 560

Getting Started with Fresco 560

Using OkHttp 3 with Fresco 561

JPEG Streaming with Fresco using DraweeController 561


Chapter 110: Genymotion for android 563

Introduction 563

Examples 563

Installing Genymotion, the free version 563

Step 1 - installing VirtualBox 563

Step 2 - downloading Genymotion 563

Step 3 - Installing Genymotion 563

Step 4 - Installing Genymotion's emulators 563

Step 5 - Integrating genymotion with Android Studio 563

Step 6 - Running Genymotion from Android Studio 564

Google framework on Genymotion 564

Chapter 111: Gesture Detection 565

Remarks 565

Examples 565

Swipe Detection 565

Basic Gesture Detection 566

Chapter 112: Getting Calculated View Dimensions 568

Remarks 568

Examples 568

Calculating initial View dimensions in an Activity 568

Chapter 113: Getting started with OpenGL ES 2.0+ 570

Introduction 570

Examples 570

Setting up GLSurfaceView and OpenGL ES 2.0+ 570

Compiling and Linking GLSL-ES Shaders from asset file 571

Chapter 114: Getting system font names and using the fonts 573

Introduction 573

Examples 573

Getting system font names 573

Applying a system font to a TextView 573

Chapter 115: Glide 574


Introduction 574

Remarks 574

Examples 574

Add Glide to your project 574

Loading an image 575

ImageView 575

RecyclerView and ListView 575

Glide circle transformation (Load image in a circular ImageView) 576

Default transformations 577

Glide rounded corners image with custom Glide target 577

Preloading images 578

Placeholder and Error handling 579

Load image in a circular ImageView without custom transformations 579

Handling Glide image load failed 580

Chapter 116: Google Awareness APIs 581

Remarks 581

Examples 581

Get current user activity using Snapshot API 581

Get headphone state with Snapshot API 582

Get current location using Snapshot API 582

Get nearby places using Snapshot API 582

Get current weather using Snapshot API 583

Get changes in user activity with Fence API 583

Get changes for location within a certain range using Fence API 584

Chapter 117: Google Drive API 586

Introduction 586

Remarks 586

Examples 586

Integrate Google Drive in Android 586

Create a File on Google Drive 597

Result Handler of DriveContents 597

Create File Programmatically 598


Handle result of Created File 599

Chapter 118: Google Maps API v2 for Android 600

Parameters 600

Remarks 600

Examples 600

Default Google Map Activity 600

Custom Google Map Styles 601

Adding markers to a map 611

MapView: embedding a GoogleMap in an existing layout 612

Show Current Location in a Google Map 614

Obtaining the SH1-Fingerprint of your certificate keystore file 620

Do not launch Google Maps when the map is clicked (lite mode) 621

UISettings 621

Get debug SHA1 fingerprint 622

InfoWindow Click Listener 623

Change Offset 624

Chapter 119: Google Play Store 626

Examples 626

Open Google Play Store Listing for your app 626

Open Google Play Store with the list of all applications from your publisher account 626

Chapter 120: Google signin integration on android 628

Introduction 628

Examples 628

Integration of google Auth in your project. (Get a configuration file) 628

Code Implementation Google SignIn 628

Chapter 121: Gradle for Android 630

Introduction 630

Syntax 630

Remarks 630

Gradle for Android - Extended documentation: 631

Examples 631

A basic build.gradle file 631


DSL (domain-specific language) 631

Plugins 632

Understanding the DSLs in the sample above 632

Dependencies 632

Specifying dependencies specific to different build configurations 633

signingConfig 633

Defining product flavors 634

Adding product flavor-specific dependencies 634

Adding product flavor-specific resources 635

Define and use Build Configuration Fields 636

BuildConfigField 636

ResValue 637

Centralizing dependencies via "dependencies.gradle" file 638

Another approach 639

Directory structure for flavor-specific resources 640

Why are there two build.gradle files in an Android Studio project? 640

Executing a shell script from gradle 641

Debugging your Gradle errors 642

Specifying different application IDs for build types and product flavors 642

Sign APK without exposing keystore password 643

Method A: Configure release signing using a keystore.properties file 644

Method B: By using an environment variable 645

Versioning your builds via "version.properties" file 645

Changing output apk name and add version name: 646

Disable image compression for a smaller APK file size 647

Enable Proguard using gradle 647

Enable experimental NDK plugin support for Gradle and AndroidStudio 647

Configure MyApp/build.gradle file 647

Configure MyApp/app/build.gradle file 648

Test if plugin is enabled 649

Show all gradle project tasks 649


Delete "unaligned" apk automatically 651

Ignoring build variant 651

Seeing dependency tree 652

Use gradle.properties for central versionnumber/buildconfigurations 653

Display signing information 654

Defining build types 654

Chapter 122: GreenDAO 656

Introduction 656

Examples 656

Helper methods for SELECT, INSERT, DELETE, UPDATE queries 656

Creating an Entity with GreenDAO 3.X that has a Composite Primary Key 658

Getting started with GreenDao v3.X 659

Chapter 123: GreenRobot EventBus 662

Syntax 662

Parameters 662

Examples 662

Creating an Event object 662

Receiving Events 662

Sending Events 663

Passing a Simple Event 663

Chapter 124: Gson 665

Introduction 665

Syntax 665

Examples 666

Parsing JSON with Gson 666

Parsing JSON property to enum with Gson 667

Parsing a List with Gson 668

JSON Serialization/Deserialization with AutoValue and Gson 668

Parsing JSON to Generic Class Object with Gson 669

Adding Gson to your project 670

Using Gson to load a JSON file from disk. 671

Adding a custom Converter to Gson 671


Using Gson as serializer with Retrofit 672

Parsing json array to generic class using Gson 672

Custom JSON Deserializer using Gson 673

Using Gson with inheritance 675

Chapter 125: Handler 678

Remarks 678

Examples 678

Using a Handler to execute code after a delayed amount of time 678

HandlerThreads and communication between Threads 678

Creating a Handler for the current Thread 678

Creating a Handler for the main Thread (UI Thread) 678

Send a Runnable from another Thread to the main Thread 679

Creating a Handler for another HandlerThread and sending events to it 679

Stop handler from execution 679

Use Handler to create a Timer (similar to javax.swing.Timer) 680

Chapter 126: Handling Deep Links 682

Introduction 682

Parameters 682

Remarks 682

The <intent-filter> 682

Multiple <data> tags 682

Resources 683

Examples 683

Simple deep link 683

Multiple paths on a single domain 683

Multiple domains and multiple paths 684

Both http and https for the same domain 684

Retrieving query parameters 685

Using pathPrefix 685

Chapter 127: Handling touch and motion events 687

Introduction 687

Parameters 687
Examples 687

Buttons 687

Surface 688

Handling multitouch in a surface 689

Chapter 128: Hardware Button Events/Intents (PTT, LWP, etc.) 691

Introduction 691

Examples 691

Sonim Devices 691

PTT_KEY 691

YELLOW_KEY 691

SOS_KEY 691

GREEN_KEY 691

Registering the buttons 691

RugGear Devices 692

PTT Button 692

Chapter 129: How to store passwords securely 693

Examples 693

Using AES for salted password encryption 693

Chapter 130: How to use SparseArray 697

Introduction 697

Remarks 697

Examples 698

Basic example using SparseArray 698

Chapter 131: HttpURLConnection 700

Syntax 700

Remarks 700

Examples 700

Creating an HttpURLConnection 700

Sending an HTTP GET request 701

Reading the body of an HTTP GET request 702

Use HttpURLConnection for multipart/form-data 702


Sending an HTTP POST request with parameters 705

Upload (POST) file using HttpURLConnection 706

A multi-purpose HttpURLConnection class to handle all types of HTTP requests 707

Usage 710

Chapter 132: Image Compression 711

Examples 711

How to compress image without size change 711

Chapter 133: ImageView 714

Introduction 714

Syntax 714

Parameters 714

Examples 714

Set Image Resource 714

Set alpha 714

ImageView ScaleType - Center 715

ImageView ScaleType - CenterCrop 717

ImageView ScaleType - CenterInside 717

ImageView ScaleType - FitStart and FitEnd 717

ImageView ScaleType - FitCenter 717

ImageView ScaleType - FitXy 717

Set Scale Type 717

Set tint 722

MLRoundedImageView.java 723

Chapter 134: Implicit Intents 725

Syntax 725

Parameters 725

Remarks 725

Examples 725

Implicit and Explicit Intents 725

Implicit Intents 726

Chapter 135: In-app Billing 727

Examples 727
Consumable In-app Purchases 727

Steps in summary: 727

Step 1: 727

Step 2: 727

Step 3: 727

Step 4: 727

Step 5: 728

Step 6: 731

(Third party) In-App v3 Library 732

Chapter 136: Installing apps with ADB 734

Examples 734

Install an app 734

Uninstall an app 734

Install all apk file in directory 734

Chapter 137: Instant Run in Android Studio 735

Remarks 735

Examples 735

Enabling or disabling Instant Run 735

Types of code Swaps in Instant Run 737

Unsupported code changes when using Instant Run 737

Chapter 138: Integrate Google Sign In 739

Syntax 739

Parameters 739

Examples 739

Google Sign In with Helper class 739

Chapter 139: Integrate OpenCV into Android Studio 742

Remarks 742

Examples 742

Instructions 742

Chapter 140: Intent 751

Introduction 751
Syntax 751

Parameters 752

Remarks 752

Caveats of using implicit intent 752

Starting Activity which is a singleTask or singleTop 752

Examples 753

Start an activity 753

Passing data between activities 753

OriginActivity 753

DestinationActivity 754

Sending emails 755

Getting a result from another Activity 756

MainActivity: 756

DetailActivity: 757

A few things you need to be aware of: 757

Open a URL in a browser 758

Opening with the default browser 758

Prompting the user to select a browser 758

Best Practices 759

Clearing an activity stack 759

Intent URI 759

Broadcasting Messages to Other Components 760

CustomTabsIntent for Chrome Custom Tabs 760

Sharing Multiple Files through Intent 761

Starter Pattern 762

Start Unbound Service using an Intent 762

Share intent 763

Start the dialer 763

Open Google map with specified latitude, longitude 764

Passing different data through Intent in Activity 764

Showing a File Chooser and Reading the Result 766


Starting a File Chooser Activity 767

Reading the Result 767

Passing custom object between activities 768

Parcelable 768

Serializable 770

Getting a result from Activity to Fragment 771

Chapter 141: IntentService 773

Syntax 773

Remarks 773

Examples 773

Creating an IntentService 773

Sample Intent Service 773

Basic IntentService Example 774

Chapter 142: Inter-app UI testing with UIAutomator 776

Syntax 776

Remarks 776

Examples 776

Prepare your project and write the first UIAutomator test 776

Writing more complex tests using the UIAutomatorViewer 777

Creating a test suite of UIAutomator tests 778

Chapter 143: Interfaces 779

Examples 779

Custom Listener 779

Define interface 779

Create listener 779

Implement listener 779

Trigger listener 780

Basic Listener 781

Chapter 144: Internationalization and localization (I18N and L10N) 783

Introduction 783

Remarks 783
Examples 783

Planning for localization : enable RTL support in Manifest 783

Planning for localization : Add RTL support in Layouts 784

Planning for localization : Test layouts for RTL 785

Coding for Localization : Creating default strings and resources 785

Coding for localization : Providing alternative strings 785

Coding for localization : Providing alternate layouts 786

Chapter 145: Jackson 788

Introduction 788

Examples 788

Full Data Binding Example 788

Chapter 146: Java on Android 790

Introduction 790

Examples 790

Java 8 features subset with Retrolambda 790

Chapter 147: JCodec 793

Examples 793

Getting Started 793

Getting frame from movie 793

Chapter 148: Jenkins CI setup for Android Projects 794

Examples 794

Step by step approach to set up Jenkins for Android 794

PART I: Initial setup on your machine 794

PART II: Set up Jenkins to build Android Jobs 795

Part III: Create a Jenkins Job for your Android project 795

Chapter 149: Job Scheduling 797

Remarks 797

Examples 797

Basic usage 797

Create a new JobService 797

Add the new JobService to your AndroidManifest.xml 797


Setup and run the job 798

Chapter 150: JSON in Android with org.json 800

Syntax 800

Remarks 800

Examples 800

Parse simple JSON object 800

Creating a simple JSON object 801

Add JSONArray to JSONObject 802

Create a JSON String with null value. 802

Working with null-string when parsing json 802

Using JsonReader to read JSON from a stream 803

Create nested JSON object 805

Handling dynamic key for JSON response 805

Check for the existence of fields on JSON 806

Updating the elements in the JSON 807

Chapter 151: Keyboard 809

Examples 809

Hide keyboard when user taps anywhere else on the screen 809

Register a callback for keyboard open and close 809

Chapter 152: Layouts 811

Introduction 811

Syntax 811

Remarks 811

LayoutParams and Layout_ Attributes 811

Performance impact from using RelativeLayouts near the top of your view hierarchy 812

Examples 813

LinearLayout 813

RelativeLayout 814

Gravity and layout gravity 816

GridLayout 819

Percent Layouts 821

FrameLayout 822
CoordinatorLayout 823

CoordinatorLayout Scrolling Behavior 824

View Weight 826

Creating LinearLayout programmatically 828

LayoutParams 829

Chapter 153: Leakcanary 833

Introduction 833

Remarks 833

Examples 833

Implementing a Leak Canary in Android Application 833

Chapter 154: Library Dagger 2: Dependency Injection in Applications 834

Introduction 834

Remarks 834

Dagger 2 API: 834

Important Links: 834

Examples 835

Create @Module Class and @Singleton annotation for Object 835

Request Dependencies in Dependent Objects 835

Connecting @Modules with @Inject 835

Using @Component Interface to Obtain Objects 836

Chapter 155: Lint Warnings 837

Remarks 837

Official documentation: 837

Examples 837

Using tools:ignore in xml files 837

Importing resources without "Deprecated" error 837

Configure LintOptions with gradle 838

How to configure the lint.xml file 839

Configuring lint checking in Java and XML source files 839

Configuring lint checking in Java 839

Configuring lint checking in XML 840

Mark Suppress Warnings 840


Chapter 156: ListView 841

Introduction 841

Remarks 841

Examples 841

Filtering with CursorAdapter 841

Custom ArrayAdapter 842

A basic ListView with an ArrayAdapter 843

Chapter 157: Loader 845

Introduction 845

Parameters 845

Remarks 845

When not to use Loaders 845

Examples 846

Basic AsyncTaskLoader 846

AsyncTaskLoader with cache 847

Reloading 848

Pass parameters using a Bundle 848

Chapter 158: Loading Bitmaps Effectively 850

Introduction 850

Syntax 850

Examples 850

Load the Image from Resource from Android Device. Using Intents. 850

Chapter 159: Localization with resources in Android 853

Examples 853

Currency 853

Adding translation to your Android app 853

Type of resource directories under the "res" folder 854

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

Change locale of android application programatically 858

Chapter 160: Localized Date/Time in Android 863


Remarks 863

Examples 863

Custom localized date format with DateUtils.formatDateTime() 863

Standard date/time formatting in Android 863

Fully customized date/time 863

Chapter 161: Location 865

Introduction 865

Remarks 865

LocationManager 865

FusedLocationProviderApi 866

TroubleShooting 868

Examples 875

Fused location API 875

Example Using Activity w/ LocationRequest 875

Example Using Service w/ PendingIntent and BroadcastReceiver 877

Requesting location updates using LocationManager 880

Requesting location updates on a separate thread using LocationManager 881

Register geofence 883

Get Address From Location using Geocoder 886

Getting location updates in a BroadcastReceiver 886

Chapter 162: Logging and using Logcat 888

Syntax 888

Parameters 888

Remarks 888

Definition 888

When to use 889

Useful links 889

Examples 889

Filtering the logcat output 889

Logging 891

Basic Logging 891


Log Levels 892

Motivation For Logging 892

Things To Considering When Logging: 893

Log Readability: 893

Performance: 893

Security: 893

Conclusion: 893

Log with link to source directly from Logcat 893

Using the Logcat 894

Generating Logging code 895

Android Studio usage 896

Clear logs 898

Chapter 163: Looper 899

Introduction 899

Examples 899

Create a simple LooperThread 899

Run a loop with a HandlerThread 899

Chapter 164: LruCache 900

Remarks 900

Examples 900

Initialising the cache 900

Adding a Bitmap(Resource) to the cache 900

Getting a Bitmap(Resouce) from the cache 901

Chapter 165: Material Design 902

Introduction 902

Remarks 902

Examples 902

Apply an AppCompat theme 902

Adding a Toolbar 903

Adding a FloatingActionButton (FAB) 905

Buttons styled with Material Design 906

How to use TextInputLayout 907


Adding a TabLayout 908

RippleDrawable 910

Add a Navigation Drawer 914

Bottom Sheets in Design Support Library 917

Persistent Bottom Sheets 918

Bottom Sheet DialogFragment 919

Add a Snackbar 920

Chapter 166: MediaPlayer 923

Syntax 923

Remarks 923

Examples 925

Basic creation and playing 925

Asynchronous prepare 925

Getting system ringtones 926

Getting and setting system volume 927

Audio stream types 927

Setting volume 927

Adjusting volume by one step 927

Setting MediaPlayer to use specific stream type 928

Media Player with Buffer progress and play position 928

Import audio into androidstudio and play it 930

Chapter 167: MediaSession 932

Syntax 932

Remarks 932

Examples 932

Receiving and handling button events 932

Chapter 168: MediaStore 935

Examples 935

Fetch Audio/MP3 files from specific folder of device or fetch all files 935

Example with Activity 936

Chapter 169: Memory Leaks 938


Examples 938

Common memory leaks and how to fix them 938

1. Fix your contexts: 938

2. Static reference to Context 938

3. Check that you're actually finishing your services. 938

4. Check image and bitmaps usage: 939

5. If you are using broadcast receivers unregister them. 939

6. If you are using java.util.Observer (Observer pattern): 939

Avoid leaking Activities with AsyncTask 939

Anonymous callback in activities 940

Activity Context in static classes 941

Detect memory leaks with the LeakCanary library 942

Avoid leaking Activities with Listeners 943

Alternative 1: Removing listeners 945

Alternative 2: Using weak references 946

Avoid memory leaks with Anonymous Class, Handler, Timer Task, Thread 948

Chapter 170: Menu 950

Syntax 950

Parameters 950

Remarks 950

Examples 950

Options menu with dividers 950

Apply custom font to Menu 951

Creating a Menu in an Activity 951

Step 1: 951

Step 2: 952

Wrapping up! 952

Screenshot of how your own Menu looks: 953

Chapter 171: Moshi 955

Introduction 955

Remarks 955

Examples 955
JSON into Java 955

serialize Java objects as JSON 955

Built in Type Adapters 955

Chapter 172: Multidex and the Dex Method Limit 957

Introduction 957

Remarks 957

What is dex? 957

The problem: 957

What to do about it: 957

How to avoid the limit: 958

Examples 958

Multidex by using MultiDexApplication directly 958

Multidex by extending Application 959

Enabling Multidex 959

Gradle configuration 960

Enable MultiDex in your Application 960

Counting Method References On Every Build (Dexcount Gradle Plugin) 960

Multidex by extending MultiDexApplication 961

Chapter 173: MVP Architecture 962

Introduction 962

Remarks 962

MVP Definition 962

Recommended App Structure (not required) 962

Examples 962

Login example in the Model View Presenter (MVP) pattern 962

Class Diagram 966

Notes: 966

Simple Login Example in MVP 967

Required package structure 967

XML activity_login 967

Activity Class LoginActivity.class 968


Creating an ILoginView Interface 970

Creating an ILoginPresenter Interface 970

ILoginPresenter.class 970

LoginPresenterCompl.class 970

Creating a UserModel 971

UserModel.class 971

IUser.class 972

MVP 972

Chapter 174: MVVM (Architecture) 974

Remarks 974

Examples 975

MVVM Example using DataBinding Library 975

Chapter 175: NavigationView 983

Remarks 983

Official Documentation: 983

Material Design Specifications: 983

Examples 983

How to add the NavigationView 983

Add underline in menu elements 988

Add seperators to menu 989

Add menu Divider using default DividerItemDecoration. 990

Chapter 176: Notification Channel Android O 992

Introduction 992

Syntax 992

Parameters 992

Examples 992

Notification Channel 992

Chapter 177: Notifications 998

Examples 998

Creating a simple Notification 998

Specify the notification's content: 998


Create the intent to fire on click: 998

Finally, build the notification and show it 998

Heads Up Notification with Ticker for older devices 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

Android 6.0 Marshmallow: 1000

Android 4.4.x KitKat: 1001

Setting Different priorities in notification 1002

Scheduling notifications 1003

Set custom notification - show full content text 1004

For example, you have this: 1004

But you wish your text will be fully shown: 1004

Set custom notification icon using `Picasso` library. 1005

Dynamically getting the correct pixel size for the large icon 1006

Ongoing notification with Action button 1006

Chapter 178: OkHttp 1008

Examples 1008

Logging interceptor 1008

Rewriting Responses 1008

Basic usage example 1008

Synchronous Get Call 1009

Asynchronous Get Call 1009

Posting form parameters 1010

Posting a multipart request 1010

Setting up OkHttp 1011

Chapter 179: Okio 1012

Examples 1012

Download / Implement 1012

PNG decoder 1012

ByteStrings and Buffers 1013

Chapter 180: Optimized VideoView 1014

Introduction 1014
Examples 1014

Optimized VideoView in ListView 1014

Chapter 181: Orientation Changes 1026

Remarks 1026

Examples 1026

Saving and Restoring Activity State 1026

Saving and Restoring Fragment State 1027

Retaining Fragments 1028

Locking Screen Orientation 1029

Manually Managing Configuration Changes 1029

Handling AsyncTask 1030

Problem: 1030

Solution: 1030

Example: 1030

MainActivity: 1030

AsyncTaskLoader: 1031

Note: 1031

Lock Screen's rotation programmatically 1031

Chapter 182: ORMLite in android 1033

Examples 1033

Android OrmLite over SQLite example 1033

Gradle setup 1033

Database Helper 1034

Persisting Object to SQLite 1035

Chapter 183: Otto Event Bus 1038

Remarks 1038

Examples 1038

Passing an event 1038

Receiving an event 1039

Chapter 184: PackageManager 1040

Examples 1040
Retrieve application version 1040

Version name and version code 1040

Install time and update time 1040

Utility method using PackageManager 1041

Chapter 185: Pagination in RecyclerView 1043

Introduction 1043

Examples 1043

MainActivity.java 1043

Chapter 186: Paint 1048

Introduction 1048

Examples 1048

Creating a Paint 1048

Setting up Paint for text 1048

Text drawing settings 1048

Measuring text 1049

Setting up Paint for drawing shapes 1049

Setting flags 1049

Chapter 187: Parcelable 1051

Introduction 1051

Remarks 1051

Examples 1051

Making a custom object Parcelable. 1051

Parcelable object containing another Parcelable object 1052

Using Enums with Parcelable 1053

Chapter 188: Performance Optimization 1055

Introduction 1055

Examples 1055

Save View lookups with the ViewHolder pattern 1055

Chapter 189: Picasso 1056

Introduction 1056

Remarks 1056

Examples 1056
Adding Picasso Library to your Android Project 1056

Gradle. 1056

Maven: 1056

Placeholder and Error Handling 1056

Re-sizing and Rotating 1057

Circular Avatars with Picasso 1057

Disable cache in Picasso 1059

Loading Image from external Storage 1059

Downloading image as Bitmap using Picasso 1059

Cancelling Image Requests using Picasso 1060

Using Picasso as ImageGetter for Html.fromHtml 1060

Try offline disk cache first, then go online and fetch the image 1062

Chapter 190: Ping ICMP 1064

Introduction 1064

Examples 1064

Performs a single Ping 1064

Chapter 191: Port Mapping using Cling library in Android 1065

Examples 1065

Adding Cling Support to your Android Project 1065

Mapping a NAT port 1065

Chapter 192: PorterDuff Mode 1067

Introduction 1067

Remarks 1067

Examples 1068

Creating a PorterDuff ColorFilter 1068

Creating a PorterDuff XferMode 1069

Apply a radial mask (vignette) to a bitmap using PorterDuffXfermode 1069

Chapter 193: ProgressBar 1070

Remarks 1070

Examples 1070

Indeterminate ProgressBar 1070


Determinate ProgressBar 1070

Customized progressbar 1072

Tinting ProgressBar 1075

Material Linear ProgressBar 1076

Indeterminate 1077

Determinate 1077

Buffer 1078

Indeterminate and Determinate 1078

Creating Custom Progress Dialog 1079

Chapter 194: ProGuard - Obfuscating and Shrinking your code 1081

Examples 1081

Rules for some of the widely used Libraries 1081

Enable ProGuard for your build 1083

Remove trace logging (and other) statements at build time 1083

Protecting your code from hackers 1084

Enabling ProGuard with a custom obfuscation configuration file 1085

Chapter 195: Project SDK versions 1087

Introduction 1087

Parameters 1087

Remarks 1087

Examples 1087

Defining project SDK versions 1088

Chapter 196: Publish .aar file to Apache Archiva with Gradle 1089

Examples 1089

Simple implementation example 1089

Chapter 197: Publish a library to Maven Repositories 1091

Examples 1091

Publish .aar file to Maven 1091

Chapter 198: Publish to Play Store 1093

Examples 1093

Minimal app submission guide 1093


Chapter 199: Realm 1095

Introduction 1095

Remarks 1095

Examples 1095

Adding Realm to your project 1095

Realm Models 1096

List of primitives (RealmList) 1097

try-with-resources 1098

Sorted queries 1098

Async queries 1098

Using Realm with RxJava 1099

Basic Usage 1100

Setting up an instance 1100

Closing an instance 1100

Models 1101

Inserting or updating data 1102

Querying the database 1102

Deleting an object 1102

Chapter 200: RecyclerView 1104

Introduction 1104

Parameters 1104

Remarks 1104

Other related topics: 1105

Official Documentation 1105

Older versions: 1105

Examples 1105

Adding a RecyclerView 1105

Smoother loading of items 1106

Drag&Drop and Swipe with RecyclerView 1108

Add header/footer to a RecyclerView 1108

Using several ViewHolders with ItemViewType 1111


Filter items inside RecyclerView with a SearchView 1112

Popup menu with recyclerView 1113

Animate data change 1115

Example using SortedList 1117

RecyclerView with DataBinding 1119

Endless Scrolling in Recycleview. 1121

Show default view till items load or when data is not available 1121

Add divider lines to RecyclerView items 1124

Chapter 201: RecyclerView and LayoutManagers 1126

Examples 1126

GridLayoutManager with dynamic span count 1126

Adding header view to recyclerview with gridlayout manager 1128

Simple list with LinearLayoutManager 1130

Activity layout 1130

Define the data model 1130

List item layout 1131

Create a RecyclerView adapter and ViewHolder 1131

(Generate random data) 1133

Connect the RecyclerView with the PlaceListAdapter and the dataset 1133

Done! 1134

StaggeredGridLayoutManager 1134

Chapter 202: RecyclerView Decorations 1137

Syntax 1137

Parameters 1137

Remarks 1137

Decorations are static 1137

Multiple decorations 1137

Other related topics: 1137

Official javadoc 1137

Examples 1137

Drawing a Separator 1138


Per-item margins with ItemDecoration 1139

Add divider to RecyclerView 1139

How to add dividers using and DividerItemDecoration 1142

ItemOffsetDecoration for GridLayoutManager in RecycleView 1142

Chapter 203: RecyclerView onClickListeners 1144

Examples 1144

New Example 1144

Kotlin and RxJava example 1145

Easy OnLongClick and OnClick Example 1146

Adaptor demo 1147

Item Click Listeners 1149

Another way to implement Item Click Listener 1150

RecyclerView Click listener 1152

Chapter 204: RenderScript 1155

Introduction 1155

Examples 1155

Getting Started 1155

Setting up your project 1155

How RenderScript works 1156

Writing your first RenderScript 1156

RenderScript Boilerplate 1157

Global Variables 1158

Kernels 1158

Kernels in general 1158

RenderScript Runtime API methods 1159

Kernel Implementation 1159

Calling RenderScript in Java 1160

Basics 1160

Creating Allocation instances 1161

Full example 1162

Conclusion 1163
Blur an image 1163

Blur a View 1165

BlurBitmapTask.java 1165

Usage: 1167

Chapter 205: Resources 1168

Examples 1168

Translate a string 1168

Define strings 1169

Define string array 1169

Define dimensions 1170

Define integers 1171

Define integer array 1171

Define colors 1172

Getting resources without "deprecated" warnings 1173

Define a menu resource and use it inside Activity/Fragment 1174

String formatting in strings.xml 1175

Define a color state list 1175

Define String Plurals 1176

Import array of objects defined in resources 1176

9 Patches 1179

A SIMPLE GUIDE TO 9-PATCH FOR ANDROID UI May 18, 2011 1180

Color Transparency(Alpha) Level 1183

Working with strings.xml file 1183

Chapter 206: Retrofit2 1186

Introduction 1186

Remarks 1186

Examples 1186

A Simple GET Request 1186

Add logging to Retrofit2 1189

Uploading a file via Multipart 1190

Retrofit with OkHttp interceptor 1190

Header and Body: an Authentication Example 1191


Upload multiple file using Retrofit as multipart 1192

Download a file from Server using Retrofit2 1194

Debugging with Stetho 1196

Retrofit 2 Custom Xml Converter 1197

A simple POST request with GSON 1199

Reading XML form URL with Retrofit 2 1201

Chapter 207: Retrofit2 with RxJava 1204

Examples 1204

Retrofit2 with RxJava 1204

Retrofit with RxJava to fetch data asyncronously 1205

Nested requests example: multiple requests, combine results 1207

Chapter 208: RoboGuice 1209

Examples 1209

Simple example 1209

Installation for Gradle Projects 1209

@ContentView annotation 1209

@InjectResource annotation 1209

@InjectView annotation 1210

Introduction to RoboGuice 1210

Chapter 209: Robolectric 1213

Introduction 1213

Examples 1213

Robolectric test 1213

Configuration 1213

Run with custom Application class 1213

Set target SDK 1213

Run with custom manifest 1214

Use qualifiers 1214

Chapter 210: Runtime Permissions in API-23 + 1215

Introduction 1215

Remarks 1215

Examples 1216
Android 6.0 multiple permissions 1216

Enforcing Permissions in Broadcasts, URI 1217

Multiple Runtime Permissions From Same Permission Groups 1218

Using PermissionUtil 1220

Include all permission-related code to an abstract base class and extend the activity of t 1221

Example usage in the activity 1222

Chapter 211: SearchView 1224

Examples 1224

Appcompat SearchView with RxBindings watcher 1224

SearchView in Toolbar with Fragment 1226

Setting Theme for SearchView 1228

Chapter 212: Secure SharedPreferences 1230

Introduction 1230

Syntax 1230

Parameters 1230

Remarks 1230

Examples 1230

Securing a Shared Preference 1230

Chapter 213: Secure SharedPreferences 1232

Introduction 1232

Syntax 1232

Parameters 1232

Remarks 1232

Examples 1232

Securing a Shared Preference 1232

Chapter 214: Security 1234

Examples 1234

Verifying App Signature - Tamper Detection 1234

Chapter 215: SensorManager 1235

Examples 1235

Retrieving sensor events 1235


Sensor transformation to world coordinate system 1236

Decide if your device is static or not, using the accelerometer 1236

Chapter 216: Service 1238

Introduction 1238

Remarks 1238

Examples 1238

Starting a Service 1238

Lifecycle of a Service 1238

Defining the process of a service 1239

Creating Bound Service with help of Binder 1240

Creating Remote Service (via AIDL) 1241

Creating an unbound service 1242

Chapter 217: Shared Element Transitions 1246

Introduction 1246

Syntax 1246

Examples 1246

Shared Element Transition between two Fragments 1246

Chapter 218: SharedPreferences 1249

Introduction 1249

Syntax 1249

Parameters 1250

Remarks 1250

Official Documentation 1250

Examples 1250

Read and write values to SharedPreferences 1250

Removing keys 1251

Implementing a Settings screen using SharedPreferences 1252

Retrieve all stored entries from a particular SharedPreferences file 1254

Listening for SharedPreferences changes 1254

Reading and writing data to SharedPreferences with Singleton 1255

Different ways of instantiating an object of SharedPreferences 1259

getPreferences(int) VS getSharedPreferences(String, int) 1259


Commit vs. Apply 1260

Supported data types in SharedPreferences 1260

Store, Retrieve, Remove and Clear Data from SharedPreferences 1261

Support pre-Honeycomb with StringSet 1262

Add filter for EditTextPreference 1263

Chapter 219: ShortcutManager 1265

Examples 1265

Dynamic Launcher Shortcuts 1265

Chapter 220: Sign your Android App for Release 1266

Introduction 1266

Examples 1266

Sign your App 1266

Configure the build.gradle with signing configuration 1267

Chapter 221: Smartcard 1269

Examples 1269

Smart card send and receive 1269

Chapter 222: Snackbar 1272

Syntax 1272

Parameters 1272

Remarks 1272

Official Documentation 1272

Examples 1272

Creating a simple Snackbar 1272

Custom Snack Bar 1273

Snackbar with Callback 1274

Custom Snackbar 1274

Snackbar vs Toasts: Which one should I use? 1275

Custom Snackbar (no need view) 1275

Chapter 223: SpannableString 1277

Syntax 1277

Examples 1277

Add styles to a TextView 1277


Multi string , with multi color 1280

Chapter 224: Speech to Text Conversion 1282

Examples 1282

Speech to Text With Default Google Prompt Dialog 1282

Speech to Text without Dialog 1283

Chapter 225: Spinner 1285

Examples 1285

Adding a spinner to your activity 1285

Basic Spinner Example 1285

Chapter 226: Split Screen / Multi-Screen Activities 1288

Examples 1288

Split Screen introduced in Android Nougat implemented. 1288

Chapter 227: SQLite 1290

Introduction 1290

Remarks 1290

Examples 1290

Using the SQLiteOpenHelper class 1290

Insert data into database 1291

onUpgrade() method 1292

Reading data from a Cursor 1292

Create a Contract, Helper and Provider for SQLite in Android 1294

Updating a row in a table 1298

Performing a Transaction 1299

Delete row(s) from the table 1299

Store image into SQLite 1300

Create Database from assets folder 1301

Exporting and importing a database 1304

Bulk insert 1305

Chapter 228: Storing Files in Internal & External Storage 1307

Syntax 1307

Parameters 1307

Examples 1307
Using Internal Storage 1307

Using External Storage 1308

Android: Internal and External Storage - Terminology Clarification 1309

Save Database on SD Card (Backup DB on SD) 1314

Fetch Device Directory : 1314

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

Chapter 230: Supporting Screens With Different Resolutions, Sizes 1318

Remarks 1318

Screen size 1318

Screen density 1318

Orientation 1318

Units 1318

px 1319

in 1319

mm 1319

pt 1319

dp or dip 1319

sp 1319

Examples 1320

Using configuration qualifiers 1320

Converting dp and sp to pixels 1320

Text size and different android screen sizes 1321

Chapter 231: Swipe to Refresh 1323

Syntax 1323

Examples 1323

Swipe To Refresh with RecyclerView 1323

How to add Swipe-to-Refresh To your app 1323


Chapter 232: SyncAdapter with periodically do sync of data 1325

Introduction 1325

Examples 1325

Sync adapter with every min requesting value from server. 1325

Chapter 233: TabLayout 1335

Examples 1335

Using a TabLayout without a ViewPager 1335

Chapter 234: TensorFlow 1336

Introduction 1336

Remarks 1336

Examples 1336

How to use 1336

Chapter 235: Testing UI with Espresso 1338

Remarks 1338

Espresso 1338

Troubleshooting 1338

Examples 1338

Set Up Espresso 1338

Create Espresso Test Class 1339

Open Close DrawerLayout 1339

Espresso simple UI test 1340

UI testing tools 1340

How to add espresso to the project 1341

Device setup 1342

Writing the test 1342

Up Navigation 1345

Performing an action on a view 1345

Finding a view with onView 1345

Espresso custom matchers 1346

Overall Espresso 1348

Enter Text In EditText 1349


Perform Click on View 1349

Checking View is Displayed 1349

Group a collection of test classes in a test suite 1349

Chapter 236: Text to Speech(TTS) 1351

Examples 1351

Text to Speech Base 1351

TextToSpeech implementation across the APIs 1353

Chapter 237: TextInputLayout 1356

Introduction 1356

Remarks 1356

Examples 1356

Basic usage 1356

Handling Errors 1356

Adding Character Counting 1357

Password Visibility Toggles 1357

TextInputEditText 1358

Customizing the appearance of the TextInputLayout 1358

Chapter 238: TextView 1360

Introduction 1360

Syntax 1360

Remarks 1360

Examples 1360

Textview with different Textsize 1360

TextView customization 1360

Spannable TextView 1363

TextView with image 1365

Strikethrough TextView 1365

Strikethrough the entire text 1365

Strikethrough only parts of the text 1365

Theme and Style customization 1366

Make RelativeSizeSpan align to top 1368

Pinchzoom on TextView 1369


Single TextView with two different colors 1371

Chapter 239: The Manifest File 1373

Introduction 1373

Examples 1373

Declaring Components 1373

Declaring permissions in your manifest file 1374

Chapter 240: Theme, Style, Attribute 1375

Examples 1375

Use Custom Theme Globally 1375

Define primary, primary dark, and accent colors 1375

Use Custom Theme Per Activity 1375

Overscroll Color (API 21+) 1376

Ripple Color (API 21+) 1376

Light Status Bar (API 23+) 1376

Translucent Navigation and Status Bars (API 19+) 1377

Navigation Bar Color (API 21+) 1377

Theme inheritance 1377

Multiple Themes in one App 1378

change theme for all activities at once 1379

Chapter 241: Thread 1381

Examples 1381

Thread Example with its description 1381

Updating the UI from a Background Thread 1381

Chapter 242: Time Utils 1383

Examples 1383

Convert Date Format into Milliseconds 1383

To check within a period 1384

GetCurrentRealTime 1384

Chapter 243: Toast 1386

Introduction 1386

Syntax 1386

Parameters 1386
Remarks 1386

Official Documentation: 1387

Examples 1387

Set position of a Toast 1387

Showing a Toast Message 1387

Creating a custom Toast 1388

Thread safe way of displaying Toast (Application Wide) 1389

Show Toast Message Above Soft Keyboard 1390

Thread safe way of displaying a Toast Message (For AsyncTask) 1390

Chapter 244: Tools Attributes 1391

Remarks 1391

Examples 1391

Designtime Layout Attributes 1391

Chapter 245: Touch Events 1393

Examples 1393

How to vary between child and parent view group touch events 1393

Chapter 246: TransitionDrawable 1397

Examples 1397

Add transition or Cross-fade between two images. 1397

Step 1: Create a transition drawable in XML 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

Animate views background color (switch-color) with TransitionDrawable 1398

Chapter 247: Twitter APIs 1399

Examples 1399

Creating login with twitter button and attach a callback to it 1399

Chapter 248: Typedef Annotations: @IntDef, @StringDef 1401

Remarks 1401

Examples 1401

IntDef Annotations 1401

Combining constants with flags 1402


Chapter 249: UI Lifecycle 1403

Examples 1403

Saving data on memory trimming 1403

Chapter 250: Unit testing in Android with JUnit 1404

Remarks 1404

Examples 1404

Creating Local unit tests 1404

Example test class 1404

Breakdown 1404

Tip Quickly create test classes in Android Studio 1405

Tip Easily execute tests in Android Studio 1405

Moving Business Logic Out of Android Componenets 1405

Getting started with JUnit 1408

Setup 1408

Writing a test 1409

Running a test 1410

Exceptions 1411

Static import 1412

Chapter 251: Universal Image Loader 1414

Remarks 1414

Examples 1414

Initialize Universal Image Loader 1414

Basic usage 1414

Chapter 252: Unzip File in Android 1416

Examples 1416

Unzip file 1416

Chapter 253: Vector Drawables 1417

Introduction 1417

Parameters 1417

Remarks 1417

Examples 1418
VectorDrawable Usage Example 1418

VectorDrawable xml example 1419

Importing SVG file as VectorDrawable 1419

Chapter 254: VectorDrawable and AnimatedVectorDrawable 1422

Examples 1422

Basic VectorDrawable 1422

Using 1422

tags 1423

Basic AnimatedVectorDrawable 1424

Using Strokes 1425

Vector compatibility through AppCompat 1427

Chapter 255: Vibration 1429

Examples 1429

Getting Started with Vibration 1429

Vibrate Indefinitely 1429

Vibration Patterns 1429

Stop Vibrate 1430

Vibrate for one time 1430

Chapter 256: VideoView 1431

Examples 1431

VideoView Create 1431

Play video from URL with using VideoView 1431

Chapter 257: ViewFlipper 1433

Introduction 1433

Examples 1433

ViewFlipper with image sliding 1433

Chapter 258: ViewPager 1435

Introduction 1435

Remarks 1435

Examples 1435

Basic ViewPager usage with fragments 1435

ViewPager with TabLayout 1437


ViewPager with PreferenceFragment 1439

Adding a ViewPager 1440

ViewPager with a dots indicator 1441

Nested TabLayout in ViewPager 1441

Separate TabLayout 1442

selected_dot.xml 1442

default_dot.xml 1442

tab_selector.xml 1443

Setup OnPageChangeListener 1443

Chapter 259: Volley 1445

Introduction 1445

Syntax 1445

Remarks 1445

Installation 1445

Official Documentation 1445

Examples 1446

Basic StringRequest using GET method 1446

Cancel a request 1446

Adding custom design time attributes to NetworkImageView 1447

Request JSON 1448

Adding custom headers to your requests [e.g. for basic auth] 1448

Helper Class for Handling Volley Errors 1449

Remote server authentication using StringRequest through POST method 1450

Using Volley for HTTP requests 1452

Boolean variable response from server with json request in volley 1454

Use JSONArray as request body 1455

Chapter 260: WebView 1457

Introduction 1457

Remarks 1457

Examples 1457

JavaScript alert dialogs in WebView - How to make them work 1457

Communication from Javascript to Java (Android) 1457


Communication from Java to Javascript 1458

Open dialer example 1459

Troubleshooting WebView by printing console messages or by remote debugging 1459

Printing webview console messages to logcat 1460

Remote debugging android devices with Chrome 1460

Enable USB debugging on your Android device 1460

Connect and discover your Android device 1460

Open Local File / Create dynamic content in Webview 1461

Chapter 261: What is ProGuard? What is use in Android? 1462

Introduction 1462

Examples 1462

Shrink your code and resources with proguard 1462

Chapter 262: Widgets 1464

Remarks 1464

Examples 1464

Manifest Declaration - 1464

Metadata 1464

AppWidgetProvider Class 1464

Two widgets with different layouts declaration 1465

Create/Integrate Basic Widget using Android Studio 1466

Right on your Application ==> New ==> Widget ==> App Widget 1466

Chapter 263: Wi-Fi Connections 1468

Examples 1468

Connect with WEP encryption 1468

Connect with WPA2 encryption 1468

Scan for access points 1469

Chapter 264: Writing UI tests - Android 1472

Introduction 1472

Syntax 1472

Remarks 1472

JUnit rules: 1472

Appium 1472
Parameters 1472

Examples 1473

MockWebServer example 1473

IdlingResource 1475

Implementation 1475

NOTES 1476

Example 1476

Usage 1477

Combination with JUnit rule 1477

Chapter 265: XMPP register login and chat simple example 1479

Examples 1479

XMPP register login and chat basic example 1479

Chapter 266: Xposed 1488

Examples 1488

Creating a Xposed Module 1488

Hooking a method 1488

Chapter 267: Youtube-API 1491

Remarks 1491

Examples 1491

Launching StandAlonePlayerActivity 1491

Activity extending YouTubeBaseActivity 1491

YoutubePlayerFragment in portrait Activty 1492

YouTube Player API 1495

Consuming YouTube Data API on Android 1497

Chapter 268: Zip file in android 1501

Examples 1501

Zip file on android 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 [email protected]

https://riptutorial.com/ 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

Version API Level Version Code Release Date

1.0 1 BASE 2008-09-23

1.1 2 BASE_1_1 2009-02-09

1.5 3 CUPCAKE 2009-04-27

1.6 4 DONUT 2009-09-15

2.0 5 ECLAIR 2009-10-26

2.0.1 6 ECLAIR_0_1 2009-12-03

2.1.x 7 ECLAIR_MR1 2010-01-12

2.2.x 8 FROYO 2010-05-20

2.3 9 GINGERBREAD 2010-12-06

2.3.3 10 GINGERBREAD_MR1 2011-02-09

3.0.x 11 HONEYCOMB 2011-02-22

3.1.x 12 HONEYCOMB_MR1 2011-05-10

3.2.x 13 HONEYCOMB_MR2 2011-07-15

4.0 14 ICE_CREAM_SANDWICH 2011-10-18

4.0.3 15 ICE_CREAM_SANDWICH_MR1 2011-12-16

4.1 16 JELLY_BEAN 2012-07-09

4.2 17 JELLY_BEAN_MR1 2012-11-13

https://riptutorial.com/ 2
Version API Level Version Code Release Date

4.3 18 JELLY_BEAN_MR2 2013-07-24

4.4 19 KITKAT 2013-10-31

4.4W 20 KITKAT_WATCH 2014-06-25

5.0 21 LOLLIPOP 2014-11-12

5.1 22 LOLLIPOP_MR1 2015-03-09

6.0 23 M (Marshmallow) 2015-10-05

7.0 24 N (Nougat) 2016-08-22

7.1 25 N_MR1 (Nougat MR1) 2016-10-04

8.0 26 O (Developer Preview 4) 2017-07-24

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.

Installing Android Studio and Android SDK tools:

1. Download and install Android Studio.


2. Download the latest SDK Tools and SDK Platform-tools by opening the Android Studio, and
then following the Android SDK Tool Updates instructions. You should install the latest
available stable packages.

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.

https://riptutorial.com/ 3
Configure Android Studio
Android Studio provides access to two configuration files through the Help menu:

• studio.vmoptions: 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
studio64.vmoptions, depending on your version of Android Studio.
• idea.properties: Customize Android Studio properties, such as the plugins folder path or
maximum supported file size.

Change/add theme
You can change it as your preference.File->Settings->Editor->Colors & Fonts-> and select a
theme.Also you can download new themes from http://color-themes.com/ Once you have
downloaded the .jar.zip 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 local.properties file,
which is created by Android Studio automatically. If you need to create the project without Android
Studio you need a line starting with sdk.dir= 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 ModuleName-release.apk.

Creating a New Project

Set up Android Studio


Start by setting up Android Studio and then open it. Now, you're ready to make your first Android
App!

Note: this guide is based on Android Studio 2.2, but the process on other versions is
mainly the same.

Configure Your Project


Basic Configuration

https://riptutorial.com/ 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:

1. Application Name - This name will be shown to the user.

Example: Hello World. You can always change it later in AndroidManifest.xml file.

2. Company Domain - This is the qualifier for your project's package name.

Example: stackoverflow.com.

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.

Example: com.stackoverflow.android.helloworld or com.stackoverflow.helloworld. You can


always change your applicationId by overriding it in your gradle file.

Don't use the default prefix "com.example" 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.

https://riptutorial.com/ 5
https://riptutorial.com/ 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.

https://riptutorial.com/ 7
https://riptutorial.com/ 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.

From: Dashboards on Android Developer website.

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

https://riptutorial.com/ 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.

Inspecting the Project


To understand how Android works, let's take a look at some of the files that were created for us.

On the left pane of Android Studio, we can see the structure of our Android application.

First, let's open AndroidManifest.xml 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.

If an application needs access to a feature protected by a permission, it must declare that it


requires that permission with a <uses-permission> element in the manifest. Then, when the
application is installed on the device, the installer determines whether or not to grant the requested
permission by checking the authorities that signed the application's certificates and, in some
cases, asking the user. An application can also protect its own components (activities, services,
broadcast receivers, and content providers) with permissions. It can employ any of the

https://riptutorial.com/ 10
permissions defined by Android (listed in android.Manifest.permission) or declared by other
applications. Or it can define its own.

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.stackoverflow.helloworld">

<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="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>
</application>
</manifest>

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:

<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"

https://riptutorial.com/ 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="com.stackexchange.docs.helloworld.MainActivity">

<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.

You can read more about Layouts and attributes.

Next, let's take a look at MainActivity. This is the Java code that has been generated for
MainActivity.

public class MainActivity extends AppCompatActivity {

// The onCreate method is called when an Activity starts


// This is where we will set up our layout
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// setContentView sets the Activity's layout to a specified XML layout


// In our case we are using the activity_main layout
setContentView(R.layout.activity_main);
}
}

As defined in our Android manifest, MainActivity will launch by default when a user starts the
HelloWorld app.

Lastly, open up the file named build.gradle located in app/.


Android Studio uses the build system Gradle to compile and build Android applications and
libraries.

apply plugin: 'com.android.application'

android {
signingConfigs {
applicationName {
keyAlias 'applicationName'
keyPassword 'password'
storeFile file('../key/applicationName.jks')
storePassword 'anotherPassword'
}
}
compileSdkVersion 26
buildToolsVersion "26.0.0"

https://riptutorial.com/ 12
defaultConfig {
applicationId "com.stackexchange.docs.helloworld"
minSdkVersion 16
targetSdkVersion 26
versionCode 1
versionName "1.0"
signingConfig signingConfigs.applicationName
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support: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
• com.android.support: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

https://riptutorial.com/ 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.

You can find more info about the Gradle plugin:

• A basic example
• Introduction to the Gradle plugin for android and the wrapper
• Introduction to the configuration of the build.gradle and the DSL methods

Running the Application


Now, let's run our HelloWorld application. You can either run an Android Virtual Device (which you
can set up by using the AVD Manager in Android Studio, as described in the example below) or
connect your own Android device through a USB cable.

Setting up an Android device


To run an application from Android Studio on your Android Device, you must enable USB Debugging
in the Developer Options in the settings of your device.

Settings > Developer options > USB debugging

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.

Settings > About phone > Build number

You also might need to change build.gradle configuration to build on a version that your device
has.

Running from Android Studio


Click the green Run button from the toolbar at the top of Android Studio. In the window that
appears, select whichever device you would like to run the app on (start an Android Virtual Device
if necessary, or see Setting up an AVD (Android Virtual Device) if you need to set one up) and

https://riptutorial.com/ 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.

APK file location


When you prepare your application for release, you configure, build, and test a release version of
your application. The configuration tasks are straightforward, involving basic code cleanup and
code modification tasks that help optimize your application. The build process is similar to the
debug build process and can be done using JDK and Android SDK tools. The testing tasks serve
as a final check, ensuring that your application performs as expected under real-world conditions.
When you are finished preparing your application for release you have a signed APK file, which
you can distribute directly to users or distribute through an application marketplace such as
Google Play.

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/app-debug.apk

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/...

Note: this is will become deprecated sometimes around 1.0

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/...

Android programming without an IDE

https://riptutorial.com/ 15
This is a minimalist Hello World example that uses only the most basic Android tools.

Requirements and assumptions


• Oracle JDK 1.7 or later
• Android SDK Tools (just the command line tools)

This example assumes Linux. You may have to adjust the syntax for your own platform.

Setting up the Android SDK


After unpacking the SDK release:

1. Install additional packages using the SDK manager. Don't use android update sdk --no-ui as
instructed in the bundled Readme.txt; 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.

(You can also use your own device)

4. Run the device:

emulator -avd DEVICE

5. If the device screen appears to be locked, then swipe to unlock it.

Leave it running while you code the app.

Coding the app


6. Change to an empty working directory.

7. Make the source file:

https://riptutorial.com/ 16
mkdir --parents src/dom/domain
touch src/dom/domain/SayingHello.java

Content:

package dom.domain;
import android.widget.TextView;

public final class SayingHello extends android.app.Activity


{
protected @Override void onCreate( final android.os.Bundle activityState )
{
super.onCreate( activityState );
final TextView textV = new TextView( SayingHello.this );
textV.setText( "Hello world" );
setContentView( textV );
}
}

8. Add a manifest:

touch AndroidManifest.xml

Content:

<?xml version='1.0'?>
<manifest xmlns:a='http://schemas.android.com/apk/res/android'
package='dom.domain' a:versionCode='0' a:versionName='0'>
<application a:label='Saying hello'>
<activity a:name='dom.domain.SayingHello'>
<intent-filter>
<category a:name='android.intent.category.LAUNCHER'/>
<action a:name='android.intent.action.MAIN'/>
</intent-filter>
</activity>
</application>
</manifest>

9. Make a sub-directory for the declared resources:

mkdir res

Leave it empty for now.

Building the code


10. Generate the source for the resource declarations. Substitute here the correct path to your
SDK, and the installed API to build against (e.g. "android-23"):

aapt package -f \
-I SDK/platforms/android-API/android.jar \

https://riptutorial.com/ 17
-J src -m \
-M AndroidManifest.xml -S res -v

Resource declarations (described further below) are actually optional. Meantime the above
call does nothing if res/ is still empty.

11. Compile the source code to Java bytecode (.java → .class):

javac \
-bootclasspath SDK/platforms/android-API/android.jar \
-classpath src -source 1.7 -target 1.7 \
src/dom/domain/*.java

12. Translate the bytecode from Java to Android (.class → .dex):

First using Jill (.class → .jayce):

java -jar SDK/build-tools/LATEST/jill.jar \


--output classes.jayce src

Then Jack (.jayce → .dex):

java -jar SDK/build-tools/LATEST/jack.jar \


--import classes.jayce --output-dex .

Android bytecode used to be called "Dalvik executable code", and so "dex".

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.

13. Package up the resource files, including the manifest:

aapt package -f \
-F app.apkPart \
-I SDK/platforms/android-API/android.jar \
-M AndroidManifest.xml -S res -v

That results in a partial APK file (Android application package).

14. Make the full APK using the ApkBuilder tool:

java -classpath SDK/tools/lib/sdklib.jar \


com.android.sdklib.build.ApkBuilderMain \
app.apkUnalign \
-d -f classes.dex -v -z app.apkPart

It warns, "THIS TOOL IS DEPRECATED. See --help for more information." If --help fails with
an ArrayIndexOutOfBoundsException, then instead pass no arguments:

https://riptutorial.com/ 18
java -classpath SDK/tools/lib/sdklib.jar \
com.android.sdklib.build.ApkBuilderMain

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.)

15. Optimize the data alignment of the APK (recommended practice):

zipalign -f -v 4 app.apkUnalign app.apk

Installing and running


16. Install the app to the Android device:

adb install -r app.apk

17. Start the app:

adb shell am start -n dom.domain/.SayingHello

It should run and say hello.

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.

18. Add a resource file:

mkdir res/values
touch res/values/values.xml

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:

https://riptutorial.com/ 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:

// v.setText( "Hello world" );


v.setText( "This app is called "
+ getResources().getString( R.string.appLabel ));

21. Test the above modifications by rebuilding, reinstalling and re-running the app (steps 10-17).

It should restart and say, "This app is called Saying hello".

Uninstalling the app


adb uninstall dom.domain

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

https://riptutorial.com/ 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 android.content.Context 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

https://riptutorial.com/ 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.

More detailed description is written here.

Setting up an AVD (Android Virtual Device)

TL;DR It basically allows us to simulate real devices and test our apps without a real device.

According to Android Developer Documentation,

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.

To set up an AVD, follow these steps:

1. Click this button to bring up the AVD Manager:

2. You should see a dialog like this:

https://riptutorial.com/ 22
3. Now click the + Create Virtual Device... button. This will bring up Virtual Device Configuration
Dialog:

https://riptutorial.com/ 23
4. Select any device you want, then click Next:

https://riptutorial.com/ 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.

https://riptutorial.com/ 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.

https://riptutorial.com/ 26
Read Getting started with Android online: https://riptutorial.com/android/topic/85/getting-started-
with-android

https://riptutorial.com/ 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).

A Nine Patch image is stored with the extension .9.png.

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.

Located in the Android SDK: android-sdk\tools\lib\draw9patch.jar

Examples
Basic rounded corners

The key to correctly stretching is in the top and left border.

The top border controls horizontal stretching and the left border controls vertical stretching.

This example creates rounded corners suitable for a Toast.

https://riptutorial.com/ 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.

This example will stretch to all combinations of sizes, as shown below:

Basic spinner

The Spinner can be reskinned according to your own style requirements using a Nine Patch.

As an example, see this Nine Patch:

As you can see, it has 3 extremely small areas of stretching marked.

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.

Using the image without Nine Patch metadata:

Using the image with Nine Patch metadata:

Optional padding lines

https://riptutorial.com/ 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:

Read 9-Patch Images online: https://riptutorial.com/android/topic/461/9-patch-images

https://riptutorial.com/ 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 = SQLiteDatabase.openDatabase(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();
values.put("First_Name", str_edtfname);
values.put("Last_Name", str_edtlname);
myDataBase.insert("table_name", null, values);

Updating data
ContentValues values = new ContentValues();
values.put("First_Name", str_edtfname);
values.put("Last_Name", str_edtlname);
myDataBase.update("table_name", values, "id" + " = ?", new String[] {id});

Read Accessing SQLite databases using the ContentValues class online:


https://riptutorial.com/android/topic/10154/accessing-sqlite-databases-using-the-contentvalues-
class

https://riptutorial.com/ 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

Extend an AbstractAccountAuthenticator (Primarily used to retrieve authentication & re-


authenticate them)

public class AccountAuthenticator extends AbstractAccountAuthenticator {

@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
}

https://riptutorial.com/ 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.
}
}

Create a service (Account Manager framework connects to the extended


AbstractAccountAuthenticator through the service interface)

public class AuthenticatorService extends Service {

private AccountAuthenticator authenticator;

@Override
public void onCreate(){
authenticator = new AccountAuthenticator(this);
}

@Override
public IBinder onBind(Intent intent) {
return authenticator.getIBinder();
}
}

Authenticator XML configuration (The account manager framework requires. This is what you'll
see inside Settings -> Accounts in Android)

<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="rename.with.your.applicationid"
android:icon="@drawable/app_icon"
android:label="@string/app_name"
android:smallIcon="@drawable/app_icon" />

Changes to the AndroidManifest.xml (Bring all the above concepts together to make it usable
programmatically through the AccountManager)

<application
...>
<service
android:name=".authenticator.AccountAuthenticatorService"
android:exported="false"
android:process=":authentication">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data

https://riptutorial.com/ 33
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator"/>
</service>
</application>

The next example will contain how to make use of this setup.

Read Accounts and AccountManager online: https://riptutorial.com/android/topic/7003/accounts-


and-accountmanager

https://riptutorial.com/ 34
Chapter 5: ACRA
Syntax
• android:name=".ACRAHandler"
• ACRA.init(this, config);
• public class ACRAHandler extends Application {

Parameters

Parameter Description

Defines the ACRA settings such as where it is to be reported, custom


@ReportCrashes
content, etc

formUri the path to the file that reports the crash

Remarks
• ACRA no longer supports Google forms, so you need a backend:
https://github.com/ACRA/acra/wiki/Backends

Examples
ACRAHandler

Example Application-extending class for handling the reporting:

@ReportsCrashes(

formUri = "https://backend-of-your-choice.com/",//Non-password protected.


customReportContent = { /* */ReportField.APP_VERSION_NAME,
ReportField.PACKAGE_NAME,ReportField.ANDROID_VERSION,
ReportField.PHONE_MODEL,ReportField.LOGCAT },
mode = ReportingInteractionMode.TOAST,
resToastText = R.string.crash

)
public class ACRAHandler extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);

final ACRAConfiguration config = new ConfigurationBuilder(this)

.build();

// Initialise ACRA

https://riptutorial.com/ 35
ACRA.init(this, config);

Example manifest

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
<!-- etc -->

>

<!-- Internet is required. READ_LOGS are to ensure that the Logcat is transmitted-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.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" >

<!-- Activities -->


</application>

</manifest>

Installation

Maven

<dependency>
<groupId>ch.acra</groupId>
<artifactId>acra</artifactId>
<version>4.9.2</version>
<type>aar</type>
</dependency>

Gradle

compile 'ch.acra:acra:4.9.2'

Read ACRA online: https://riptutorial.com/android/topic/1324/acra

https://riptutorial.com/ 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 onPostCreate(Bundle savedInstanceState) // Called when activity start-up is complete


(after onStart() and onRestoreInstanceState(Bundle) have been called).

• 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 onResume() // Called after onRestoreInstanceState(Bundle), onRestart(), or onPause(),


for your activity to start interacting with 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 onDestroy() // Perform any final cleanup before an activity is destroyed.

• 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).

• void onSaveInstanceState(Bundle outState) // Called to retrieve per-instance state from an


activity before being killed so that the state can be restored in onCreate(Bundle) or
onRestoreInstanceState(Bundle) (the Bundle populated by this method will be passed to
both).

• void onRestoreInstanceState(Bundle savedInstanceState) // This method is called after


onStart() when the activity is being re-initialized from a previously saved state, given here in
savedInstanceState.

https://riptutorial.com/ 37
Parameters

Parameter Details

Intent Can be used with startActivity to launch an Activity

Bundle A mapping from String keys to various Parcelable values.

Context Interface to global information about an application environment.

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.

https://riptutorial.com/ 38
The simplest solution is to set the attribute noHistory to true for that <activity> tag in
AndroidManifest.xml:

<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, C.class));

Typical usage of noHistory flag is with "Splash Screen" or Login Activities.

Android Activity LifeCycle Explained

Assume an application with a MainActivity which can call the Next Activity using a button click.

https://riptutorial.com/ 39
public class MainActivity extends AppCompatActivity {

private final String LOG_TAG = MainActivity.class.getSimpleName();


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(LOG_TAG, "calling onCreate from MainActivity");
}
@Override
protected void onStart() {
super.onStart();
Log.d(LOG_TAG, "calling onStart from MainActivity");
}
@Override
protected void onResume() {
super.onResume();
Log.d(LOG_TAG, "calling onResume from MainActivity");
}

@Override
protected void onPause() {
super.onPause();
Log.d(LOG_TAG, "calling onPause from MainActivity");
}

@Override
protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "calling onStop from MainActivity");
}

@Override
protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "calling onDestroy from MainActivity");
}

@Override
protected void onRestart() {
super.onRestart();
Log.d(LOG_TAG, "calling onRestart from MainActivity");
}
public void toNextActivity(){
Log.d(LOG_TAG, "calling Next Activity");
Intent intent = new Intent(this, NextActivity.class);
startActivity(intent);
} }

and

public class NextActivity extends AppCompatActivity {


private final String LOG_TAG = NextActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
Log.d(LOG_TAG, "calling onCreate from Next Activity");
}
@Override

https://riptutorial.com/ 40
protected void onStart() {
super.onStart();
Log.d(LOG_TAG, "calling onStart from Next Activity");
}
@Override
protected void onResume() {
super.onResume();
Log.d(LOG_TAG, "calling onResume from Next Activity");
}

@Override
protected void onPause() {
super.onPause();
Log.d(LOG_TAG, "calling onPause from Next Activity");
}

@Override
protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "calling onStop from Next Activity");
}

@Override
protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "calling onDestroy from Next Activity");
}

@Override
protected void onRestart() {
super.onRestart();
Log.d(LOG_TAG, "calling onRestart from Next Activity");
} }

When app is first created


D/MainActivity: calling onCreate from MainActivity
D/MainActivity: calling onStart from MainActivity
D/MainActivity: calling onResume from MainActivity
are called

When screen sleeps


08:11:03.142 D/MainActivity: calling onPause from MainActivity
08:11:03.192 D/MainActivity: calling onStop from MainActivity
are called. And again when it wakes up
08:11:55.922 D/MainActivity: calling onRestart from MainActivity
08:11:55.962 D/MainActivity: calling onStart from MainActivity
08:11:55.962 D/MainActivity: calling onResume from MainActivity
are called

Case1: When Next Activity is called from Main Activity


D/MainActivity: calling Next Activity
D/MainActivity: calling onPause from MainActivity
D/NextActivity: calling onCreate from Next Activity
D/NextActivity: calling onStart from Next Activity
D/NextActivity: calling onResume from Next Activity

https://riptutorial.com/ 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

It should be defined in android manifest in <activity/> element as android:launchMode attribute.

https://riptutorial.com/ 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.

Presenting UI with setContentView

Activity class takes care of creating a window for you in which you can place your UI with
setContentView.
There are three setContentView methods:

• setContentView(int layoutResID) - Set the activity content from a layout resource.


• setContentView(View view) - Set the activity content to an explicit view.
• setContentView(View view, ViewGroup.LayoutParams params) - Set the activity content to an
explicit view with provided params.

When setContentView is called, this view is placed directly into the activity's view hierarchy. It can

https://riptutorial.com/ 43
itself be a complex view hierarchy.

Examples
Set content from resource file:
Add resource file (main.xml in this example) with view hierarchy:

<?xml version="1.0" encoding="utf-8"?>


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello" />

</FrameLayout>

Set it as content in activity:

public final class MainActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// The resource will be inflated,


// adding all top-level views to the activity.
setContentView(R.layout.main);
}
}

Set content to an explicit view:

public final class MainActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Creating view with container


final FrameLayout root = new FrameLayout(this);
final TextView text = new TextView(this);
text.setText("Hello");
root.addView(text);

// Set container as content view


setContentView(root);
}
}

https://riptutorial.com/ 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.

1. Target (API >= 16)

Calling finishAffinity() from an Activity

2. Target (11 <= API < 16)

Intent intent = new Intent(this, LoginActivity.class);


intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
|Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();

End Application with exclude from Recents

First define an ExitActivity in the AndroidManifest.xml

<activity
android:name="com.your_example_app.activities.ExitActivity"
android:autoRemoveFromRecents="true"
android:theme="@android:style/Theme.NoDisplay" />

Afterwards the ExitActivity-class

/**
* Activity to exit Application without staying in the stack of last opened applications
*/
public class ExitActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

if (Utils.hasLollipop()) {
finishAndRemoveTask();
} else if (Utils.hasJellyBean()) {
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, ExitActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(intent);

https://riptutorial.com/ 45
}
}

Up Navigation for Activities

Up navigation is done in android by adding android:parentActivityName="" in Manifest.xml to the


activity tag. Basically with this tag you tell the system about the parent activity of a activity.

How is it done?

<uses-permission android:name="android.permission.INTERNET" />

<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=".ui.activities.SplashActivity"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>
<activity android:name=".ui.activities.MainActivity" />
<activity android:name=".ui.activities.HomeActivity"
android:parentActivityName=".ui.activities.MainActivity/> // HERE I JUST TOLD THE SYSTEM
THAT MainActivity is the parent of HomeActivity
</application>

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.

public class HomeActivity extends AppCompatActivity {


@BindView(R.id.toolbar)
Toolbar toolbar;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ButterKnife.bind(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);
getSupportActionBar.setDisplayHomeAsUpEnabled(true); // this will show the back arrow
in the tool bar.
}

https://riptutorial.com/ 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 (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this); // Here you will write your logic for handling
up navigation
return true;
}
return super.onOptionsItemSelected(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 android.R.id.home

@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}

Read Activity online: https://riptutorial.com/android/topic/1481/activity

https://riptutorial.com/ 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

This is a just a simple example of how to use GooglePlay Service's ActivityRecognitionApi.


Although this is a great library, it does not work on devices that do not have Google Play Services
installed.

Docs for ActivityRecognition API

Manifest

<!-- This is needed to use Activity Recognition! -->


<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />

<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="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>

<receiver android:name=".ActivityReceiver" />


</application>

MainActivity.java

public class MainActivity extends AppCompatActivity implements


GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

private GoogleApiClient apiClient;


private LocalBroadcastManager localBroadcastManager;
private BroadcastReceiver localActivityReceiver;

https://riptutorial.com/ 48
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
apiClient = new GoogleApiClient.Builder(this)
.addApi(ActivityRecognition.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();

//This just gets the activity intent from the ActivityReceiver class
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localActivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ActivityRecognitionResult recognitionResult =
ActivityRecognitionResult.extractResult(intent);
TextView textView = (TextView) findViewById(R.id.activityText);

//This is just to get the activity name. Use at your own risk.

textView.setText(DetectedActivity.zzkf(recognitionResult.getMostProbableActivity().getType()));

}
};
}

@Override
protected void onResume() {
super.onResume();

//Register local broadcast receiver


localBroadcastManager.registerReceiver(localActivityReceiver, new
IntentFilter("activity"));

//Connect google api client


apiClient.connect();
}

@Override
protected void onPause() {
super.onPause();

//Unregister for activity recognition


ActivityRecognition.ActivityRecognitionApi.removeActivityUpdates(apiClient,
PendingIntent.getBroadcast(this, 0, new Intent(this, ActivityReceiver.class),
PendingIntent.FLAG_UPDATE_CURRENT));

//Disconnects api client


apiClient.disconnect();

//Unregister local receiver


localBroadcastManager.unregisterReceiver(localActivityReceiver);
}

@Override
public void onConnected(@Nullable Bundle bundle) {
//Only register for activity recognition if google api client has connected
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(apiClient, 0,
PendingIntent.getBroadcast(this, 0, new Intent(this, ActivityReceiver.class),
PendingIntent.FLAG_UPDATE_CURRENT));

https://riptutorial.com/ 49
}

@Override
public void onConnectionSuspended(int i) {
}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

}
}

ActivityReceiver

public class ActivityReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {

LocalBroadcastManager.getInstance(context).sendBroadcast(intent.setAction("activity"));
}
}

PathSense Activity Recognition

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 http://developer.pathsense.com 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="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>

<receiver android:name=".ActivityReceiver" />

<!-- You need to acquire these from their website (http://developer.pathsense.com) -->
<meta-data
android:name="com.pathsense.android.sdk.CLIENT_ID"
android:value="YOUR_CLIENT_ID" />
<meta-data
android:name="com.pathsense.android.sdk.API_KEY"
android:value="YOUR_API_KEY" />
</application>

https://riptutorial.com/ 50
MainActivity.java

public class MainActivity extends AppCompatActivity {

private PathsenseLocationProviderApi pathsenseLocationProviderApi;


private LocalBroadcastManager localBroadcastManager;
private BroadcastReceiver localActivityReceiver;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pathsenseLocationProviderApi = PathsenseLocationProviderApi.getInstance(this);

//This just gets the activity intent from the ActivityReceiver class
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localActivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//The detectedActivities object is passed as a serializable
PathsenseDetectedActivities detectedActivities = (PathsenseDetectedActivities)
intent.getSerializableExtra("ps");
TextView textView = (TextView) findViewById(R.id.activityText);

textView.setText(detectedActivities.getMostProbableActivity().getDetectedActivity().name());
}
};
}

@Override
protected void onResume() {
super.onResume();

//Register local broadcast receiver


localBroadcastManager.registerReceiver(localActivityReceiver, new
IntentFilter("activity"));

//This gives an update everytime it receives one, even if it was the same as the last
update
pathsenseLocationProviderApi.requestActivityUpdates(ActivityReceiver.class);

// This gives updates only when it changes (ON_FOOT -> IN_VEHICLE for example)
// pathsenseLocationProviderApi.requestActivityChanges(ActivityReceiver.class);
}

@Override
protected void onPause() {
super.onPause();

pathsenseLocationProviderApi.removeActivityUpdates();

// pathsenseLocationProviderApi.removeActivityChanges();

//Unregister local receiver


localBroadcastManager.unregisterReceiver(localActivityReceiver);
}
}

ActivityReceiver.java

https://riptutorial.com/ 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);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
}

Read Activity Recognition online: https://riptutorial.com/android/topic/9831/activity-recognition

https://riptutorial.com/ 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

A large portion of this topic was split out to adb shell

Remarks
List of examples moved to adb shell:

• Granting & revoking API 23+ permissions


• Send text, key pressed and touch events to Android Device via ADB
• List packages
• Recording the display
• Open Developer Options
• Set Date/Time via adb
• Changing file permissions using chmod command
• Generating a "Boot Complete" broadcast
• Print application data
• View external/secondary storage content
• http://stackoverflow.com/documentation/android/9408/adb-shell/29140/adb-shell
• kill a process inside an Android device

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

List of devices attached


ZX1G425DC6 device usb:336592896X product:shamu model:Nexus_6 device:shamu
013e4e127e59a868 device usb:337641472X product:bullhead model:Nexus_5X device:bullhead
ZX1D229KCN device usb:335592811X product:titan_retde model:XT1068
device:titan_umtsds
A50PL device usb:331592812X

https://riptutorial.com/ 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.

Read device information

Write the following command in your terminal:

adb shell getprop

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:

adb shell getprop ro.product.model

Here are a few interesting pieces of information that you cat get:

• ro.product.model: Model name of the device (e.g. Nexus 6P)


• ro.build.version.sdk: API Level of the device (e.g. 23)
• ro.product.brand: Branding of the device (e.g. Samsung)

Full Example Output

[dalvik.vm.dex2oat-Xms]: [64m]
[dalvik.vm.dex2oat-Xmx]: [512m]
[dalvik.vm.heapsize]: [384m]
[dalvik.vm.image-dex2oat-Xms]: [64m]
[dalvik.vm.image-dex2oat-Xmx]: [64m]
[dalvik.vm.isa.x86.variant]: [dalvik.vm.isa.x86.features=default]
[dalvik.vm.isa.x86_64.features]: [default]
[dalvik.vm.isa.x86_64.variant]: [x86_64]
[dalvik.vm.lockprof.threshold]: [500]
[dalvik.vm.stack-trace-file]: [/data/anr/traces.txt]
[debug.atrace.tags.enableflags]: [0]
[debug.force_rtl]: [0]
[dev.bootcomplete]: [1]
[gsm.current.phone-type]: [1]
[gsm.defaultpdpcontext.active]: [true]
[gsm.network.type]: [UMTS]
[gsm.nitz.time]: [1469106902492]
[gsm.operator.alpha]: [Android]
[gsm.operator.iso-country]: [us]
[gsm.operator.isroaming]: [false]
[gsm.operator.numeric]: [310260]
[gsm.sim.operator.alpha]: [Android]
[gsm.sim.operator.iso-country]: [us]

https://riptutorial.com/ 54
[gsm.sim.operator.numeric]: [310260]
[gsm.sim.state]: [READY]
[gsm.version.ril-impl]: [android reference-ril 1.0]
[init.svc.adbd]: [running]
[init.svc.bootanim]: [stopped]
[init.svc.console]: [running]
[init.svc.debuggerd]: [running]
[init.svc.debuggerd64]: [running]
[init.svc.drm]: [running]
[init.svc.fingerprintd]: [running]
[init.svc.gatekeeperd]: [running]
[init.svc.goldfish-logcat]: [stopped]
[init.svc.goldfish-setup]: [stopped]
[init.svc.healthd]: [running]
[init.svc.installd]: [running]
[init.svc.keystore]: [running]
[init.svc.lmkd]: [running]
[init.svc.logd]: [running]
[init.svc.logd-reinit]: [stopped]
[init.svc.media]: [running]
[init.svc.netd]: [running]
[init.svc.perfprofd]: [running]
[init.svc.qemu-props]: [stopped]
[init.svc.ril-daemon]: [running]
[init.svc.servicemanager]: [running]
[init.svc.surfaceflinger]: [running]
[init.svc.ueventd]: [running]
[init.svc.vold]: [running]
[init.svc.zygote]: [running]
[init.svc.zygote_secondary]: [running]
[net.bt.name]: [Android]
[net.change]: [net.dns2]
[net.dns1]: [10.0.2.3]
[net.dns2]: [10.0.2.4]
[net.eth0.dns1]: [10.0.2.3]
[net.eth0.dns2]: [10.0.2.4]
[net.eth0.gw]: [10.0.2.2]
[net.gprs.local-ip]: [10.0.2.15]
[net.hostname]: [android-5e1af924d72dc578]
[net.qtaguid_enabled]: [1]
[net.tcp.default_init_rwnd]: [60]
[persist.sys.dalvik.vm.lib.2]: [libart.so]
[persist.sys.profiler_ms]: [0]
[persist.sys.timezone]: [Europe/Vienna]
[persist.sys.usb.config]: [adb]
[qemu.gles]: [1]
[qemu.hw.mainkeys]: [0]
[qemu.sf.fake_camera]: [none]
[qemu.sf.lcd_density]: [560]
[rild.libargs]: [-d /dev/ttyS0]
[rild.libpath]: [/system/lib/libreference-ril.so]
[ro.allow.mock.location]: [0]
[ro.baseband]: [unknown]
[ro.board.platform]: []
[ro.boot.hardware]: [ranchu]
[ro.bootimage.build.date]: [Thu Jul 7 15:56:30 UTC 2016]
[ro.bootimage.build.date.utc]: [1467906990]
[ro.bootimage.build.fingerprint]:
[Android/sdk_google_phone_x86_64/generic_x86_64:6.0/MASTER/3038907:userdebug/test-keys]
[ro.bootloader]: [unknown]
[ro.bootmode]: [unknown]

https://riptutorial.com/ 55
[ro.build.characteristics]: [emulator]
[ro.build.date]: [Thu Jul 7 15:55:30 UTC 2016]
[ro.build.date.utc]: [1467906930]
[ro.build.description]: [sdk_google_phone_x86_64-userdebug 6.0 MASTER 3038907 test-keys]
[ro.build.display.id]: [sdk_google_phone_x86_64-userdebug 6.0 MASTER 3038907 test-keys]
[ro.build.fingerprint]:
[Android/sdk_google_phone_x86_64/generic_x86_64:6.0/MASTER/3038907:userdebug/test-keys]
[ro.build.flavor]: [sdk_google_phone_x86_64-userdebug]
[ro.build.host]: [vpak15.mtv.corp.google.com]
[ro.build.id]: [MASTER]
[ro.build.product]: [generic_x86_64]
[ro.build.tags]: [test-keys]
[ro.build.type]: [userdebug]
[ro.build.user]: [android-build]
[ro.build.version.all_codenames]: [REL]
[ro.build.version.base_os]: []
[ro.build.version.codename]: [REL]
[ro.build.version.incremental]: [3038907]
[ro.build.version.preview_sdk]: [0]
[ro.build.version.release]: [6.0]
[ro.build.version.sdk]: [23]
[ro.build.version.security_patch]: [2015-10-01]
[ro.com.google.locationfeatures]: [1]
[ro.config.alarm_alert]: [Alarm_Classic.ogg]
[ro.config.nocheckin]: [yes]
[ro.config.notification_sound]: [OnTheHunt.ogg]
[ro.crypto.state]: [unencrypted]
[ro.dalvik.vm.native.bridge]: [0]
[ro.debuggable]: [1]
[ro.hardware]: [ranchu]
[ro.hardware.audio.primary]: [goldfish]
[ro.kernel.android.checkjni]: [1]
[ro.kernel.android.qemud]: [1]
[ro.kernel.androidboot.hardware]: [ranchu]
[ro.kernel.clocksource]: [pit]
[ro.kernel.console]: [0]
[ro.kernel.ndns]: [2]
[ro.kernel.qemu]: [1]
[ro.kernel.qemu.gles]: [1]
[ro.opengles.version]: [131072]
[ro.product.board]: []
[ro.product.brand]: [Android]
[ro.product.cpu.abi]: [x86_64]
[ro.product.cpu.abilist]: [x86_64,x86]
[ro.product.cpu.abilist32]: [x86]
[ro.product.cpu.abilist64]: [x86_64]
[ro.product.device]: [generic_x86_64]
[ro.product.locale]: [en-US]
[ro.product.manufacturer]: [unknown]
[ro.product.model]: [Android SDK built for x86_64]
[ro.product.name]: [sdk_google_phone_x86_64]
[ro.radio.use-ppp]: [no]
[ro.revision]: [0]
[ro.runtime.firstboot]: [1469106908722]
[ro.secure]: [1]
[ro.serialno]: []
[ro.wifi.channels]: []
[ro.zygote]: [zygote64_32]
[selinux.reload_policy]: [1]
[service.bootanim.exit]: [1]
[status.battery.level]: [5]

https://riptutorial.com/ 56
[status.battery.level_raw]: [50]
[status.battery.level_scale]: [9]
[status.battery.state]: [Slow]
[sys.boot_completed]: [1]
[sys.sysctl.extra_free_kbytes]: [43200]
[sys.sysctl.tcp_def_init_rwnd]: [60]
[sys.usb.config]: [adb]
[sys.usb.state]: [adb]
[vold.has_adoptable]: [1]
[wlan.driver.status]: [unloaded]
[xmpp.auto-presence]: [true]

Connect ADB to a device via WiFi

The standard ADB configuration involves a USB connection to a physical device.


If you prefer, you can switch over to TCP/IP mode, and connect ADB via WiFi instead.

Not rooted device


1. Get on the same network:

• Make sure your device and your computer are on the same network.

2. Connect the device to the host computer with a USB cable.

3. Connect adb to device over 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):

• Type adb tcpip <port> (switch to TCP/IP mode).


• Disconnect the USB cable from the target device.
• Type adb connect <ip address>:<port> (port is optional; default 5555).

For example:

adb tcpip 5555


adb connect 192.168.0.101:5555

If you don't know your device's IP you can:

• check the IP in the WiFi settings of your device.


• use ADB to discover IP (via USB):
1. Connect the device to the computer via USB
2. In a command line, type adb shell ifconfig and copy your device's IP address

To revert back to debugging via USB use the following command:

adb usb

https://riptutorial.com/ 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

The process is explained in detail in the following answer:


http://stackoverflow.com/questions/2604727/how-can-i-connect-to-android-with-adb-over-
tcp/3623727#3623727 The most important commands are shown below.

Open a terminal in the device and type the following:

su
setprop service.adb.tcp.port <a tcp port number>
stop adbd
start adbd

For example:

setprop service.adb.tcp.port 5555

And on your computer:

adb connect <ip address>:<a tcp port number>

For example:

adb connect 192.168.1.2:5555

To turn it off:

setprop service.adb.tcp.port -1

https://riptutorial.com/ 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.

A simple change in the Gradle configuration can do the trick:

android {
adbOptions {
timeOutInMs 10 * 1000
}
}

Pull (push) files from (to) the device

You may pull (download) files from the device by executing the following command:

adb pull <remote> <local>

For example:

adb pull /sdcard/ ~/

You may also push (upload) files from your computer to the device:

adb push <local> <remote>

For example:

adb push ~/image.jpg /sdcard/

Example to Retrieve Database from device

sudo adb -d shell "run-as com.example.name cat /data/da/com.example.name


/databases/DATABASE_NAME > /sdcard/file

Reboot device

You can reboot your device by executing the following command:

adb reboot

Perform this command to reboot into bootloader:

https://riptutorial.com/ 59
adb reboot bootloader

Reboot to recovery mode:

adb reboot recovery

Be aware that the device won't shutdown first!

Turn on/off Wifi

Turn on:

adb shell svc wifi enable

Turn off:

adb shell svc wifi disable

View available devices

Command:

adb devices

Result example:

List of devices attached


emulator-5554 device
PhoneRT45Fr54 offline
123.454.67.45 no device

First column - device serial number

Second column - connection status

Android documentation

Connect device by IP

Enter these commands in Android device Terminal

su
setprop service.adb.tcp.port 5555
stop adbd
start adbd

After this, you can use CMD and ADB to connect using the following command

https://riptutorial.com/ 60
adb connect 192.168.0.101.5555

And you can disable it and return ADB to listening on USB with

setprop service.adb.tcp.port -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

adb tcpip 5555


adb connect 192.168.0.101:5555

Replace 192.168.0.101 with device IP

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

One useful command is:

adb logcat -v threadtime

This displays the date, invocation time, priority, tag, and the PID and TID of the thread issuing the
message in a long message format.

https://riptutorial.com/ 61
Filtering

Logcat logs got so called log levels:

V — Verbose, D — Debug, I — Info, W — Warning, E — Error, F — Fatal, S — Silent

You can filter logcat by log level as well. For instance if you want only to output Debug level:

adb logcat *:D

Logcat can be filtered by a package name, of course you can combine it with the log level filter:

adb logcat <package-name>:<log level>

You can also filter the log using grep (more on filtering logcat output here):

adb logcat | grep <some text>

In Windows, filter can be used using findstr, for example:

adb logcat | findstr <some text>

To view alternative log buffer [main|events|radio], run the logcat with the -b option:

adb logcat -b radio

Save output in file :

adb logcat > logcat.txt

Save output in file while also watching it:

adb logcat | tee logcat.txt

Cleaning the logs:

adb logcat -c

Direct ADB command to specific device in a multi-device setting

1. Target a device by serial number

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.

adb -s <device> <command>

https://riptutorial.com/ 62
Example:

adb devices

List of devices attached


emulator-5554 device
02157df2d1faeb33 device

adb -s emulator-5554 shell

Example#2:

adb devices -l

List of devices attached


06157df65c6b2633 device usb:1-3 product:zerofltexx model:SM_G920F device:zeroflte
LC62TB413962 device usb:1-5 product:a50mgp_dug_htc_emea model:HTC_Desire_820G_dual_sim
device:htc_a50mgp_dug

adb -s usb:1-3 shell

2. Target a device, when only one device type is connected

You can target the only running emulator with -e

adb -e <command>

Or you can target the only connected USB device with -d

adb -d <command>

Taking a screenshot and video (for kitkat only) from a device display

Screen shot: Option 1 (pure adb)


The shell adb command allows us to execute commands using a device's built-in shell. The
screencap shell command captures the content currently visible on a device and saves it into a
given image file, e.g. /sdcard/screen.png:

adb shell screencap /sdcard/screen.png

You can then use the pull command to download the file from the device into the current directory
on you computer:

adb pull /sdcard/screen.png

Screen shot:Option 2 (faster)


https://riptutorial.com/ 63
Execute the following one-liner:

(Marshmallow and earlier):

adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png

(Nougat and later):

adb shell screencap -p > screen.png

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 screen.png 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.

Clear application data

One can clear the user data of a specific app using adb:

adb shell pm clear <package>

This is the same as to browse the settings on the phone, select the app and press on the clear
data button.

• pm invokes the package manager on the device


• clear deletes all data associated with a package

Sending broadcast

https://riptutorial.com/ 64
It's possible to send broadcast to BroadcastReceiver with adb.

In this example we are sending broadcast with action com.test.app.ACTION and string extra in
bundle 'foo'='bar':

adb shell am broadcast -a action com.test.app.ACTION --es 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 ',')

To send intent to specific package/class -n or -p parameter can be used.


Sending to package:

-p com.test.app

Sending to a specific component (SomeReceiver class in com.test.app package):

-n com.test.app/.SomeReceiver

Useful examples:

• Sending a "boot complete" broadcast


• Sending a "time changed" broadcast after setting time via adb command

Install and run an application

To install an APK file, use the following command:

adb install path/to/apk/file.apk

or if the app is existing and we want to reinstall

adb install -r path/to/apk/file.apk

To uninstall an application, we have to specify its package

adb uninstall application.package.name

https://riptutorial.com/ 65
Use the following command to start an app with a provided package name (or a specific activity in
an app):

adb shell am start -n adb shell am start <package>/<activity>

For example, to start Waze:

adb shell am start -n adb shell am start com.waze/com.waze.FreeMapAppActivity

Backup

You can use the adb backup command to backup your device.

adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all]


[-system|nosystem] [<packages...>]

-f <filename> specify filename default: creates backup.ab in the current directory

-apk|noapk enable/disable backup of .apks themself default: -noapk

-obb|noobb enable/disable backup of additional files default: -noobb

-shared|noshared backup device's shared storage / SD card contents default: -noshared

-all backup all installed apllications

-system|nosystem include system applications default: -system

<packages> a list of packages to be backed up (e.g. com.example.android.myapp) (not needed if -


all is specified)

For a full device backup, including everything, use

adb backup -apk -obb -shared -all -system -f fullbackup.ab

Note: Doing a full backup can take a long time.

In order to restore a backup, use

adb restore backup.ab

Install ADB on Linux system

How to install the Android Debugging Bridge (ADB) to a Linux system with the terminal using your
distro's repositories.

Install to Ubuntu/Debian system via apt:

https://riptutorial.com/ 66
sudo apt-get update
sudo apt-get install adb

Install to Fedora/CentOS system via yum:

sudo yum check-update


sudo yum install android-tools

Install to Gentoo system with portage:

sudo emerge --ask dev-util/android-tools

Install to openSUSE system with zypper:

sudo zypper refresh


sudo zypper install android-tools

Install to Arch system with pacman:

sudo pacman -Syyu


sudo pacman -S android-tools

List all permissions that require runtime grant from users on Android 6.0

adb shell pm list permissions -g -d

View an app's internal data (data/data/) on a device

First, make sure your app can be backed up in AndroidManifest.xml, i.e. android:allowBackup is not
false.

Backup command:

adb -s <device_id> backup -noapk <sample.package.id>

Create a tar with dd command:

dd if=backup.ab bs=1 skip=24 | python -c "import


zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))" > backup.tar

Extract the tar:

tar -xvf backup.tar

You may then view the extracted content.

View activity stack

https://riptutorial.com/ 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'"

View and pull cache files of an app

You may use this command for listing the files for your own debuggable apk:

adb shell run-as <sample.package.id> ls /data/data/sample.package.id/cache

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 <sample.package.id> cat '/data/data/<sample.package.id>/$1' > '/sdcard/$1'"
adb pull "/sdcard/$1"
adb shell "rm '/sdcard/$1'"

Then you can pull a file from cache like this:

./pull.sh cache/someCachedData.txt

Get Database file via ADB

sudo adb -d shell "run-as com.example.name cat /data/da/com.example.name


/databases/STUDENT_DATABASE > /sdcard/file

Read ADB (Android Debug Bridge) online: https://riptutorial.com/android/topic/1051/adb--android-


debug-bridge-

https://riptutorial.com/ 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

-e choose escape character, or "none"; default '~'

-n don't read from stdin

-T disable PTY allocation

-t force PTY allocation

-x disable remote exit codes and stdout/stderr separation

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

Send text on SDK 23+

adb shell "input keyboard text 'Paste text on Android Device'"

If already connected to your device via adb:

input text 'Paste text on Android Device'

6.0

https://riptutorial.com/ 69
Send text prior to SDK 23

adb shell "input keyboard text 'Paste%stext%son%sAndroid%sDevice'"

Spaces are not accepted as the input, replace them with %s.

Send events

To simulate pressing the hardware power key

adb shell input keyevent 26

or alternatively

adb shell input keyevent POWER

Even if you don't have a hardware key you still can use a keyevent to perform the equivalent action

adb shell input keyevent CAMERA

Send touch event as input

adb shell input tap Xpoint Ypoint

Send swipe event as input

adb shell input swipe Xpoint1 Ypoint1 Xpoint2 Ypoint2 [DURATION*]

*DURATION is optional, default=300ms. source

Get X and Y points by enabling pointer location in developer option.

ADB sample shell script

To run a script in Ubuntu, Create script.sh right click the file and add read/write
permission and tick allow executing file as program.

Open terminal emulator and run the command ./script.sh

Script.sh

for (( c=1; c<=5; c++ ))


do
adb shell input tap X Y
echo "Clicked $c times"
sleep 5s
done

For a comprehensive list of event numbers

https://riptutorial.com/ 70
• shortlist of several interesting events ADB Shell Input Events
• reference documentation
https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_POWER.

List packages

Prints all packages, optionally only those whose package name contains the text in <FILTER>.

adb shell pm list packages [options] <FILTER>

All <FILTER>

adb shell pm list packages

Attributes:

-f to see their associated file.

-i See the installer for the packages.

-u to also include uninstalled packages.

-u Also include uninstalled packages.

Attributes that filter:

-d for disabled packages.

-e for enabled packages.

-s for system packages.

-3 for third party packages.

--user <USER_ID> for a specific user space to query.

Granting & revoking API 23+ permissions

A one-liner that helps granting or revoking vulnerable permissions.

• granting

adb shell pm grant <sample.package.id> android.permission.<PERMISSION_NAME>

• revoking

adb shell pm revoke <sample.package.id> android.permission.<PERMISSION_NAME>

• Granting all run-time permissions at a time on installation (-g)

https://riptutorial.com/ 71
adb install -g /path/to/sample_package.apk

Print application data

This command print all relevant application data:

• version code
• version name
• granted permissions (Android API 23+)
• etc..

adb shell dumpsys package <your.package.id>

Recording the display

4.4

Recording the display of devices running Android 4.4 (API level 19) and higher:

adb shell screenrecord [options] <filename>


adb shell screenrecord /sdcard/demo.mp4

(press Ctrl-C to stop recording)

Download the file from the device:

adb pull /sdcard/demo.mp4

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.

adb shell screenrecord --size <WIDTHxHEIGHT>

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.

adb shell screenrecord --bit-rate <RATE>

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:

adb shell screenrecord --bit-rate 5000000 /sdcard/demo.mp4

https://riptutorial.com/ 72
adb shell screenrecord --time-limit <TIME>

Sets the maximum recording time, in seconds. The default and maximum value is 180 (3 minutes).

adb shell screenrecord --rotate

Rotates the output 90 degrees. This feature is experimental.

adb shell screenrecord --verbose

Displays log information on the command-line screen. If you do not set this option, the utility does
not display any information while running.

Note: This might not work on some devices.

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.

Changing file permissions using chmod command

Notice, that in order to change file prmissions, your device need to be rooted, su binary
doesn't come with factory shipped devices!

Convention:

adb shell su -c "chmod <numeric-permisson> <file>"

Numeric permission constructed from user, group and world sections.

For example, if you want to change file to be readable, writable and executable by everyone, this
will be your command:

adb shell su -c "chmod 777 <file-path>"

Or

adb shell su -c "chmod 000 <file-path>"

if you intent to deny any permissions to it.

1st digit-specifies user permission, 2nd digit- specifies group permission, 3rd digit - specifies
world (others) permission.

https://riptutorial.com/ 73
Access permissions:

--- : binary value: 000, octal value: 0 (none)


--x : binary value: 001, octal value: 1 (execute)
-w- : binary value: 010, octal value: 2 (write)
-wx : binary value: 011, octal value: 3 (write, execute)
r-- : binary value: 100, octal value: 4 (read)
r-x : binary value: 101, octal value: 5 (read, execute)
rw- : binary value: 110, octal value: 6 (read, write)
rwx : binary value: 111, octal value: 7 (read, write, execute)

Set Date/Time via adb

6.0

Default SET format is MMDDhhmm[[CC]YY][.ss], that's (2 digits each)

For example, to set July 17'th 10:10am, without changing the current year, type:

adb shell 'date 07171010.00'

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:

adb shell 'date 07171010.00 ; am broadcast -a android.intent.action.TIME_SET'

Tip 2: to synchronize Android's clock with your local machine:

Linux:

adb shell date `date +%m%d%H%M%G.%S`

Windows (PowerShell):

$currentDate = Get-Date -Format "MMddHHmmyyyy.ss" # Android's preferred format


adb shell "date $currentDate"

Both tips together:

adb shell 'date `date +%m%d%H%M%G.%S` ; am broadcast -a android.intent.action.TIME_SET'

6.0

Default SET format is 'YYYYMMDD.HHmmss'

adb shell 'date -s 20160117.095930'

Tip: to synchronize Android's clock with your local (linux based) machine:

https://riptutorial.com/ 74
adb shell date -s `date +%G%m%d.%H%M%S`

Open Developer Options

adb shell am start -n com.android.settings/.DevelopmentSettings

Will navigate your device/emulator to the Developer Options section.

Generating a "Boot Complete" broadcast

This is relevant for apps that implement a BootListener. Test your app by killing your app and then
test with:

adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -c android.intent.category.HOME


-n your.app/your.app.BootListener

(replace your.package/your.app.BootListener with proper values).

View external/secondary storage content

View content:

adb shell ls \$EXTERNAL_STORAGE


adb shell ls \$SECONDARY_STORAGE

View path:

adb shell echo \$EXTERNAL_STORAGE


adb shell echo \$SECONDARY_STORAGE

kill a process inside an Android device

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

03-10 11:41:40.010 1550-1627/? E/SomeProcess: ....

notice the process number: 1550

Now we can open a shell and kill the process. Note that we cannot kill root process.

adb shell

https://riptutorial.com/ 75
inside the shell we can check more about the process using

ps -x | grep 1550

and kill it if we want:

kill -9 1550

Read adb shell online: https://riptutorial.com/android/topic/9408/adb-shell

https://riptutorial.com/ 76
Chapter 10: Adding a FuseView to an Android
Project
Introduction
Export a Fuse.View 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.

Final work can be found @lucamtudor/hikr-fuse-view

Examples
hikr app, just another android.view.View

Prerequisites

• you should have fuse installed (https://www.fusetools.com/downloads)


• you should have done the introduction tutorial
• in terminal: fuse install android
• in terminal: uno install Fuse.Views

Step 1

git clone https://github.com/fusetools/hikr

Step 2 : Add package reference to Fuse.Views

Find hikr.unoproj file inside the project root folder and add "Fuse.Views" to the "Packages" array.

{
"RootNamespace":"",
"Packages": [
"Fuse",
"FuseJS",
"Fuse.Views"
],
"Includes": [
"*",
"Modules/*.js:Bundle"
]
}

Step 3 : Make HikrApp component to hold the entire app

https://riptutorial.com/ 77
3.1 In the project root folder make a new file called HikrApp.ux and paste the contents of
MainView.ux.

HikrApp.ux

<App Background="#022328">
<iOS.StatusBarConfig Style="Light" />
<Android.StatusBarConfig Color="#022328" />

<Router ux:Name="router" />

<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 HikrApp.ux

• replace the <App> tags with <Page>


• add ux:Class="HikrApp" to the opening <Page>
• remove <ClientPanel>, we don't have to worry anymore about the status bar or the bottom
nav buttons

HikrApp.ux

<Page ux:Class="HikrApp" Background="#022328">


<iOS.StatusBarConfig Style="Light" />
<Android.StatusBarConfig Color="#022328" />

<Router ux:Name="router" />

<Navigator DefaultPath="splash">
<SplashPage ux:Template="splash" router="router" />
<HomePage ux:Template="home" router="router" />
<EditHikePage ux:Template="editHike" router="router" />
</Navigator>
</Page>

3.3 Use the newly created HikrApp component inside MainView.ux

Replace the content of MainView.ux file with:

<App>
<HikrApp/>
</App>

Our app is back to its normal behavior, but we now have extracted it to a separate component
called HikrApp

https://riptutorial.com/ 78
Step 4 Inside MainView.ux 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.

Note. From the fuse docs:

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?

Step 5 Wrap SplashPage.ux's <DockPanel> in a <GraphicsView>

<Page ux:Class="SplashPage">
<Router ux:Dependency="router" />

<JavaScript File="SplashPage.js" />

<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>

<hikr.Text Dock="Bottom" Margin="10" Opacity=".5" TextAlignment="Center"


FontSize="12">original video by Graham Uhelski</hikr.Text>

<Grid RowCount="2">
<StackPanel Alignment="VerticalCenter">
<hikr.Text Alignment="HorizontalCenter" FontSize="70">hikr</hikr.Text>
<hikr.Text Alignment="HorizontalCenter" Opacity=".5">get out
there</hikr.Text>
</StackPanel>

<hikr.Button Text="Get Started" FontSize="18" Margin="50,0"


Alignment="VerticalCenter" Clicked="{goToHomePage}" />
</Grid>
</DockPanel>
</GraphicsView>
</Page>

https://riptutorial.com/ 79
Step 6 Export the fuse project as an aar library

• in terminal, in root project folder: uno clean


• in terminal, in root project folder: uno build -t=android -DLIBRARY

Step 7 Prepare your android project

• copy the aar from .../rootHikeProject/build/Android/Debug/app/build/outputs/aar/app-


debug.aar to .../androidRootProject/app/libs
• add flatDir { dirs 'libs' } to the root build.gradle file

// Top-level build file where you can add configuration options common to all sub-
projects/modules.

buildscript { ... }

...

allprojects {
repositories {
jcenter()
flatDir {
dirs 'libs'
}
}
}

...

• add compile(name: 'app-debug', ext: 'aar') to dependencies in app/build.gradle

apply plugin: 'com.android.application'

android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.shiftstudio.fuseviewtest"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile(name: 'app-debug', ext: 'aar')

https://riptutorial.com/ 80
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
}

• add the following properties to the activity inside AndroidManifest.xml

android:launchMode="singleTask"
android:taskAffinity=""
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize"

Your AndroidManifest.xml will look like this:

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.shiftstudio.fuseviewtest">

<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="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>
</application>

</manifest>

Step 8: Show the Fuse.View HikrAppView in your Activity

• note that your Activity needs to inherit FuseViewsActivity

public class MainActivity extends FuseViewsActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

final ViewHandle fuseHandle = ExportedViews.instantiate("HikrAppView");

https://riptutorial.com/ 81
final FrameLayout root = (FrameLayout) findViewById(R.id.fuse_root);
final View fuseApp = fuseHandle.getView();
root.addView(fuseApp);
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
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="com.shiftstudio.fuseviewtest.MainActivity">

<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
(io.fuseviewtest)

https://riptutorial.com/ 82
[ 05-25 11:52:33.658 16567:16567 W/ ]

debuggerd: handling request: pid=18026 uid=10236 gid=10236 tid=18026

And the final result is something like this. You can also find a short clip on github.

https://riptutorial.com/ 83
https://riptutorial.com/ 84
https://riptutorial.com/android/topic/10052/adding-a-fuseview-to-an-android-project

https://riptutorial.com/ 85
Chapter 11: AdMob
Syntax
• compile 'com.google.firebase:firebase-ads:10.2.1' //NOTE: SET TO NEWEST VERSION IF
AVAILABLE
• <uses-permission android:name="android.permission.INTERNET" /> Required to retrieve the ad
• AdRequest adRequest = new AdRequest.Builder().build();//Banner ad
• AdView mAdView = (AdView) findViewById(R.id.adView);//Banner ad
• mAdView.loadAd(adRequest);//Banner ad

Parameters

Param Details

The ID of your ad. Get your ID from the admob


site. "While it's not a requirement, storing your ad
unit ID values in a resource file is a good practice.
As your app grows and your ad publishing needs
ads:adUnitId="@string/main_screen_ad"
mature, it may be necessary to change the ID
values. If you keep them in a resource file, you
never have to search through your code looking
for them.".[1]

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.

Build.gradle on app level


Change to the latest version if existing:

compile 'com.google.firebase:firebase-ads:10.2.1'

https://riptutorial.com/ 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:

<uses-permission android:name="android.permission.INTERNET" />

XML
The following XML example shows a banner ad:

<com.google.android.gms.ads.AdView
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:

// Alternative for faster initialization.


// MobileAds.initialize(getApplicationContext(), "AD_UNIT_ID");

AdView mAdView = (AdView) findViewById(R.id.adView);


// Add your device test ID if you are doing testing before releasing.
// The device test ID can be found in the admob stacktrace.
AdRequest adRequest = new AdRequest.Builder().build();
mAdView.loadAd(adRequest);

Add the AdView life cycle methods in the onResume(), onPause(), and onDestroy() methods of your
activity:

@Override
public void onPause() {
if (mAdView != null) {
mAdView.pause();
}
super.onPause();
}

@Override
public void onResume() {
super.onResume();

https://riptutorial.com/ 87
if (mAdView != null) {
mAdView.resume();
}
}

@Override
public void onDestroy() {
if (mAdView != null) {
mAdView.destroy();
}
super.onDestroy();
}

Read AdMob online: https://riptutorial.com/android/topic/5334/admob

https://riptutorial.com/ 88
Chapter 12: AIDL
Introduction
AIDL is Android interface definition language.

What? Why? How ?

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

ICalculator.aidl

// Declare any non-default types here with import statements

interface ICalculator {
int add(int x,int y);
int sub(int x,int y);
}

AidlService.java

public class AidlService extends Service {

private static final String TAG = "AIDLServiceLogs";


private static final String className = " AidlService";

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 iCalculator.asBinder();
}

@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, className+" onCreate");

https://riptutorial.com/ 89
}

@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, className+" onDestroy");
}

ICalculator.Stub iCalculator = new ICalculator.Stub() {


@Override
public int add(int x, int y) throws RemoteException {
Log.i(TAG, className+" add Thread Name: "+Thread.currentThread().getName());
int z = x+y;
return z;
}

@Override
public int sub(int x, int y) throws RemoteException {
Log.i(TAG, className+" add Thread Name: "+Thread.currentThread().getName());
int z = x-y;
return z;
}
};

Service Connection

// Return the stub as interface


ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, className + " onServiceConnected");
iCalculator = ICalculator.Stub.asInterface(service);
}

@Override
public void onServiceDisconnected(ComponentName name) {

unbindService(serviceConnection);
}
};

Read AIDL online: https://riptutorial.com/android/topic/9504/aidl

https://riptutorial.com/ 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.

public class AlarmReceiver extends BroadcastReceiver


{
@Override
public void onReceive(Context context, Intent intent)
{
// Handle intent
int reqCode = intent.getExtras().getInt("requestCode");
...
}
}

2. Give an intent to AlarmManager. This example will trigger the intent to be sent to
AlarmReceiver after 1 minute.

final int requestCode = 1337;


AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.set( AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 60000 , pendingIntent );

How to Cancel an Alarm

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.

An Intent is considered equal by the AlarmManager:

if their action, data, type, class, and categories are the same. This does not compare
any extra data included in the intents.

Usually the request code for each alarm is defined as a constant:

public static final int requestCode = 9999;

So, for a simple alarm set up like this:

Intent intent = new Intent(this, AlarmReceiver.class);


intent.setAction("SomeAction");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, requestCode, intent,

https://riptutorial.com/ 91
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.setExact(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:

Intent intent = new Intent(this, AlarmReceiver.class);


intent.setAction("SomeAction");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, requestCode, intent,
PendingIntent.FLAG_NO_CREATE);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
if(pendingIntent != null) {
alarmManager.cancel(pendingIntent);
}

Creating exact alarms on all Android versions

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:

public static void setExactAndAllowWhileIdle(AlarmManager alarmManager, int type, long


triggerAtMillis, PendingIntent operation) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M){
alarmManager.setExactAndAllowWhileIdle(type, triggerAtMillis, operation);
} else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
alarmManager.setExact(type, triggerAtMillis, operation);
} else {
alarmManager.set(type, triggerAtMillis, operation);
}
}

API23+ Doze mode interferes with AlarmManager

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)

Inside your app you can check this setting ...

String packageName = getPackageName();


PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm.isIgnoringBatteryOptimizations(packageName)) {
// your app is ignoring Doze battery optimization
}

https://riptutorial.com/ 92
... and eventually show the respective settings dialog:

Intent intent = new Intent();


String packageName = getPackageName();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);

Read AlarmManager online: https://riptutorial.com/android/topic/1361/alarmmanager

https://riptutorial.com/ 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 build.gradle

allprojects {
repositories {
jcenter()
// Add this if you use Gradle 4.0+
google()
// Add this if you use Gradle < 4.0
maven { url 'https://maven.google.com' }
}
}

ext {
archVersion = '1.0.0-alpha5'
}

Application build gradle

// For Lifecycles, LiveData, and ViewModel


compile "android.arch.lifecycle:runtime:$archVersion"
compile "android.arch.lifecycle:extensions:$archVersion"
annotationProcessor "android.arch.lifecycle:compiler:$archVersion"

// For Room
compile "android.arch.persistence.room:runtime:$archVersion"
annotationProcessor "android.arch.persistence.room:compiler:$archVersion"

// For testing Room migrations


testCompile "android.arch.persistence.room:testing:$archVersion"

// For Room RxJava support


compile "android.arch.persistence.room:rxjava2:$archVersion"

Using Lifecycle in AppCompatActivity

Extend your activity from this activity

https://riptutorial.com/ 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;
}
}

ViewModel with LiveData transformations

public class BaseViewModel extends ViewModel {


private static final int TAG_SEGMENT_INDEX = 2;
private static final int VIDEOS_LIMIT = 100;

// We save input params here


private final MutableLiveData<Pair<String, String>> urlWithReferrerLiveData = new
MutableLiveData<>();

// transform specific uri param to "tag"


private final LiveData<String> currentTagLiveData =
Transformations.map(urlWithReferrerLiveData, pair -> {
Uri uri = Uri.parse(pair.first);
List<String> segments = uri.getPathSegments();
if (segments.size() > TAG_SEGMENT_INDEX)
return segments.get(TAG_SEGMENT_INDEX);
return null;
});

// transform "tag" to videos list


private final LiveData<List<VideoItem>> videoByTagData =
Transformations.switchMap(currentTagLiveData, tag -> contentRepository.getVideoByTag(tag,
VIDEOS_LIMIT));

ContentRepository contentRepository;

public BaseViewModel() {
// some inits
}

public void setUrlWithReferrer(String url, String referrer) {


// set value activates observers and transformations
urlWithReferrerLiveData.setValue(new Pair<>(url, referrer));
}

public LiveData<List<VideoItem>> getVideoByTagData() {


return videoByTagData;
}
}

Somewhere in UI:

https://riptutorial.com/ 95
public class VideoActivity extends BaseCompatLifecycleActivity {
private VideoViewModel viewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Get ViewModel
viewModel = ViewModelProviders.of(this).get(BaseViewModel.class);
// Add observer
viewModel.getVideoByTagData().observe(this, data -> {
// some checks
adapter.updateData(data);
});

...
if (savedInstanceState == null) {
// init loading only at first creation
// you just set params and
viewModel.setUrlWithReferrer(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

// Set custom table name, add indexes


@Entity(tableName = "videos",
indices = {@Index("title")}
)
public final class VideoItem {
@PrimaryKey // required
public long articleId;
public String title;
public String url;
}

// Use ForeignKey for setup table relation


@Entity(tableName = "tags",
indices = {@Index("score"), @Index("videoId"), @Index("value")},
foreignKeys = @ForeignKey(entity = VideoItem.class,
parentColumns = "articleId",
childColumns = "videoId",
onDelete = ForeignKey.CASCADE)
)
public final class VideoTag {
@PrimaryKey
public long id;
public long videoId;
public String displayName;
public String value;
public double score;
}

https://riptutorial.com/ 96
DAO classes

@Dao
public interface VideoDao {
// Create insert with custom conflict strategy
@Insert(onConflict = OnConflictStrategy.REPLACE)
void saveVideos(List<VideoItem> videos);

// Simple update
@Update
void updateVideos(VideoItem... videos);

@Query("DELETE FROM tags WHERE videoId = :videoId")


void deleteTagsByVideoId(long videoId);

// Custom query, you may use select/delete here


@Query("SELECT v.* FROM tags t LEFT JOIN videos v ON v.articleId = t.videoId WHERE t.value
= :tag ORDER BY updatedAt DESC LIMIT :limit")
LiveData<List<VideoItem>> getVideosByTag(String tag, int limit);
}

Database class

// register your entities and DAOs


@Database(entities = {VideoItem.class, VideoTag.class}, version = 2)
public abstract class ContentDatabase extends RoomDatabase {
public abstract VideoDao videoDao();
}

Migrations

public final class Migrations {


private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
final String[] sqlQueries = {
"CREATE TABLE IF NOT EXISTS `tags` (`id` INTEGER PRIMARY KEY
AUTOINCREMENT," +
" `videoId` INTEGER, `displayName` TEXT, `value` TEXT, `score`
REAL," +
" FOREIGN KEY(`videoId`) REFERENCES `videos`(`articleId`)" +
" ON UPDATE NO ACTION ON DELETE CASCADE )",
"CREATE INDEX `index_tags_score` ON `tags` (`score`)",
"CREATE INDEX `index_tags_videoId` ON `tags` (`videoId`)"};
for (String query : sqlQueries) {
database.execSQL(query);
}
}
};

public static final Migration[] ALL = {MIGRATION_1_2};

private Migrations() {
}
}

Use in Application class or provide via Dagger

https://riptutorial.com/ 97
ContentDatabase provideContentDatabase() {
return Room.databaseBuilder(context, ContentDatabase.class, "data.db")
.addMigrations(Migrations.ALL).build();
}

Write your repository:

public final class ContentRepository {


private final ContentDatabase db;
private final VideoDao videoDao;

public ContentRepository(ContentDatabase contentDatabase, VideoDao videoDao) {


this.db = contentDatabase;
this.videoDao = videoDao;
}

public LiveData<List<VideoItem>> getVideoByTag(@Nullable String tag, int limit) {


// you may fetch from network, save to database
....
return videoDao.getVideosByTag(tag, limit);
}
}

Use in ViewModel:

ContentRepository contentRepository = ...;


contentRepository.getVideoByTag(tag, limit);

Custom LiveData

You may write custom LiveData, if you need custom logic.


Don't write custom class, if you only need to transform data (use Transformations class)

public class LocationLiveData extends LiveData<Location> {


private LocationManager locationManager;

private LocationListener listener = new LocationListener() {


@Override
public void onLocationChanged(Location location) {
setValue(location);
}

@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
}

https://riptutorial.com/ 98
};

public LocationLiveData(Context context) {


locationManager = (LocationManager)
context.getSystemService(Context.LOCATION_SERVICE);
}

@Override
protected void onActive() {
// We have observers, start working
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
}

@Override
protected void onInactive() {
// We have no observers, stop working
locationManager.removeUpdates(listener);
}
}

Custom Lifecycle-aware component

Each UI component lifecycle changed as shown at image.

You may create component, that will be notified on lifecycle state change:

public class MyLocationListener implements LifecycleObserver {


private boolean enabled = false;
private Lifecycle lifecycle;
public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
...
}

@OnLifecycleEvent(Lifecycle.Event.ON_START)
void start() {

https://riptutorial.com/ 99
if (enabled) {
// connect
}
}

public void enable() {


enabled = true;
if (lifecycle.getState().isAtLeast(STARTED)) {
// connect if not connected
}
}

@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void stop() {
// disconnect if connected
}
}

Read Android Architecture Components online: https://riptutorial.com/android/topic/10872/android-


architecture-components

https://riptutorial.com/ 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:

• A service, triggered by the android.accounts.AccountAuthenticator. Its onBind method should


return a subclass of AbstractAccountAuthenticator.
• An activity to prompt the user for credentials (Login activity)
• An xml resource file to describe the account

1. The service:

Place the following permissions in your AndroidManifest.xml:

<uses-permission android:name="android.permission.GET_ACCOUNTS" />


<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />

Declare the service in the manifest file:

<service android:name="com.example.MyAuthenticationService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>

Note that the android.accounts.AccountAuthenticator is included within the intent-filter tag. The
xml resource (named authenticator here) is specified in the meta-data tag.

The service class:

public class MyAuthenticationService extends Service {

private static final Object lock = new Object();


private MyAuthenticator mAuthenticator;

public MyAuthenticationService() {
super();
}

@Override
public void onCreate() {
super.onCreate();

https://riptutorial.com/ 101
synchronized (lock) {
if (mAuthenticator == null) {
mAuthenticator = new MyAuthenticator(this);
}
}
}

@Override
public IBinder onBind(Intent intent) {
return mAuthenticator.getIBinder();
}

2. The xml resource:

<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.example.account"
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.

3. Extend the AbstractAccountAuthenticator class:

public class MyAuthenticator extends AbstractAccountAuthenticator {

private Context mContext;

public MyAuthenticator(Context context) {


super(context);
mContext = context;
}

@Override
public Bundle addAccount(AccountAuthenticatorResponse response,
String accountType,
String authTokenType,
String[] requiredFeatures,
Bundle options) throws NetworkErrorException {

Intent intent = new Intent(mContext, LoginActivity.class);


intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);

Bundle bundle = new Bundle();


bundle.putParcelable(AccountManager.KEY_INTENT, intent);

return bundle;
}

@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,
Bundle options) throws NetworkErrorException {
return null;
}

https://riptutorial.com/ 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;
}
}

The addAccount() method in AbstractAccountAuthenticator class is important as this method is


called when adding an account from the "Add Account" screen in under settings.
AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE is important, as it will include the
AccountAuthenticatorResponse object that is needed to return the account keys upon successful
user verification.

Read Android Authenticator online: https://riptutorial.com/android/topic/6759/android-authenticator

https://riptutorial.com/ 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.

First, we need an activity:

public class GameLauncher extends AppCompatActivity {

private Game game;


@Override
public void onCreate(Bundle sis){
super.onCreate(sis);
game = new Game(GameLauncher.this);//Initialize the game instance
setContentView(game);//setContentView to the game surfaceview
//Custom XML files can also be used, and then retrieve the game instance using
findViewById.
}

The activity also has to be declared in the Android Manifest.

Now for the game itself. First, we start by implementing a game thread:

public class Game extends SurfaceView implements SurfaceHolder.Callback, Runnable{

/**
* Holds the surface frame
*/
private SurfaceHolder holder;

/**
* Draw thread
*/

https://riptutorial.com/ 104
private Thread drawThread;

/**
* True when the surface is ready to draw
*/
private boolean surfaceReady = false;

/**
* Drawing thread flag
*/

private boolean drawingActive = false;

/**
* Time per frame for 60 FPS
*/
private static final int MAX_FRAME_TIME = (int) (1000.0 / 60.0);

private static final String LOGTAG = "surface";

/*
* 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();
}

public void init(Context c) {


this.c = c;

SurfaceHolder holder = getHolder();


holder.addCallback(this);
setFocusable(true);
//Initialize other stuff here later
}

public void render(Canvas c){


//Game rendering here
}

public void tick(){


//Game logic here
}

@Override

https://riptutorial.com/ 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){
this.holder = holder;

if (drawThread != null){
Log.d(LOGTAG, "draw thread still active..");
drawingActive = false;
try{
drawThread.join();
} 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
holder.getSurface().release();

this.holder = 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");
drawThread.join(5000);
break;
} catch (Exception e) {
Log.e(LOGTAG, "Could not join with draw thread");
}

https://riptutorial.com/ 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;
drawThread.start();
}
}

@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 (android.os.Build.BRAND.equalsIgnoreCase("google") &&
android.os.Build.MANUFACTURER.equalsIgnoreCase("asus") &&
android.os.Build.MODEL.equalsIgnoreCase("Nexus 7")) {
Log.w(LOGTAG, "Sleep 500ms (Device: Asus Nexus 7)");
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {}
}

while (drawing) {
if (sf == null) {
return;
}

frameStartTime = System.nanoTime();
Canvas canvas = sf.lockCanvas();
if (canvas != null) {
try {
synchronized (sf) {
tick();
render(canvas);
}
} finally {

sf.unlockCanvasAndPost(canvas);
}
}

// calculate the time required to draw the frame in ms


frameTime = (System.nanoTime() - frameStartTime) / 1000000;

if (frameTime < MAX_FRAME_TIME){


try {
Thread.sleep(MAX_FRAME_TIME - frameTime);
} catch (InterruptedException e) {

https://riptutorial.com/ 107
// ignore
}
}

}
Log.d(LOGTAG, "Draw thread finished");
}
}

That is the basic part. Now you have the ability to draw onto the screen.

Now, let's start by adding to integers:

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)

Now, we declare a Bitmap:

private Bitmap PLAYER_BMP = BitmapFactory.decodeResource(getResources(),


R.drawable.my_player_drawable);

In render, we need to draw this bitmap.

...
c.drawBitmap(PLAYER_BMP, x, y, null);
...

BEFORE LAUNCHING there are still some things to be done

We need a boolean first:

boolean up = false;

in onTouchEvent, we add:

if(ev.getAction() == MotionEvent.ACTION_DOWN){
up = true;
}else if(ev.getAction() == MotionEvent.ACTION_UP){
up = false;
}

And in tick we need this to move the player:

if(up){
velY -=1;
}
else{

https://riptutorial.com/ 108
velY +=1;
}
if(velY >14)velY = 14;
if(velY <-14)velY = -14;
y += velY *2;

and now we need this in init:

WindowManager wm = (WindowManager) c.getSystemService(Context.WINDOW_SERVICE);


Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
WIDTH = size.x;
HEIGHT = size.y;
y = HEIGHT/ 2 - PLAYER_BMP.getHeight();

And we need these to variables:

public static int WIDTH, HEIGHT;

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.

First, we need to declare the Rect:

private Rect screen;

In init, after initializing width and height, we create a new rect that is the screen.

screen = new Rect(0,0,WIDTH,HEIGHT);

Now we need another rect in the form of a method:

private Rect getPlayerBound(){


return new Rect(x, y, x + PLAYER_BMP.getWidth(), y + PLAYER_BMP.getHeight();
}

and in tick:

if(!getPlayerBound().intersects(screen){
gameOver = true;
}

The implementation of gameOVer can also be used to show the start of a game.

https://riptutorial.com/ 109
Other aspects of a game worth noting:

Saving(currently missing in documentation)

Read Android game development online: https://riptutorial.com/android/topic/10011/android-game-


development

https://riptutorial.com/ 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.

Suppose you have a native library named libjniexample.so in the project/libs/<architecture>


folder, and you want to call a function from the JNITestJava class inside the com.example.jniexample
package.

In the JNITest class, declare the function like this:

public native int testJNIfunction(int a, int b);

In your native code, define the function like this:

#include <jni.h>

JNIEXPORT jint JNICALL Java_com_example_jniexample_JNITest_testJNIfunction(JNIEnv *pEnv,


jobject thiz, jint a, jint b)
{
return a + b;
}

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).

In your Java code, in JNITest, load the library like this:

static{
System.loadLibrary("jniexample");
}

Note the lib at the start, and the .so at the end of the filename are omitted.

https://riptutorial.com/ 111
Call the native function from Java like this:

JNITest test = new JNITest();


int c = test.testJNIfunction(3, 4);

How to call a Java method from native code

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 com.example.jniexample;
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;");

// Calling the method


return (int)env->CallStaticObjectMethod(jniTestClass, getAnswerMethod, (jboolean)true);
}

JNI method signature to Java type:

JNI Signature Java Type

Z boolean

B byte

C char

S short

I int

J long

https://riptutorial.com/ 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.

Utility method in JNI layer

This method will help to get the Java string from C++ string.

jstring getJavaStringFromCPPString(JNIEnv *global_env, const char* cstring) {

jstring nullString = global_env->NewStringUTF(NULL);

if (!cstring) {
return nullString;
}

jclass strClass = global_env->FindClass("java/lang/String");


jmethodID ctorID = global_env->GetMethodID(strClass, "<init>",
"([BLjava/lang/String;)V");
jstring encoding = global_env->NewStringUTF("UTF-8");

jbyteArray bytes = global_env->NewByteArray(strlen(cstring));


global_env->SetByteArrayRegion(bytes, 0, strlen(cstring), (jbyte*) cstring);
jstring str = (jstring) global_env->NewObject(strClass, ctorID, bytes,
encoding);

global_env->DeleteLocalRef(strClass);
global_env->DeleteLocalRef(encoding);
global_env->DeleteLocalRef(bytes);

return str;
}

This method will help you to convert jbyteArray to char

char* as_unsigned_char_array(JNIEnv *env, jbyteArray array) {


jsize length = env->GetArrayLength(array);
jbyte* buffer = new jbyte[length + 1];

env->GetByteArrayRegion(array, 0, length, buffer);


buffer[length] = '\0';

return (char*) buffer;


}

Read Android Java Native Interface (JNI) online: https://riptutorial.com/android/topic/8674/android-


java-native-interface--jni-

https://riptutorial.com/ 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.

Enable Low Ram Device flag

We are introducing a new API called ActivityManager.isLowRamDevice() for applications to


determine if they should turn off specific memory-intensive features that work poorly on low-
memory devices.

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 += ro.config.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 += dalvik.vm.jit.codecachesize=0

How to add a CPU Governor

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:

1. Copy your governor file (cpufreq_govname.c) and browse to kernel_source/drivers/cpufreq,

https://riptutorial.com/ 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!

for example, for smartassV2.

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.

for example, for smartassV2.

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:

https://riptutorial.com/ 115
#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND)
extern struct cpufreq_governor cpufreq_gov_ondemand;
#define CPUFREQ_DEFAULT_GOVERNOR (&amp;cpufreq_gov_ondemand)

(other cpu governors are also listed there)

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 (&amp;cpufreq_gov_smartass2)

Save the file and close it.

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.

I/O schedulers can be found in kernel_source/block.

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 Kconfig.iosched 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).

3. Then set the default choice option as follows:

default "sio" if DEFAULT_SIO

Save the file.

https://riptutorial.com/ 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.

Similar commit on GitHub: added Simple I/O scheduler.

Read Android Kernel Optimization online: https://riptutorial.com/android/topic/9106/android-kernel-


optimization

https://riptutorial.com/ 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/Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := hello_world
LOCAL_SRC_FILES := main.c
include $(BUILD_EXECUTABLE)

project/jni/Application.mk

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).

To build the executable:

cd project
ndk-build

https://riptutorial.com/ 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 ro.product.cpu.abi for the
primary architecture or ro.product.cpu.abilist (on newer devices) for a complete list of supported
architectures. You can do this using the android.os.Build class from within your application or
using getprop <name> via ADB.

How to clean the build

If you need to clean the build:

ndk-build clean

How to use a makefile other than Android.mk

ndk-build NDK_PROJECT_PATH=PROJECT_PATH APP_BUILD_SCRIPT=MyAndroid.mk

How to log in ndk

First make sure you link against the logging library in your Android.mk file:

LOCAL_LDLIBS := -llog

Then use one of the following __android_log_print() calls:

#include <android/log.h>
#define TAG "MY LOG"

__android_log_print(ANDROID_LOG_VERBOSE, TAG, "The value of 1 + 1 is %d", 1 + 1)


__android_log_print(ANDROID_LOG_WARN, TAG, "The value of 1 + 1 is %d", 1 + 1)
__android_log_print(ANDROID_LOG_DEBUG, TAG, "The value of 1 + 1 is %d", 1 + 1)
__android_log_print(ANDROID_LOG_INFO, TAG, "The value of 1 + 1 is %d", 1 + 1)
__android_log_print(ANDROID_LOG_ERROR, TAG, "The value of 1 + 1 is %d", 1 + 1)

Or use those in a more convenient way by defining corresponding macros:

#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)


#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)

Example:

int x = 42;
LOGD("The value of x is %d", x);

https://riptutorial.com/ 119
Read Android NDK online: https://riptutorial.com/android/topic/492/android-ndk

https://riptutorial.com/ 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

1)First go through Paypal Developer web site and create an application.

2)Now open your manifest file and give the below permissions

<uses-permission android:name="android.permission.INTERNET" />


<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

3)And some required Activity and Services-

<service
android:name="com.paypal.android.sdk.payments.PayPalService"
android:exported="false" />
<activity android:name="com.paypal.android.sdk.payments.PaymentActivity" />
<activity android:name="com.paypal.android.sdk.payments.LoginActivity" />
<activity android:name="com.paypal.android.sdk.payments.PaymentMethodActivity" />
<activity android:name="com.paypal.android.sdk.payments.PaymentConfirmActivity" />
<activity android:name="com.paypal.android.sdk.payments.PayPalFuturePaymentActivity" />
<activity android:name="com.paypal.android.sdk.payments.FuturePaymentConsentActivity" />
<activity android:name="com.paypal.android.sdk.payments.FuturePaymentInfoActivity" />
<activity
android:name="io.card.payment.CardIOActivity"
android:configChanges="keyboardHidden|orientation" />
<activity android:name="io.card.payment.DataEntryActivity" />

4)Open your Activity class and set Configuration for your app-

//set the environment for production/sandbox/no netowrk


private static final String CONFIG_ENVIRONMENT = PayPalConfiguration.ENVIRONMENT_PRODUCTION;

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, PayPalService.class);
intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config); startService(intent);

7)Now you are ready to make a payment just on button press call the Payment Activity-

https://riptutorial.com/ 121
PayPalPayment thingToBuy = new PayPalPayment(new BigDecimal(1),"USD", "androidhub4you.com",
PayPalPayment.PAYMENT_INTENT_SALE);
Intent intent = new Intent(MainActivity.this,
PaymentActivity.class);
intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);

startActivityForResult(intent, REQUEST_PAYPAL_PAYMENT);

8)And finally from the onActivityResult get the payment response-

@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 {
System.out.println("Responseeee"+confirm);
Log.i("paymentExample", confirm.toJSONObject().toString());

JSONObject jsonObj=new
JSONObject(confirm.toJSONObject().toString());

String
paymentId=jsonObj.getJSONObject("response").getString("id");
System.out.println("payment id:-=="+paymentId);
Toast.makeText(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.");
}
}

Read Android Paypal Gateway Integration online:


https://riptutorial.com/android/topic/5895/android-paypal-gateway-integration

https://riptutorial.com/ 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.

This is a sample usage of Place Picker UI widget.

private static int PLACE_PICKER_REQUEST = 1;

private TextView txtPlaceName;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_place_picker_sample);

txtPlaceName = (TextView) this.findViewById(R.id.txtPlaceName);


Button btnSelectPlace = (Button) this.findViewById(R.id.btnSelectPlace);
btnSelectPlace.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
openPlacePickerView();
}
});

private void openPlacePickerView(){


PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();
try {
startActivityForResult(builder.build(this), PLACE_PICKER_REQUEST);
} catch (GooglePlayServicesRepairableException e) {
e.printStackTrace();
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {


if (requestCode == PLACE_PICKER_REQUEST) {
if (resultCode == RESULT_OK) {
Place place = PlacePicker.getPlace(this, data);
Log.i(LOG_TAG, String.format("Place Name : %s", place.getName()));
Log.i(LOG_TAG, String.format("Place Address : %s", place.getAddress()));
Log.i(LOG_TAG, String.format("Place Id : %s", place.getId()));

txtPlaceName.setText(String.format("Place : %s - %s" , place.getName() ,


place.getAddress()));
}
}
}

https://riptutorial.com/ 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 PlaceDetectionApi.getCurrentPlace() 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
PlaceLikelihood.getPlace() method.

Important: You must request and obtain the ACCESS_FINE_LOCATION permission in order to
allow your app to access precise location information.

private static final int PERMISSION_REQUEST_TO_ACCESS_LOCATION = 1;

private TextView txtLocation;


private GoogleApiClient googleApiClient;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);

txtLocation = (TextView) this.findViewById(R.id.txtLocation);


googleApiClient = new GoogleApiClient.Builder(this)
.addApi(Places.GEO_DATA_API)
.addApi(Places.PLACE_DETECTION_API)
.enableAutoManage(this, this)
.build();

getCurrentLocation();
}

private void getCurrentLocation() {


if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
Log.e(LOG_TAG, "Permission is not granted");

ActivityCompat.requestPermissions(this,new
String[]{Manifest.permission.ACCESS_FINE_LOCATION},PERMISSION_REQUEST_TO_ACCESS_LOCATION);
return;
}

Log.i(LOG_TAG, "Permission is granted");

PendingResult<PlaceLikelihoodBuffer> result =
Places.PlaceDetectionApi.getCurrentPlace(googleApiClient, null);
result.setResultCallback(new ResultCallback<PlaceLikelihoodBuffer>() {
@Override
public void onResult(PlaceLikelihoodBuffer likelyPlaces) {
Log.i(LOG_TAG, String.format("Result received : %d " , likelyPlaces.getCount() ));
StringBuilder stringBuilder = new StringBuilder();

for (PlaceLikelihood placeLikelihood : likelyPlaces) {


stringBuilder.append(String.format("Place : '%s' %n",
placeLikelihood.getPlace().getName()));
}
likelyPlaces.release();
txtLocation.setText(stringBuilder.toString());

https://riptutorial.com/ 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 (grantResults.length > 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: " +
connectionResult.getErrorMessage());
}

Place Autocomplete Integration

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.

AutoCompleteActivity.java

private TextView txtSelectedPlaceName;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_autocomplete);

txtSelectedPlaceName = (TextView) this.findViewById(R.id.txtSelectedPlaceName);

PlaceAutocompleteFragment autocompleteFragment = (PlaceAutocompleteFragment)


getFragmentManager().findFragmentById(R.id.fragment_autocomplete);

autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
@Override
public void onPlaceSelected(Place place) {
Log.i(LOG_TAG, "Place: " + place.getName());
txtSelectedPlaceName.setText(String.format("Selected places : %s - %s" ,
place.getName(), place.getAddress()));
}

@Override

https://riptutorial.com/ 125
public void onError(Status status) {
Log.i(LOG_TAG, "An error occurred: " + status);
Toast.makeText(AutoCompleteActivity.this, "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="com.google.android.gms.location.places.ui.PlaceAutocompleteFragment"
/>

<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"/>

Adding more than one google auto complete activity.

public static final int PLACE_AUTOCOMPLETE_FROM_PLACE_REQUEST_CODE=1;


public static final int PLACE_AUTOCOMPLETE_TO_PLACE_REQUEST_CODE=2;

fromPlaceEdit.setOnClickListener(new View.OnClickListener() {
@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.
}
}
});
toPlaceEdit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

try {
//Do your stuff to place

https://riptutorial.com/ 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.
}
}
}

Setting place type filters for PlaceAutocomplete

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:

MainActivity.java

public class MainActivity extends AppComatActivity {

private static final int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1;


private TextView selectedPlace;

protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

selectedPlace = (TextView) findViewById(R.id.selected_place);


try {
AutocompleteFilter typeFilter = new AutocompleteFilter.Builder()
.setTypeFilter(AutocompleteFilter.TYPE_FILTER_REGIONS)
.setCountry("IN")
.build();

Intent intent =
new PlaceAutocomplete.IntentBuilder(PlaceAutocomplete.MODE_FULLSCREEN)
.setFilter(typeFilter)

https://riptutorial.com/ 127
.build(this);
startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE);

} catch (GooglePlayServicesRepairableException
| GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
}

protected void onActivityResult(int requestCode,


int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == PLACE_AUTOCOMPLETE_REQUEST_CODE && resultCode == Activity.RESULT_OK) {


final Place place = PlacePicker.getPlace(this, data);
selectedPlace.setText(place.getName().toString().toUpperCase());
} else {
Toast.makeText(MainActivity.this, "Could not get location.",
Toast.LENGTH_SHORT).show();
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<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.

Read Android Places API online: https://riptutorial.com/android/topic/4111/android-places-api

https://riptutorial.com/ 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

First, you'll need to install the Kotlin plugin.

For Windows:

• Navigate to File → Settings → Plugins → Install JetBrains plugin

For Mac:

• Navigate to Android Studio → Preferences → Plugins → Install JetBrains plugin

And then search for and install Kotlin. You'll need to restart the IDE after this completes.

https://riptutorial.com/ 129
https://riptutorial.com/ 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 build.gradle file.

buildscript {

repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.1'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.2'
}
}

allprojects {
repositories {
jcenter()
}
}

task clean(type: Delete) {


delete rootProject.buildDir
}

2. Apply Kotlin Android Plugin - simply add apply plugin: 'kotlin-android' to a module
build.gradle file.

3. Add dependency to Kotlin stdlib - add the dependency to 'org.jetbrains.kotlin:kotlin-


stdlib:1.1.2' to the dependency section in a module build.gradle file.

For a new project, build.gradle file could looks like this:

apply plugin: 'com.android.application'


apply plugin: 'kotlin-android'

android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "org.example.example"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {

https://riptutorial.com/ 131
compile 'org.jetbrains.kotlin:kotlin-stdlib:1.1.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:appcompat-v7:25.3.1'

androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})

testCompile 'junit:junit:4.12'
}

Creating a new Kotlin Activity

1. Click to File → New → Kotlin Activity.


2. Choose a type of the Activity.
3. Select name and other parameter for the Activity.
4. Finish.

https://riptutorial.com/ 132
Final class could look like this:

import android.support.v7.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}

https://riptutorial.com/ 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:

Starting a new Activity

fun startNewActivity(){
val intent: Intent = Intent(context, Activity::class.java)
startActivity(intent)
}

You can add extras to the intent just like in Java.

fun startNewActivityWithIntents(){
val intent: Intent = Intent(context, Activity::class.java)
intent.putExtra(KEY_NAME, KEY_VALUE)
startActivity(intent)
}

Read Android programming with Kotlin online: https://riptutorial.com/android/topic/9623/android-


programming-with-kotlin

https://riptutorial.com/ 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 video.It will work for all APIs less than 19 and greater than 19
as well.

Image:

if (Build.VERSION.SDK_INT <= 19) {


Intent i = new Intent();
i.setType("image/*");
i.setAction(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(i, 10);
} else if (Build.VERSION.SDK_INT > 19) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 10);
}

Video:

if (Build.VERSION.SDK_INT <= 19) {


Intent i = new Intent();
i.setType("video/*");
i.setAction(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(i, 20);
} else if (Build.VERSION.SDK_INT > 19) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 20);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {

if (requestCode == 10) {
Uri selectedImageUri = data.getData();
String selectedImagePath = getRealPathFromURI(selectedImageUri);
} else if (requestCode == 20) {
Uri selectedVideoUri = data.getData();
String selectedVideoPath = getRealPathFromURI(selectedVideoUri);
}

public String getRealPathFromURI(Uri uri) {

https://riptutorial.com/ 135
if (uri == null) {
return null;
}
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = getActivity().getContentResolver().query(uri, projection, null,
null, null);
if (cursor != null) {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
return uri.getPath();
}

Play sounds via SoundPool

public class PlaySound extends Activity implements OnTouchListener {


private SoundPool soundPool;
private int soundID;
boolean loaded = false;

/** Called when the activity is first created. */


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
View view = findViewById(R.id.textView1);
view.setOnTouchListener(this);
// Set the hardware buttons to control the music
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
// Load the sound
soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId,
int status) {
loaded = true;
}
});
soundID = soundPool.load(this, R.raw.sound1, 1);

@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == 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) {
soundPool.play(soundID, volume, volume, 1, 0, 1f);
Log.e("Test", "Played sound");

https://riptutorial.com/ 136
}
}
return false;
}
}

Read Android Sound and Media online: https://riptutorial.com/android/topic/4730/android-sound-


and-media

https://riptutorial.com/ 137
Chapter 24: Android Studio
Examples
Filter logs from UI

Android logs can be filtered directly from the UI. Using this code

public class MainActivity extends AppCompatActivity {


private final static String TAG1 = MainActivity.class.getSimpleName();
private final static String TAG2 = MainActivity.class.getCanonicalName();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(TAG1,"Log from onCreate method with TAG1");
Log.i(TAG2,"Log from onCreate method with TAG2");
}
}

If I use the regex TAG1|TAG2 and the level verbose I get

01-14 10:34:46.961 12880-12880/android.doc.so.thiebaudthomas.sodocandroid E/MainActivity: Log


from onCreate method with TAG1
01-14 10:34:46.961 12880-12880/android.doc.so.thiebaudthomas.sodocandroid
I/androdi.doc.so.thiebaudthomas.sodocandroid.MainActivity: 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

https://riptutorial.com/ 138
01-14 10:34:46.961 12880-12880/androdi.doc.so.thiebaudthomas.sodocandroid E/MainActivity: Log
from onCreate method with TAG1

Create filters configuration

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.

Enter the filter you want

And use it (you can selected it from the same dropdown)

https://riptutorial.com/ 139
Important If you add an input in the filter bar, android studio will consider both your filter and your
input.

With both input and filter there is no output

Without filter, there is some outputs

https://riptutorial.com/ 140
Custom colors of logcat message based on message importance

Go to File -> Settings -> Editor -> Colors & Fonts -> Android Logcat

Change the colors as you need:

Choose the appropriate color:

https://riptutorial.com/ 141
Enable/Disable blank line copy

ctrl + alt + shift + / (cmd + alt + shift + / on MacOS) should show you the following dialog:

Clicking on Registry you will get

https://riptutorial.com/ 142
The key you want to enable/disable is

editor.skip.copy.and.cut.for.empty.selection

Tested on Linux Ubuntu and MacOS.

Android Studio useful shortcuts

The following are some of the more common/useful shortcuts.

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>

https://riptutorial.com/ 143
Action Shortcut

Format code CTRL + ALT + L

Add unimplemented methods CTRL +I

Show logcat ALT +6

Build CTRL + F9

Build and Run CTRL + F10

Find CTRL +F

Find in project CTRL+SHIFT +F

Find and replace CTRL +R

Find and replace in project CTRL + SHIFT + R

Override methods CTRL +O

Show project ALT +1

Hide project - logcat SHIFT + ESC

Collapse all CTRL + SHIFT + NumPad +

View Debug Points CTRL + SHIFT + F8

Expand all CTRL + SHIFT + NumPad -

Open Settings ALT +s

Select Target (open current file in Project view) ALT + F1 → ENTER

Search Everywhere SHIFT → SHIFT (Double shift)

Code | Surround With CTRL → ALT + T

Create method form selected code ALT + CTRL

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

https://riptutorial.com/ 144
Action Shortcut

Mac CMD + ALT + M - Win/Linux


Extract Method
CTRL + ALT + M

Mac CMD + ALT + P - Win/Linux


Extract Parameter
CTRL + ALT + P

Mac CMD + ALT + V - Win/Linux


Extract Variable
CTRL + ALT + V

Android Studio Improve performance tip

Enable Offline Work:

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.

Improve Gradle Performance

Add following two line of code in your gradle.properties file.

org.gradle.daemon=true
org.gradle.parallel=true

Increasing the value of -Xmx and -Xms in studio.vmoptions file

-Xms1024m
-Xmx4096m
-XX:MaxPermSize=1024m
-XX:ReservedCodeCacheSize=256m
-XX:+UseCompressedOops

Window

%USERPROFILE%.{FOLDER_NAME}\studio.exe.vmoptions and/or
%USERPROFILE%.{FOLDER_NAME}\studio64.exe.vmoptions

Mac

~/Library/Preferences/{FOLDER_NAME}/studio.vmoptions

Linux

~/.{FOLDER_NAME}/studio.vmoptions and/or
~/.{FOLDER_NAME}/studio64.vmoptions

Setup Android Studio

https://riptutorial.com/ 145
System Requirements

• Microsoft® Windows® 8/7/Vista/2003 (32 or 64-bit).


• Mac® OS X® 10.8.5 or higher, up to 10.9 (Mavericks)
• GNOME or KDE desktop

Installation

Window

1. Download and install JDK (Java Development Kit) version 8


2. Download Android Studio
3. Launch Android Studio.exe then mention JDK path and download the latest SDK

Linux

1. Download and install JDK (Java Development Kit) version 8


2. Download Android Studio
3. Extract the zip file
4. Open terminal, cd to the extracted folder, cd to bin (example cd android-studio/bin)
5. Run ./studio.sh

View And Add Shortcuts in Android Studio

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

https://riptutorial.com/ 146
Gradle build project takes forever

Android Studio -> Preferences -> Gradle -> Tick Offline work and then restart your Android
studio.

Reference screenshot:

https://riptutorial.com/ 147
https://riptutorial.com/ 148
• Assets folder will be under MAIN folder with the same symbol as RES folder.
• In this example I put a font file.

Read Android Studio online: https://riptutorial.com/android/topic/107/android-studio

https://riptutorial.com/ 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:

• movement between 0 and 180 degrees


• pulse period of 20 ms
• minimum pulse length of 0.5 ms
• maximum pulse length of 2.5 ms

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():

public class ServoController {


private double periodMs, maxTimeMs, minTimeMs;
private Pwm pin;

public void setup(String pinName) throws IOException {


periodMs = 20;
maxTimeMs = 2.5;
minTimeMs = 0.5;

PeripheralManagerService service = new PeripheralManagerService();


pin = service.openPwm(pinName);

pin.setPwmFrequencyHz(1000.0d / periodMs);
setPosition(90);
pin.setEnabled(true);
}

public void setPosition(double degrees) {


double pulseLengthMs = (degrees / 180.0 * (maxTimeMs - minTimeMs)) + minTimeMs;

if (pulseLengthMs < minTimeMs) {


pulseLengthMs = minTimeMs;
} else if (pulseLengthMs > maxTimeMs) {
pulseLengthMs = maxTimeMs;
}

double dutyCycle = pulseLengthMs / periodMs * 100.0;

Log.i(TAG, "Duty cycle = " + dutyCycle + " pulse length = " + pulseLengthMs);

try {
pin.setPwmDutyCycle(dutyCycle);
} catch (IOException e) {
e.printStackTrace();

https://riptutorial.com/ 150
}
}
}

You can discover pin names that support PWM on your device as follows:

PeripheralManagerService service = new PeripheralManagerService();

for (String pinName : service.getPwmList() ) {


Log.i("ServoControlled","Pwm pin found: " + pinName);
}

In order to make your servo swinging forever between 80 degrees and 100 degrees, you can
simply use the following code:

final ServoController servoController = new ServoController(pinName);

Thread th = new Thread(new Runnable() {


@Override
public void run() {
while (true) {
try {
servoController.setPosition(80);
Thread.sleep(500);
servoController.setPosition(100);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
th.start();

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.

Read Android Things online: https://riptutorial.com/android/topic/8938/android-things

https://riptutorial.com/ 151
Chapter 26: Android Versions
Remarks

Android API-
Name Release date Build.VERSION_CODES
version level

Angel Cake 23 September


1.0 1 BASE
(Alpha) 2008

Battenberg 9 February
1.1 2 BASE_1_1
(Beta) 2009

Cupcake 1.5 30 April 2009 3 CUPCAKE

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

Froyo 2.2 20 May 2010 8 FROYO

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

3.1 10 May 2011 12 HONEYCOMB_MR2

3.2 15 July 2011 13 HONEYCOMB_MR1

Ice Cream 19 October


4.0 14 ICE_CREAM_SANDWICH
Sandwich 2011

16 December
4.0.3 15 ICE_CREAM_SANDWICH_MR1
2011

https://riptutorial.com/ 152
Android API-
Name Release date Build.VERSION_CODES
version level

Jelly Bean 4.1 9 July 2012 16 JELLY_BEAN

13 November
4.2 17 JELLY_BEAN_MR1
2012

4.3 24 July 2013 18 JELLY_BEAN_MR2

31 October
KitKat 4.4 19 KITKAT
2013

25 July 2014 20 KITKAT_WATCH

17 October
Lollipop 5.0 21 LOLLIPOP
2014

5.1 9 March 2015 22 LOLLIPOP_MR1

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

Build.VERSION_CODES is an enumeration of the currently known SDK version codes.

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() {
super.onResume();
if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
//run Marshmallow code
FingerprintManager fingerprintManager =
this.getSystemService(FingerprintManager.class);

https://riptutorial.com/ 153
//......................
}
}

Read Android Versions online: https://riptutorial.com/android/topic/3264/android-versions

https://riptutorial.com/ 154
Chapter 27: Android Vk Sdk
Examples
Initialization and login

1. Create a new application here: create application


2. Choose standalone applicaton and confirm app creation via SMS.
3. Fill Package namefor Android as your current package name. You can get your package
name inside android manifest file, at the very begginning.
4. Get your Certificate fingerprint by executing this command in your shell/cmd:

keytool -exportcert -alias androiddebugkey -keystore path-to-debug-or-production-keystore -


list -v

You can also get this fingerprint by SDK itself:

String[] fingerprints = VKUtil.getCertificateFingerprint(this, this.getPackageName());


Log.d("MainActivity", fingerprints[0]);

5. Add recieved fingerprint into your Signing certificate fingerprint for Android: field in Vk
app settings (where you entered your package name)

6. Then add this to your gradle file:

compile 'com.vk: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.

private static final int VK_ID = your_vk_id;


public static final String VK_API_VERSION = "5.52"; //current version
@Override
public void onCreate() {
super.onCreate();
VKSdk.customInitialize(this, VK_ID, VK_API_VERSION);
}

This is the best way to initizlize VKSdk. Don't use the methid where VK_ID should be placed
inside strings.xml because api will not work correctly after it.

9. Final step is to login using vksdk.

public static final String[] VK_SCOPES = new String[]{


VKScope.FRIENDS,
VKScope.MESSAGES,
VKScope.NOTIFICATIONS,
VKScope.OFFLINE,

https://riptutorial.com/ 155
VKScope.STATUS,
VKScope.STATS,
VKScope.PHOTOS
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

someButtonForLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
VKSdk.login(this, VK_SCOPES);
}
});

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
VKSdk.onActivityResult(requestCode, resultCode, data, new VKCallback<VKAccessToken>()
{
@Override
public void onResult(VKAccessToken res) {
res.accessToken; //getting our token here.
}

@Override
public void onError(VKError error) {
Toast.makeText(SocialNetworkChooseActivity.this,
"User didn't pass Authorization", Toast.LENGTH_SHORT).show();
}
});
}

Read Android Vk Sdk online: https://riptutorial.com/android/topic/6046/android-vk-sdk

https://riptutorial.com/ 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

These are my VirtualBox settings:

• 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-6.0-r3.iso (it is 64bit)
downloaded from http://www.android-x86.org/download. I suppose that it also works with 32bit
version.

Virtual hard drive Setup for SDCARD Support

With the virtual hard drive just created, boot the virtual machine with the android-x86 image in the
optical drive.

https://riptutorial.com/ 157
Once you boot, you can see the grub menu of the Live CD

https://riptutorial.com/ 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:

"n" (new partition)

"p" (primary partition)

"1" (1st partition)

"1" (first cylinder)

"261" (choose a cylinder, we'll leave 50% of the disk for a 2nd partition)

"2" (2nd partition)

https://riptutorial.com/ 159
"262" (262nd cylinder)

"522" (choose the last cylinder)

"w" (write the partition)

#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"

https://riptutorial.com/ 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.

https://riptutorial.com/ 161
Then we substitute "quiet" with "vga=ask" and add the option "SDCARD=sda2"

In my case, the kernel line looks like this after modified:

kenel /android-6.0-r3/kernel vga=ask root=ram0 SRC=/android-6/android-6.0-r3 SDCARD=sda2

Press b to boot, then you'll be able to choose the screen size pressing ENTER (the vga=ask option)

https://riptutorial.com/ 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.

Read Android-x86 in VirtualBox online: https://riptutorial.com/android/topic/9903/android-x86-in-


virtualbox

https://riptutorial.com/ 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="http://schemas.android.com/apk/res/android"
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"

https://riptutorial.com/ 164
android:textColor="#fff" />

AnimatedAndroidDialogExample.java

public class AnimatedAndroidDialogExample extends AppCompatActivity {

NiftyDialogBuilder materialDesignAnimatedDialog;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animated_android_dialog_box);

materialDesignAnimatedDialog = NiftyDialogBuilder.getInstance(this);
}

public void animatedDialog1(View view) {


materialDesignAnimatedDialog
.withTitle("Animated Fall Dialog Title")
.withMessage("Add your dialog message here. Animated dialog description
place.")
.withDialogColor("#FFFFFF")
.withButton1Text("OK")
.withButton2Text("Cancel")
.withDuration(700)
.withEffect(Effectstype.Fall)
.show();
}

public void animatedDialog2(View view) {


materialDesignAnimatedDialog
.withTitle("Animated Flip Dialog Title")
.withMessage("Add your dialog message here. Animated dialog description
place.")
.withDialogColor("#1c90ec")
.withButton1Text("OK")
.withButton2Text("Cancel")
.withDuration(700)
.withEffect(Effectstype.Fliph)
.show();
}

public void animatedDialog3(View view) {


materialDesignAnimatedDialog
.withTitle("Animated Shake Dialog Title")
.withMessage("Add your dialog message here. Animated dialog description
place.")
.withDialogColor("#1c90ec")
.withButton1Text("OK")
.withButton2Text("Cancel")
.withDuration(700)
.withEffect(Effectstype.Shake)
.show();
}

public void animatedDialog4(View view) {


materialDesignAnimatedDialog
.withTitle("Animated Slide Top Dialog Title")
.withMessage("Add your dialog message here. Animated dialog description
place.")

https://riptutorial.com/ 165
.withDialogColor("#1c90ec")
.withButton1Text("OK")
.withButton2Text("Cancel")
.withDuration(700)
.withEffect(Effectstype.Slidetop)
.show();
}
}

Add the below lines in your build.gradle to include the NifyBuilder(CustomView)

build.gradle

dependencies {

compile 'com.nineoldandroids:library:2.4.0'

compile 'com.github.sd6352051.niftydialogeffects:niftydialogeffects:1.0.0@aar'

Reference Link : https://github.com/sd6352051/NiftyDialogEffects

Read Animated AlertDialog Box online: https://riptutorial.com/android/topic/10654/animated-


alertdialog-box

https://riptutorial.com/ 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.

shakeanimation.xml

<?xml version="1.0" encoding="utf-8"?>


<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="100"
android:fromDegrees="-15"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:toDegrees="15" />

Create a blank activity called Landing

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>

And the method for animate the imageview on Landing.java

Context mContext;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext=this;
setContentView(R.layout.activity_landing);

AnimateBell();
}

public void AnimateBell() {

https://riptutorial.com/ 167
Animation shake = AnimationUtils.loadAnimation(mContext, R.anim.shakeanimation);
ImageView imgBell= (ImageView) findViewById(R.id.imgBell);
imgBell.setImageResource(R.mipmap.ic_notifications_active_white_48dp);
imgBell.setAnimation(shake);
}

Fade in/out animation

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 View.GONE or View.VISIBLE.

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;

void fadeOutAnimation(View viewToFadeOut) {


ObjectAnimator fadeOut = ObjectAnimator.ofFloat(viewToFadeOut, "alpha", 1f, 0f);

fadeOut.setDuration(500);
fadeOut.addListener(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.
viewToFadeOut.setVisibility(View.GONE);
}
});

fadeOut.start();
}

void fadeInAnimation(View viewToFadeIn) {


ObjectAnimator fadeIn = ObjectAnimator.ofFloat(viewToFadeIn, "alpha", 0f, 1f);
fadeIn.setDuration(500);

fadeIn.addListener(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.
viewToFadeIn.setVisibility(View.VISIBLE);
viewToFadeIn.setAlpha(0);
}
});

fadeIn.start();
}

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

https://riptutorial.com/ 168
a loop)

• add a image array to res/values/arrays.xml

<resources>

<array
name="splash_images">
<item>@drawable/spash_imge_first</item>
<item>@drawable/spash_img_second</item>
</array>

</resources>

private Drawable[] backgroundsDrawableArrayForTransition;


private TransitionDrawable transitionDrawable;

private void backgroundAnimTransAction() {

// set res image array


Resources resources = getResources();
TypedArray icons = resources.obtainTypedArray(R.array.splash_images);

@SuppressWarnings("ResourceType")
Drawable drawable = icons.getDrawable(0); // ending image

@SuppressWarnings("ResourceType")
Drawable drawableTwo = icons.getDrawable(1); // starting image

backgroundsDrawableArrayForTransition = new Drawable[2];


backgroundsDrawableArrayForTransition[0] = drawable;
backgroundsDrawableArrayForTransition[1] = drawableTwo;
transitionDrawable = new TransitionDrawable(backgroundsDrawableArrayForTransition);

// your image view here - backgroundImageView


backgroundImageView.setImageDrawable(transitionDrawable);
transitionDrawable.startTransition(4000);

transitionDrawable.setCrossFadeEnabled(false); // call public methods

ValueAnimator

ValueAnimator introduces a simple way to animate a value (of a particular type, e.g. int, float, etc.).

The usual way of using it is:

1. Create a ValueAnimator that will animate a value from min to max


2. Add an UpdateListener in which you will use the calculated animated value (which you can
obtain with getAnimatedValue())

https://riptutorial.com/ 169
There are two ways you can create the ValueAnimator:

(the example code animates a float from 20f to 40f in 250ms)

1. From xml (put it in the /res/animator/):

<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="250"
android:valueFrom="20"
android:valueTo="40"
android:valueType="floatType"/>

ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context,


R.animator.example_animator);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator anim) {
// ... use the anim.getAnimatedValue()
}
});
// set all the other animation-related stuff you want (interpolator etc.)
animator.start();

2. From the code:

ValueAnimator animator = ValueAnimator.ofFloat(20f, 40f);


animator.setDuration(250);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator anim) {
// use the anim.getAnimatedValue()
}
});
// set all the other animation-related stuff you want (interpolator etc.)
animator.start();

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)

1. From xml (put it in the /res/animator)

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="250"
android:propertyName="alpha"
android:valueFrom="0.4"
android:valueTo="0.2"
android:valueType="floatType"/>

https://riptutorial.com/ 170
ObjectAnimator animator = (ObjectAnimator) AnimatorInflater.loadAnimator(context,
R.animator.example_animator);
animator.setTarget(exampleView);
// set all the animation-related stuff you want (interpolator etc.)
animator.start();

2. From code:

ObjectAnimator animator = ObjectAnimator.ofFloat(exampleView, View.ALPHA, 0.4f, 0.2f);


animator.setDuration(250);
// set all the animation-related stuff you want (interpolator etc.)
animator.start();

ViewPropertyAnimator

ViewPropertyAnimator is a simplified and optimized way to animate properties of a View.

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.

View exampleView = ...;


exampleView.animate()
.alpha(0.6f)
.translationY(200)
.translationXBy(10)
.scaleX(1.5f)
.setDuration(250)
.setInterpolator(new FastOutLinearInInterpolator());

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.

Expand and Collapse animation of View

public class ViewAnimationUtils {

public static void expand(final View v) {


v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
final int targtetHeight = v.getMeasuredHeight();

v.getLayoutParams().height = 0;
v.setVisibility(View.VISIBLE);
Animation a = new Animation()
{
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1
? LayoutParams.WRAP_CONTENT
: (int)(targtetHeight * interpolatedTime);

https://riptutorial.com/ 171
v.requestLayout();
}

@Override
public boolean willChangeBounds() {
return true;
}
};

a.setDuration((int)(targtetHeight /
v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}

public static void collapse(final View v) {


final int initialHeight = v.getMeasuredHeight();

Animation a = new Animation()


{
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if(interpolatedTime == 1){
v.setVisibility(View.GONE);
}else{
v.getLayoutParams().height = initialHeight - (int)(initialHeight *
interpolatedTime);
v.requestLayout();
}
}

@Override
public boolean willChangeBounds() {
return true;
}
};

a.setDuration((int)(initialHeight /
v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}
}

Read Animators online: https://riptutorial.com/android/topic/1829/animators

https://riptutorial.com/ 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 annotations.There are two ways to access these annotations at runtime via reflection
and at compile time via annotation processors.

Examples
@NonNull Annotation

public class Foo {


private String name;
public Foo(@NonNull String name){...};
...
}

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

There are three types of annotations.

1. Marker Annotation - annotation that has no method

@interface CustomAnnotation {}

2. Single-Value Annotation - annotation that has one method

@interface CustomAnnotation {
int value();
}

3. Multi-Value Annotation - annotation that has more than one method

@interface CustomAnnotation{
int value1();
String value2();
String value3();
}

https://riptutorial.com/ 173
Creating and Using Custom Annotations

For creating custom annotations we need to decide

• 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

https://riptutorial.com/ 174
Creating Custom Annotation

@Retention(RetentionPolicy.SOURCE) // will not be available in compiled class


@Target(ElementType.METHOD) // can be applied to methods only
@interface CustomAnnotation{
int value();
}

Using Custom Annotation

class Foo{
@CustomAnnotation(value = 1) // will be used by an annotation processor
public void foo(){..}
}

the value provided inside @CustomAnnotation will be consumed by an Annotationprocessor may be


to generate code at compile time etc.

Read Annotation Processor online: https://riptutorial.com/android/topic/10726/annotation-


processor

https://riptutorial.com/ 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

Result the type of the result of 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.

Methods that can be overridden when extending AsyncTask:

• : invoked on the UI thread before the task is executed


onPreExecute()
• doInBackground(): invoked on the background thread immediately after onPreExecute()
finishes executing.
• onProgressUpdate(): invoked on the UI thread after a call to publishProgress(Progress...).
• onPostExecute(): invoked on the UI thread after the background computation finishes

Example
public class MyCustomAsyncTask extends AsyncTask<File, Void, String> {

@Override
protected void onPreExecute(){
// This runs on the UI thread before the background thread executes.
super.onPreExecute();
// Do pre-thread tasks such as initializing variables.
Log.v("myBackgroundTask", "Starting Background Task");
}

https://riptutorial.com/ 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 (scanner.hasNextLine()) {
final String line = scanner.nextLine();
publishProgress(); // tell the UI thread we made progress

if (line.contains("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(R.id.found_string);
if (s != null) {
view.setText(s);
} else {
view.setText("Match not found.");
}
}

Usage:
MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
asyncTask.execute(userSuppliedFilename);

or simply:

new MyCustomAsyncTask().execute(userSuppliedFilename);

Note
When defining an AsyncTask we can pass three types between < > brackets.

https://riptutorial.com/ 177
Defined as <Params, Progress, Result> (see Parameters section)

In the previous example we've used types <File, Void, String>:

AsyncTask<File, Void, String>


// Params has type File
// Progress has unused type
// Result has type String

Void is used when you want to mark a type as unused.

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.

The AsyncTask and Activity life cycle

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

YourAsyncTask task = new YourAsyncTask();


task.execute();
task.cancel();

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:

class YourAsyncTask extends AsyncTask<Void, Void, Void> {


@Override
protected Void doInBackground(Void... params) {
while(!isCancelled()) {
... doing long task stuff
//Do something, you need, upload part of file, for example
if (isCancelled()) {
return null; // Task was detected as canceled
}
if (yourTaskCompleted) {
return null;
}
}

https://riptutorial.com/ 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.

class YourAsyncTask extends AsyncTask<URL, Integer, Long> {


@Override
protected void onProgressUpdate(Integer... args) {
setProgressPercent(args[0])
}
}

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.

protected Long doInBackground(URL... urls) {


int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}

Download Image using AsyncTask in Android

This tutorial explains how to download Image using AsyncTask in Android. The example below
download image while showing progress bar while during download.

Understanding Android AsyncTask


Async task enables you to implement MultiThreading without get Hands dirty into threads.
AsyncTask enables proper and easy use of the UI thread. It allows performing background
operations and passing the results on the UI thread. If you are doing something isolated related to
UI, for example downloading data to present in a list, go ahead and use AsyncTask.

https://riptutorial.com/ 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.

Downloading image using Android AsyncTask


your .xml layout

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
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 com.javatechig.droid;

import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;

https://riptutorial.com/ 180
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class ImageDownladerActivity extends Activity {

private ImageView downloadedImg;


private ProgressDialog simpleWaitDialog;
private String downloadUrl = "http://www.9ori.com/store/media/images/8ab579a656.jpg";

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.asynch);
Button imageDownloaderBtn = (Button) findViewById(R.id.downloadButton);

downloadedImg = (ImageView) findViewById(R.id.imageView);

imageDownloaderBtn.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new ImageDownloader().execute(downloadUrl);
}

});
}

private class ImageDownloader extends AsyncTask {

@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 = ProgressDialog.show(ImageDownladerActivity.this,
"Wait", "Downloading Image");

@Override
protected void onPostExecute(Bitmap result) {
Log.i("Async-Example", "onPostExecute Called");
downloadedImg.setImageBitmap(result);
simpleWaitDialog.dismiss();

https://riptutorial.com/ 181
}

private Bitmap downloadBitmap(String url) {


// initilize the default HTTP client object
final DefaultHttpClient client = new DefaultHttpClient();

//forming a HttpGet request


final HttpGet getRequest = new HttpGet(url);
try {

HttpResponse response = client.execute(getRequest);

//check 200 OK for success


final int statusCode = response.getStatusLine().getStatusCode();

if (statusCode != HttpStatus.SC_OK) {
Log.w("ImageDownloader", "Error " + statusCode +
" while retrieving bitmap from " + url);
return null;

final HttpEntity entity = response.getEntity();


if (entity != null) {
InputStream inputStream = null;
try {
// getting contents from the stream
inputStream = entity.getContent();

// decoding stream data back into image Bitmap that android


understands
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);

return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
// You Could provide a more explicit error message for IOException
getRequest.abort();
Log.e("ImageDownloader", "Something went wrong while" +
" retrieving bitmap from " + url + e.toString());
}

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:

This is a good example what can be done with AsyncTask.

https://riptutorial.com/ 182
However the example currently has problems with

• possible memory leaks


• app crash if there was a screen rotation shortly before the async task finished.

For details see:

• Pass Activity as WeakReference to avoid memory leaks


• http://stackoverflow.com/documentation/android/117/asynctask/5377/possible-problems-
with-inner-async-tasks
• Avoid leaking Activities with AsyncTask

Pass Activity as WeakReference to avoid memory leaks

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.

As a result, this will cause a memory leak.

In order to prevent this from happening, make use of a WeakReference in the AsyncTask instead
of having a direct reference to the Activity.

Here is an example AsyncTask that utilizes a WeakReference:

private class MyAsyncTask extends AsyncTask<String, Void, Void> {

private WeakReference<Activity> mActivity;

public MyAsyncTask(Activity activity) {


mActivity = new WeakReference<Activity>(activity);
}

@Override
protected void onPreExecute() {
final Activity activity = mActivity.get();
if (activity != null) {
....
}
}

@Override
protected Void doInBackground(String... params) {
//Do something
String param1 = params[0];

https://riptutorial.com/ 183
String param2 = params[1];
return null;
}

@Override
protected void onPostExecute(Void result) {
final Activity activity = mActivity.get();
if (activity != null) {
activity.updateUI();
}
}
}

Calling the AsyncTask from an Activity:

new MyAsyncTask(this).execute("param1", "param2");

Calling the AsyncTask from a Fragment:

new MyAsyncTask(getActivity()).execute("param1", "param2");

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.

If you truly want parallel execution, you can invoke


executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.

SERIAL_EXECUTOR -> An Executor that executes tasks one at a time in serial order.

THREAD_POOL_EXECUTOR -> An Executor that can be used to execute tasks in


parallel.

sample :

Task task = new Task();


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, data);
else
task.execute(data);

AsyncTask: Serial Execution and Parallel Execution of Task

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 AsyncTask.call().

Executor are part of java.util.concurrent package.

https://riptutorial.com/ 184
Moreover, AsyncTask contains 2 Executors

THREAD_POOL_EXECUTOR

It uses worker threads to execute the tasks parallelly.

public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE,


MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

SERIAL_EXECUTOR

It executes the task serially, i.e. one by one.

private static class SerialExecutor implements 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:

public class MainActivity extends Activity {


private Button bt;
private int CountTask = 0;
private static final String TAG = "AsyncTaskExample";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
BackgroundTask backgroundTask = new BackgroundTask ();
Integer data[] = { ++CountTask, null, null };

// Task Executed in thread pool ( 1 )


backgroundTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, data);

// Task executed Serially ( 2 )


// Uncomment the below code and comment the above code of Thread
// pool Executor and check
// backgroundTask.execute(data);
Log.d(TAG, "Task = " + (int) CountTask + " Task Queued");

}
});

https://riptutorial.com/ 185
private class BackgroundTask extends AsyncTask<Integer, Integer, Integer> {
int taskNumber;

@Override
protected Integer doInBackground(Integer... integers) {
taskNumber = integers[0];

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Log.d(TAG, "Task = " + taskNumber + " Task Running in Background");

publishProgress(taskNumber);
return null;
}

@Override
protected void onPreExecute() {
super.onPreExecute();
}

@Override
protected void onPostExecute(Integer aLong) {
super.onPostExecute(aLong);
}

@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(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.

Task Executed in thread pool(1)

Each task takes 1000 ms to complete.

At t=36s, tasks 2, 3 and 4 are queued and started executing also because they are executing
parallelly.

08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Queued


08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Running in Background
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Queued
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Running in Background
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Queued
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Running in Background
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Queued
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Running in Background
08-02 19:48:**36.815**: D/AsyncTaskExample(11693): Task = 1 Task Execution Completed

https://riptutorial.com/ 186
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Queued
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Running in Background
08-02 19:48:37.025: D/AsyncTaskExample(11693): Task = 2 Task Execution Completed
08-02 19:48:37.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.

08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Queued


08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Running in Background
08-02 19:42:57.675: D/AsyncTaskExample(10299): Task = 2 Task Queued
08-02 19:42:57.835: D/AsyncTaskExample(10299): Task = 3 Task Queued
08-02 19:42:58.005: D/AsyncTaskExample(10299): Task = 4 Task Queued
08-02 19:42:58.155: D/AsyncTaskExample(10299): Task = 5 Task Queued
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 1 Task Execution Completed
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 2 Task Running in Background
08-02 19:42:58.755: D/AsyncTaskExample(10299): Task = 6 Task Queued
08-02 19:42:59.295: D/AsyncTaskExample(10299): Task = 7 Task Queued
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 2 Task Execution Completed
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 3 Task Running in Background
08-02 19:43:00.035: D/AsyncTaskExample(10299): Task = 8 Task Queued
08-02 19:43:00.505: D/AsyncTaskExample(10299): Task = 3 Task Execution Completed
08-02 19:43:**00.505**: D/AsyncTaskExample(10299): Task = 4 Task Running in Background
08-02 19:43:**01.505**: D/AsyncTaskExample(10299): Task = 4 Task Execution Completed
08-02 19:43:**01.515**: D/AsyncTaskExample(10299): Task = 5 Task Running in Background
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 5 Task Execution Completed
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 6 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 7 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 6 Task Execution Completed
08-02 19:43:04.515: D/AsyncTaskExample(10299): Task = 8 Task Running in Background
08-02 19:43:**04.515**: D/AsyncTaskExample(10299): Task = 7 Task Execution Completed

Read AsyncTask online: https://riptutorial.com/android/topic/117/asynctask

https://riptutorial.com/ 187
Chapter 33: AudioManager
Examples
Requesting Transient Audio Focus

audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

audioManager.requestAudioFocus(audioListener, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);

changedListener = new AudioManager.OnAudioFocusChangeListener() {


@Override
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// You now have the audio focus and may play sound.
// When the sound has been played you give the focus back.
audioManager.abandonAudioFocus(changedListener);
}
}
}

Requesting Audio Focus

audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

audioManager.requestAudioFocus(audioListener, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);

changedListener = new AudioManager.OnAudioFocusChangeListener() {


@Override
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// You now have the audio focus and may play sound.
}
else if (focusChange == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
// Handle the failure.
}
}
}

Read AudioManager online: https://riptutorial.com/android/topic/6798/audiomanager

https://riptutorial.com/ 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 sound.This is done in
the following way.

final int duration = 10; // duration of sound


final int sampleRate = 22050; // Hz (maximum frequency is 7902.13Hz (B8))
final int numSamples = duration * sampleRate;
final double samples[] = new double[numSamples];
final short buffer[] = new short[numSamples];
for (int i = 0; i < numSamples; ++i)
{
samples[i] = Math.sin(2 * Math.PI * i / (sampleRate / note[0])); // Sine wave
buffer[i] = (short) (samples[i] * Short.MAX_VALUE); // Higher amplitude increases volume
}

Now we have to configure AudioTrack to play in accordance with the generated buffer . It is done
in the following manner

AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,


sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, buffer.length,
AudioTrack.MODE_STATIC);

Write the generated buffer and play the track

audioTrack.write(buffer, 0, buffer.length);
audioTrack.play();

Hope this helps :)

Read AudioTrack online: https://riptutorial.com/android/topic/9155/audiotrack

https://riptutorial.com/ 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

Design (layout XML):

<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):

final AutoCompleteTextView myAutoCompleteTextView =


(AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1);

Provide hard-coded data via an adapter:

String[] countries = getResources().getStringArray(R.array.list_of_countries);


ArrayAdapter<String> adapter = new
ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,countries);
myAutoCompleteTextView.setAdapter(adapter);

Tip: Though the preferred way would be to provide data via a Loader of some kind instead of a
hard-coded list like this.

AutoComplete with CustomAdapter, ClickListener and Filter

Main layout : activity_main.xml

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">

https://riptutorial.com/ 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>

Row layout row.xml

<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<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>

strings.xml

<resources>
<string name="hint_enter_name">Enter Name</string>
</resources>

MainActivity.java

public class MainActivity extends AppCompatActivity {


AutoCompleteTextView txtSearch;
List<People> mList;
PeopleAdapter adapter;
private People selectedPerson;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mList = retrievePeople();
txtSearch = (AutoCompleteTextView) findViewById(R.id.auto_name);
adapter = new PeopleAdapter(this, R.layout.activity_main, R.id.lbl_name, mList);
txtSearch.setAdapter(adapter);
txtSearch.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int pos, long id) {
//this is the way to find selected object/item
selectedPerson = (People) adapterView.getItemAtPosition(pos);

https://riptutorial.com/ 191
}
});
}

private List<People> retrievePeople() {


List<People> list = new ArrayList<People>();
list.add(new People("James", "Bond", 1));
list.add(new People("Jason", "Bourne", 2));
list.add(new People("Ethan", "Hunt", 3));
list.add(new People("Sherlock", "Holmes", 4));
list.add(new People("David", "Beckham", 5));
list.add(new People("Bryan", "Adams", 6));
list.add(new People("Arjen", "Robben", 7));
list.add(new People("Van", "Persie", 8));
list.add(new People("Zinedine", "Zidane", 9));
list.add(new People("Luis", "Figo", 10));
list.add(new People("John", "Watson", 11));
return list;
}
}

Model class : People.java

public class People {

private String name, lastName;


private int id;

public People(String name, String lastName, int id) {


this.name = name;
this.lastName = lastName;
this.id = id;
}

public int getId() {


return id;
}

public void setId(int id) {


this.id = id;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}

public String getlastName() {


return lastName;
}

public void setlastName(String lastName) {


this.lastName = lastName;
}
}

https://riptutorial.com/ 192
Adapter class : PeopleAdapter.java

public class PeopleAdapter extends ArrayAdapter<People> {

Context context;
int resource, textViewResourceId;
List<People> items, tempItems, suggestions;

public PeopleAdapter(Context context, int resource, int textViewResourceId, List<People>


items) {
super(context, resource, textViewResourceId, items);
this.context = context;
this.resource = resource;
this.textViewResourceId = textViewResourceId;
this.items = items;
tempItems = new ArrayList<People>(items); // this makes the difference.
suggestions = new ArrayList<People>();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.row, parent, false);
}
People people = items.get(position);
if (people != null) {
TextView lblName = (TextView) view.findViewById(R.id.lbl_name);
if (lblName != null)
lblName.setText(people.getName());
}
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) {
suggestions.clear();
for (People people : tempItems) {
if
(people.getName().toLowerCase().contains(constraint.toString().toLowerCase())) {
suggestions.add(people);
}

https://riptutorial.com/ 193
}
FilterResults filterResults = new FilterResults();
filterResults.values = suggestions;
filterResults.count = suggestions.size();
return filterResults;
} else {
return new FilterResults();
}
}

@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
List<People> filterList = (ArrayList<People>) results.values;
if (results != null && results.count > 0) {
clear();
for (People people : filterList) {
add(people);
notifyDataSetChanged();
}
}
}
};
}

Read AutoCompleteTextView online:


https://riptutorial.com/android/topic/5300/autocompletetextview

https://riptutorial.com/ 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.

You can set up the TextView autosizing in either code or XML.

There are two ways to set autosizing TextView: Granularity and Preset Sizes

Examples
Granularity

In Java:

Call the setAutoSizeTextTypeUniformWithConfiguration() method:

setAutoSizeTextTypeUniformWithConfiguration(int autoSizeMinTextSize, int autoSizeMaxTextSize,


int autoSizeStepGranularity, int unit)

In XML:

Use the autoSizeMinTextSize, autoSizeMaxTextSize, and autoSizeStepGranularity attributes to set the


auto-sizing dimensions in the layout XML file:

<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” />

Check out the AutosizingTextViews-Demo at GitHub for more details.

Preset Sizes

In Java:

https://riptutorial.com/ 195
Call the setAutoSizeTextTypeUniformWithPresetSizes() method:

setAutoSizeTextTypeUniformWithPresetSizes(int[] presetSizes, int unit)

In XML:

Use the autoSizePresetSizes attribute in the layout XML file:

<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/arrays.xml file:

<array name=”autosize_text_sizes”>
<item>10sp</item>
<item>12sp</item>
<item>20sp</item>
<item>40sp</item>
<item>100sp</item>
</array>

Check out the AutosizingTextViews-Demo at GitHub for more details.

Read Autosizing TextViews online: https://riptutorial.com/android/topic/9652/autosizing-textviews

https://riptutorial.com/ 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.

Adding the library to your project


Add QRCodeReaderView dependency to your build.gradle

dependencies{
compile 'com.dlazaro66.qrcodereaderview:qrcodereaderview:2.0.0'
}

First use
• Add to your layout a QRCodeReaderView

<com.dlazaro66.qrcodereaderview.QRCodeReaderView
android:id="@+id/qrdecoderview"
android:layout_width="match_parent"
android:layout_height="match_parent" />

• Create an Activity which implements onQRCodeReadListener, and use it as a listener of the


QrCodeReaderView.
• Make sure you have camera permissions in order to use the library. (
https://developer.android.com/training/permissions/requesting.html)

Then in your Activity, you can use it as follows:

public class DecoderActivity extends Activity implements OnQRCodeReadListener {

private TextView resultTextView;

https://riptutorial.com/ 197
private QRCodeReaderView qrCodeReaderView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_decoder);

qrCodeReaderView = (QRCodeReaderView) findViewById(R.id.qrdecoderview);


qrCodeReaderView.setOnQRCodeReadListener(this);

// Use this function to enable/disable decoding


qrCodeReaderView.setQRDecodingEnabled(true);

// Use this function to change the autofocus interval (default is 5 secs)


qrCodeReaderView.setAutofocusInterval(2000L);

// Use this function to enable/disable Torch


qrCodeReaderView.setTorchEnabled(true);

// Use this function to set front camera preview


qrCodeReaderView.setFrontCamera();

// Use this function to set back camera preview


qrCodeReaderView.setBackCamera();
}

// Called when a QR is decoded


// "text" : the text encoded in QR
// "points" : points where QR control points are placed in View
@Override
public void onQRCodeRead(String text, PointF[] points) {
resultTextView.setText(text);
}

@Override
protected void onResume() {
super.onResume();
qrCodeReaderView.startCamera();
}

@Override
protected void onPause() {
super.onPause();
qrCodeReaderView.stopCamera();
}
}

Read Barcode and QR code reading online: https://riptutorial.com/android/topic/6067/barcode-


and-qr-code-reading

https://riptutorial.com/ 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 object.Working with bitmap in android is tricky.It 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

key key to store bitmap in memory cache

bitmap bitmap value which will cache into memory

Examples
Bitmap Cache Using LRU Cache

LRU Cache

The following example code demonstrates a possible implementation of the LruCache class for
caching images.

private LruCache<String, Bitmap> mMemoryCache;

Here string value is key for bitmap value.

// Get max available VM memory, exceeding this amount will throw an


// OutOfMemory exception. Stored in kilobytes as LruCache takes an
// int in its constructor.
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

https://riptutorial.com/ 199
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;

mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {


@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.getByteCount() / 1024;
}
};

For add bitmap to the memory cache

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {


if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}

For get bitmap from memory cache

public Bitmap getBitmapFromMemCache(String key) {


return mMemoryCache.get(key);
}

For loading bitmap into imageview just use getBitmapFromMemCache("Pass key").

Read Bitmap Cache online: https://riptutorial.com/android/topic/9901/bitmap-cache

https://riptutorial.com/ 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:

<uses-permission android:name="android.permission.BLUETOOTH" />

If you need to initiate device discovery or manipulate Bluetooth settings, you also need to add this
permission:

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

Targetting Android API level 23 and above, will require location access:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />


<!-- OR -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

* Also see the Permissions topic for more details on how to use permissions appropriately.

Check if bluetooth is enabled

private static final int REQUEST_ENABLE_BT = 1; // Unique request code


BluetoothAdapter mBluetoothAdapter;

// ...

if (!mBluetoothAdapter.isEnabled()) {
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) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {

https://riptutorial.com/ 201
// Bluetooth was enabled
} else if (resultCode == RESULT_CANCELED) {
// Bluetooth was not enabled
}
}
}

Make device discoverable

private static final int REQUEST_DISCOVERABLE_BT = 2; // Unique request code


private static final int DISCOVERABLE_DURATION = 120; // Discoverable duration time in seconds
// 0 means always discoverable
// maximum value is 3600

// ...

Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);


discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
DISCOVERABLE_DURATION);
startActivityForResult(discoverableIntent, REQUEST_DISCOVERABLE_BT);

// ...

@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent
data) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == REQUEST_DISCOVERABLE_BT) {
if (resultCode == RESULT_OK) {
// Device is discoverable
} else if (resultCode == RESULT_CANCELED) {
// Device is not discoverable
}
}
}

Find nearby bluetooth devices

Declare a BluetoothAdapter first.

BluetoothAdapter mBluetoothAdapter;

Now create a BroadcastReceiver for ACTION_FOUND

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {


public void onReceive(Context context, Intent intent) {
String action = intent.getAction();

//Device found
if (BluetoothDevice.ACTION_FOUND.equals(action))
{
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a list
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());

https://riptutorial.com/ 202
}
}
};

Register the BroadcastReceiver

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);


registerReceiver(mReceiver, filter);

Then start discovering the nearby bluetooth devices by calling startDiscovery

mBluetoothAdapter.startDiscovery();

Don't forget to unregister the BroadcastReceiver inside onDestroy

unregisterReceiver(mReceiver);

Connect to Bluetooth device

After you obtained BluetoothDevice, you can communicate with it. This kind of communication
performed by using socket input\output streams:

Those are the basic steps for Bluetooth communication establishment:

1) Initialize socket:

private BluetoothSocket _socket;


//...
public InitializeSocket(BluetoothDevice device){
try {
_socket = device.createRfcommSocketToServiceRecord(<Your app UDID>);
} catch (IOException e) {
//Error
}
}

2) Connect to socket:

try {
_socket.connect();
} catch (IOException connEx) {
try {
_socket.close();
} catch (IOException closeException) {
//Error
}
}

if (_socket != null && _socket.isConnected()) {


//Socket is connected, now we can obtain our IO streams
}

https://riptutorial.com/ 203
3) Obtaining socket Input\Output streams

private InputStream _inStream;


private OutputStream _outStream;
//....
try {
_inStream = _socket.getInputStream();
_outStream = _socket.getOutputStream();
} catch (IOException e) {
//Error
}

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:

1) Receiving data (reading from socket input stream)

byte[] buffer = new byte[1024]; // buffer (our data)


int bytesCount; // amount of read bytes

while (true) {
try {
//reading data from input stream
bytesCount = _inStream.read(buffer);
if(buffer != null && bytesCount > 0)
{
//Parse received bytes
}
} catch (IOException e) {
//Error
}
}

2) Sending data (Writing to output stream)

public void write(byte[] bytes) {


try {
_outStream.write(bytes);
} catch (IOException e) {
//Error
}
}

• Of course, connection, reading and writing functionality should be done in a dedicated


thread.
• Sockets and Stream objects need to be

Find nearby Bluetooth Low Energy devices

The BluetoothLE API was introduced in API 18. However, the way of scanning devices has

https://riptutorial.com/ 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:

1. Create bluetooth device model:

public class BTDevice {


String address;
String name;

public String getAddress() {


return address;
}

public void setAddress(String address) {


this.address = address;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}
}

2. Define Bluetooth Scanning interface:

public interface ScanningAdapter {

void startScanning(String name, String[] uuids);


void stopScanning();
List<BTDevice> getFoundDeviceList();
}

3. Create scanning factory class:

public class BluetoothScanningFactory implements ScanningAdapter {

private ScanningAdapter mScanningAdapter;

public BluetoothScanningFactory() {
if (isNewerAPI()) {
mScanningAdapter = new LollipopBluetoothLEScanAdapter();
} else {
mScanningAdapter = new JellyBeanBluetoothLEScanAdapter();
}
}

private boolean isNewerAPI() {


return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}

@Override
public void startScanning(String[] uuids) {
mScanningAdapter.startScanning(uuids);

https://riptutorial.com/ 205
}

@Override
public void stopScanning() {
mScanningAdapter.stopScanning();
}

@Override
public List<BTDevice> getFoundDeviceList() {
return mScanningAdapter.getFoundDeviceList();
}
}

4. Create factory implementation for each API:

API 18:

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.os.Build;
import android.os.Parcelable;
import android.util.Log;

import bluetooth.model.BTDevice;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class JellyBeanBluetoothLEScanAdapter implements ScanningAdapter{
BluetoothAdapter bluetoothAdapter;
ScanCallback mCallback;

List<BTDevice> mBluetoothDeviceList;

public JellyBeanBluetoothLEScanAdapter() {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mCallback = new ScanCallback();
mBluetoothDeviceList = new ArrayList<>();
}

@Override
public void startScanning(String[] uuids) {
if (uuids == null || uuids.length == 0) {
return;
}
UUID[] uuidList = createUUIDList(uuids);
bluetoothAdapter.startLeScan(uuidList, mCallback);
}

private UUID[] createUUIDList(String[] uuids) {


UUID[] uuidList = new UUID[uuids.length];
for (int i = 0 ; i < uuids.length ; ++i) {
String uuid = uuids[i];
if (uuid == null) {
continue;
}
uuidList[i] = UUID.fromString(uuid);

https://riptutorial.com/ 206
}
return uuidList;
}

@Override
public void stopScanning() {
bluetoothAdapter.stopLeScan(mCallback);
}

@Override
public List<BTDevice> getFoundDeviceList() {
return mBluetoothDeviceList;
}

private class ScanCallback implements BluetoothAdapter.LeScanCallback {

@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (isAlreadyAdded(device)) {
return;
}
BTDevice btDevice = new BTDevice();
btDevice.setName(new String(device.getName()));
btDevice.setAddress(device.getAddress());
mBluetoothDeviceList.add(btDevice);
Log.d("Bluetooth discovery", device.getName() + " " + device.getAddress());
Parcelable[] uuids = device.getUuids();
String uuid = "";
if (uuids != null) {
for (Parcelable ep : uuids) {
uuid += ep + " ";
}
Log.d("Bluetooth discovery", device.getName() + " " + device.getAddress() + "
" + uuid);
}
}

private boolean isAlreadyAdded(BluetoothDevice bluetoothDevice) {


for (BTDevice device : mBluetoothDeviceList) {
String alreadyAddedDeviceMACAddress = device.getAddress();
String newDeviceMACAddress = bluetoothDevice.getAddress();
if (alreadyAddedDeviceMACAddress.equals(newDeviceMACAddress)) {
return true;
}
}
return false;
}
}
}

API 21:

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.os.Build;
import android.os.ParcelUuid;

https://riptutorial.com/ 207
import bluetooth.model.BTDevice;

import java.util.ArrayList;
import java.util.List;

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class LollipopBluetoothLEScanAdapter implements ScanningAdapter {
BluetoothLeScanner bluetoothLeScanner;
ScanCallback mCallback;

List<BTDevice> mBluetoothDeviceList;

public LollipopBluetoothLEScanAdapter() {
bluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
mCallback = new ScanCallback();
mBluetoothDeviceList = new ArrayList<>();
}

@Override
public void startScanning(String[] uuids) {
if (uuids == null || uuids.length == 0) {
return;
}
List<ScanFilter> filterList = createScanFilterList(uuids);
ScanSettings scanSettings = createScanSettings();
bluetoothLeScanner.startScan(filterList, scanSettings, mCallback);
}

private List<ScanFilter> createScanFilterList(String[] uuids) {


List<ScanFilter> filterList = new ArrayList<>();
for (String uuid : uuids) {
ScanFilter filter = new ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString(uuid))
.build();
filterList.add(filter);
};
return filterList;
}

private ScanSettings createScanSettings() {


ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_BALANCED)
.build();
return settings;
}

@Override
public void stopScanning() {
bluetoothLeScanner.stopScan(mCallback);
}

@Override
public List<BTDevice> getFoundDeviceList() {
return mBluetoothDeviceList;
}

public class ScanCallback extends android.bluetooth.le.ScanCallback {

@Override
public void onScanResult(int callbackType, ScanResult result) {

https://riptutorial.com/ 208
super.onScanResult(callbackType, result);
if (result == null) {
return;
}
BTDevice device = new BTDevice();
device.setAddress(result.getDevice().getAddress());
device.setName(new
StringBuffer(result.getScanRecord().getDeviceName()).toString());
if (device == null || device.getAddress() == null) {
return;
}
if (isAlreadyAdded(device)) {
return;
}
mBluetoothDeviceList.add(device);
}

private boolean isAlreadyAdded(BTDevice bluetoothDevice) {


for (BTDevice device : mBluetoothDeviceList) {
String alreadyAddedDeviceMACAddress = device.getAddress();
String newDeviceMACAddress = bluetoothDevice.getAddress();
if (alreadyAddedDeviceMACAddress.equals(newDeviceMACAddress)) {
return true;
}
}
return false;
}
}
}

5. Get found device list by calling:

scanningFactory.startScanning({uuidlist});

wait few seconds...

List<BTDevice> bluetoothDeviceList = scanningFactory.getFoundDeviceList();

Read Bluetooth and Bluetooth LE API online: https://riptutorial.com/android/topic/2462/bluetooth-


and-bluetooth-le-api

https://riptutorial.com/ 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

The following permissions are required to use the Bluetooth APIs:

android.permission.BLUETOOTH
android.permission.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:

android.permission.ACCESS_FINE_LOCATION

or

android.permission.ACCESS_COARSE_LOCATION

Note.- Devices with Android 6.0 (API Level 23) or higher also need to have Location
Services enabled.

A BluetoothAdapter object is required to start scanning/advertising operations:

BluetoothManager bluetoothManager = (BluetoothManager)


context.getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();

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:

bluetoothAdapter.getBluetoothLeScanner().startScan(new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.i(TAG, "Remote device name: " + result.getDevice().getName());
}
});

https://riptutorial.com/ 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:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {


device.connectGatt(context, false, bluetoothGattCallback,
BluetoothDevice.TRANSPORT_AUTO);
} else {
device.connectGatt(context, false, bluetoothGattCallback);
}

Override onConnectionStateChange in BluetoothGattCallback to receive connection an disconnection


events:

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.");

} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {

Log.i(TAG, "Disconnected from GATT server.");


}
}
};

Writing and Reading from Characteristics

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.");
gatt.discoverServices();

}
. . .

@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService service : services) {
List<BluetoothGattCharacteristic> characteristics =

https://riptutorial.com/ 211
service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristics) {
///Once you have a characteristic object, you can perform read/write
//operations with it
}
}
}
}

A basic write operation goes like this:

characteristic.setValue(newValue);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
gatt.writeCharacteristic(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) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d(TAG, "Characteristic " + characteristic.getUuid() + " written);
}

A basic write operation goes like this:

gatt.readCharacteristic(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) {
super.onCharacteristicRead(gatt, characteristic, status);
byte[] value = characteristic.getValue();
}

Subscribing to Notifications from the Gatt Server

You can request to be notified from the Gatt Server when the value of a characteristic has been
changed:

gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);

All notifications from the server will be received in the onCharacteristicChanged method of your
BluetoothGattCallback:

https://riptutorial.com/ 212
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
byte[] newValue = characteristic.getValue();
}

Advertising a BLE Device

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:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&


bluetoothAdapter.isMultipleAdvertisementSupported())
{
BluetoothLeAdvertiser advertiser = bluetoothAdapter.getBluetoothLeAdvertiser();

AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();


//Define a service UUID according to your needs
dataBuilder.addServiceUuid(SERVICE_UUID);
dataBuilder.setIncludeDeviceName(true);

AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();


settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER);
settingsBuilder.setTimeout(0);

//Use the connectable flag if you intend on opening a Gatt Server


//to allow remote connections to your device.
settingsBuilder.setConnectable(true);

AdvertiseCallback advertiseCallback=new AdvertiseCallback() {


@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
Log.i(TAG, "onStartSuccess: ");
}

@Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
Log.e(TAG, "onStartFailure: "+errorCode );
}
};
advertising.startAdvertising(settingsBuilder.build(),dataBuilder.build(),advertiseCallback);
}

Using a Gatt Server

In order for your device to act as a peripheral, first you need to open a BluetoothGattServer and

https://riptutorial.com/ 213
populate it with at least one BluetoothGattService and one BluetoothGattCharacteristic:

BluetoothGattServer server=bluetoothManager.openGattServer(context,
bluetoothGattServerCallback);

BluetoothGattService service = new BluetoothGattService(SERVICE_UUID,


BluetoothGattService.SERVICE_TYPE_PRIMARY);

This is an example of a BluetoothGattCharacteristic with full write,read and notify permissions.


According to your needs, you might want to fine tune the permissions that you grant this
characteristic:

BluetoothGattCharacteristic characteristic = new


BluetoothGattCharacteristic(CHARACTERISTIC_UUID,
BluetoothGattCharacteristic.PROPERTY_READ |
BluetoothGattCharacteristic.PROPERTY_WRITE |
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ |
BluetoothGattCharacteristic.PERMISSION_WRITE);

characteristic.addDescriptor(new BluetoothGattDescriptor(UUID.fromString("00002902-0000-1000-
8000-00805f9b34fb"), BluetoothGattCharacteristic.PERMISSION_WRITE));

service.addCharacteristic(characteristic);

server.addService(service);

The BluetoothGattServerCallback is responsible for receiving all events related to your


BluetoothGattServer:

BluetoothGattServerCallback bluetoothGattServerCallback= new BluetoothGattServerCallback() {


@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int
newState) {
super.onConnectionStateChange(device, status, newState);
}

@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
int offset, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicReadRequest(device, requestId, offset,
characteristic);
}

@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int
requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean
responseNeeded, int offset, byte[] value) {
super.onCharacteristicWriteRequest(device, requestId, characteristic,
preparedWrite, responseNeeded, offset, value);
}

@Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int
offset, BluetoothGattDescriptor descriptor) {
super.onDescriptorReadRequest(device, requestId, offset, descriptor);
}

https://riptutorial.com/ 214
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset,
byte[] value) {
super.onDescriptorWriteRequest(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) {
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
server.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, YOUR_RESPONSE);
}

Read Bluetooth Low Energy online: https://riptutorial.com/android/topic/10020/bluetooth-low-


energy

https://riptutorial.com/ 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

This example depends on Support Library 23.4.0.+.

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.

Now let's check them one by one:

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:

• create a Behavior and extend it from AppBarLayout.ScrollingViewBehavior


• override layoutDependsOn and onDependentViewChanged methods. Doing it you will listen for
bottomSheet movements.
• create some methods to hide and unhide the AppBarLayout/ToolBar with animations.

https://riptutorial.com/ 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;
}

float dVerticalScroll = dependency.getY() - mPreviousY;


mPreviousY = dependency.getY();

//going up
if (dVerticalScroll <= 0 && !hidden) {
dismissAppBar(child);
return true;
}

return false;
}

private void initValues(final View child, View dependency) {

mChild = child;
mInitialY = child.getY();

BottomSheetBehaviorGoogleMapsLike bottomSheetBehavior =
BottomSheetBehaviorGoogleMapsLike.from(dependency);
bottomSheetBehavior.addBottomSheetCallback(new
BottomSheetBehaviorGoogleMapsLike.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet,
@BottomSheetBehaviorGoogleMapsLike.State int newState) {
if (newState == BottomSheetBehaviorGoogleMapsLike.STATE_COLLAPSED ||
newState == BottomSheetBehaviorGoogleMapsLike.STATE_HIDDEN)
showAppBar(child);
}

@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {

}
});
}

private void dismissAppBar(View child){


hidden = true;
AppBarLayout appBarLayout = (AppBarLayout)child;
mToolbarAnimation =
appBarLayout.animate().setDuration(mContext.getResources().getInteger(android.R.integer.config_shortAni

mToolbarAnimation.y(-(mChild.getHeight()+25)).start();
}

https://riptutorial.com/ 217
private void showAppBar(View child) {
hidden = false;
AppBarLayout appBarLayout = (AppBarLayout)child;
mToolbarAnimation =
appBarLayout.animate().setDuration(mContext.getResources().getInteger(android.R.integer.config_mediumAn

mToolbarAnimation.y(mInitialY).start();
}

Here is the complete file if you need it

The second Toolbar or "Modal" toolbar:


You have to override the same methods, but in this one you have to take care of more behaviors:

• show/hide the ToolBar with animations


• change status bar color/background
• show/hide the BottomSheet title in the ToolBar
• close the bottomSheet or send it to collapsed state

The code for this one is a little extensive, so I will let the link

The FAB

This is a Custom Behavior too, but extends from FloatingActionButton.Behavior. In


onDependentViewChanged you have to look when it reach the "offSet" or point in where you want to
hide it. In my case I want to hide it when it's near to the second toolbar, so I dig into FAB parent (a
CoordinatorLayout) looking for the AppBarLayout that contains the ToolBar, then I use the ToolBar
position like OffSet:

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child,
View dependency) {

if (offset == 0)
setOffsetValue(parent);

if (dependency.getY() <=0)
return false;

if (child.getY() <= (offset + child.getHeight()) && child.getVisibility() == View.VISIBLE)


child.hide();
else if (child.getY() > offset && child.getVisibility() != View.VISIBLE)
child.show();

return false;
}

Complete Custom FAB Behavior link

The image behind the BottomSheet with parallax effect:

https://riptutorial.com/ 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;
}

float dVerticalScroll = dependency.getY() - mPreviousY;


mPreviousY = dependency.getY();

//going up
if (dVerticalScroll <= 0 && child.getY() <= 0) {
child.setY(0);
return true;
}

//going down
if (dVerticalScroll >= 0 && dependency.getY() <= mImageHeight)
return false;

child.setY( (int)(child.getY() + (dVerticalScroll * mYmultiplier) ) );

return true;
}

The complete file for backdrop image with parallax effect

Now for the end: The Custom BottomSheet Behavior


To achieve the 3 steps, first you need to understand that default BottomSheetBehavior has 5
states: STATE_DRAGGING, STATE_SETTLING, STATE_EXPANDED, STATE_COLLAPSED, STATE_HIDDEN and for the
Google Maps behavior you need to add a middle state between collapsed and expanded:
STATE_ANCHOR_POINT.
I tried to extend the default bottomSheetBehavior with no success, so I just copy pasted all the
code and modified what I need.
To achieve what I'm talking about follow the next steps:

1. Create a Java class and extend it from CoordinatorLayout.Behavior<V>

2. Copy paste code from default BottomSheetBehavior file to your new one.

3. Modify the method clampViewPositionVertical with the following code:

@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);

https://riptutorial.com/ 219
}
int constrain(int amount, int low, int high) {
return amount < low ? low : (amount > high ? high : amount);
}

4. Add a new state

public static final int STATE_ANCHOR_POINT = X;

5. Modify the next methods: onLayoutChild, onStopNestedScroll, BottomSheetBehavior<V> from(V


view) and setState (optional)

public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {


// First let the parent lay it out
if (mState != STATE_DRAGGING && mState != STATE_SETTLING) {
if (ViewCompat.getFitsSystemWindows(parent) &&
!ViewCompat.getFitsSystemWindows(child)) {
ViewCompat.setFitsSystemWindows(child, true);
}
parent.onLayoutChild(child, layoutDirection);
}
// Offset the bottom sheet
mParentHeight = parent.getHeight();
mMinOffset = Math.max(0, mParentHeight - child.getHeight());
mMaxOffset = Math.max(mParentHeight - mPeekHeight, mMinOffset);

//if (mState == STATE_EXPANDED) {


// ViewCompat.offsetTopAndBottom(child, mMinOffset);
//} else if (mHideable && mState == STATE_HIDDEN...
if (mState == STATE_ANCHOR_POINT) {
ViewCompat.offsetTopAndBottom(child, mAnchorPoint);
} else if (mState == STATE_EXPANDED) {
ViewCompat.offsetTopAndBottom(child, mMinOffset);
} else if (mHideable && mState == STATE_HIDDEN) {
ViewCompat.offsetTopAndBottom(child, mParentHeight);
} else if (mState == STATE_COLLAPSED) {
ViewCompat.offsetTopAndBottom(child, mMaxOffset);
}
if (mViewDragHelper == null) {
mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
}
mViewRef = new WeakReference<>(child);
mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
return true;
}

public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {


if (child.getTop() == mMinOffset) {
setStateInternal(STATE_EXPANDED);
return;
}
if (target != mNestedScrollingChildRef.get() || !mNestedScrolled) {
return;
}

https://riptutorial.com/ 220
int top;
int targetState;
if (mLastNestedScrollDy > 0) {
//top = mMinOffset;
//targetState = STATE_EXPANDED;
int currentTop = child.getTop();
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 = child.getTop();
if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) {
top = mMinOffset;
targetState = STATE_EXPANDED;
} else {
top = mMaxOffset;
targetState = STATE_COLLAPSED;
}
} else {
//top = mMaxOffset;
//targetState = STATE_COLLAPSED;
int currentTop = child.getTop();
if (currentTop > mAnchorPoint) {
top = mMaxOffset;
targetState = STATE_COLLAPSED;
}
else {
top = mAnchorPoint;
targetState = STATE_ANCHOR_POINT;
}
}
if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
setStateInternal(STATE_SETTLING);
ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState));
} else {
setStateInternal(targetState);
}
mNestedScrolled = false;
}

public final void setState(@State int state) {


if (state == mState) {
return;
}
if (mViewRef == null) {
// The view is not laid out yet; modify mState and let onLayoutChild handle it later
/**
* New behavior (added: state == STATE_ANCHOR_POINT ||)
*/
if (state == STATE_COLLAPSED || state == STATE_EXPANDED ||
state == STATE_ANCHOR_POINT ||
(mHideable && state == STATE_HIDDEN)) {
mState = state;

https://riptutorial.com/ 221
}
return;
}
V child = mViewRef.get();
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 (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
}
}

public static <V extends View> BottomSheetBehaviorGoogleMapsLike<V> from(V view) {


ViewGroup.LayoutParams params = view.getLayoutParams();
if (!(params instanceof CoordinatorLayout.LayoutParams)) {
throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
}
CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
.getBehavior();
if (!(behavior instanceof BottomSheetBehaviorGoogleMapsLike)) {
throw new IllegalArgumentException(
"The view is not associated with BottomSheetBehaviorGoogleMapsLike");
}
return (BottomSheetBehaviorGoogleMapsLike<V>) behavior;
}

Link to the whole project where you can see all the Custom Behaviors

And here it is how it looks like:


[

https://riptutorial.com/ 222
]

Quick Setup

Make sure the following dependency is added to your app's build.gradle file under dependencies:

compile 'com.android.support:design:25.3.1'

Then you can use the Bottom sheet using these options:

• BottomSheetBehavior to be used with CoordinatorLayout


• BottomSheetDialog which is a dialog with a bottom sheet behavior
• BottomSheetDialogFragment which is an extension of DialogFragment, that creates a
BottomSheetDialog instead of a standard dialog.

Persistent Bottom Sheets

You can achieve a Persistent Bottom Sheet attaching a BottomSheetBehavior to a child View of a
CoordinatorLayout:

<android.support.design.widget.CoordinatorLayout >

https://riptutorial.com/ 223
<!-- ..... -->

<LinearLayout
android:id="@+id/bottom_sheet"
android:elevation="4dp"
android:minHeight="120dp"
app:behavior_peekHeight="120dp"
...
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">

<!-- ..... -->

</LinearLayout>

</android.support.design.widget.CoordinatorLayout>

Then in your code you can create a reference using:

// The View with the BottomSheetBehavior


View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);
BottomSheetBehavior mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);

You can set the state of your BottomSheetBehavior using the setState() method:

mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);

You can use one of these states:

• 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

• STATE_HIDDEN: disabled by default (and enabled with the app:behavior_hideable attribute),


enabling this allows users to swipe down on the bottom sheet to completely hide the bottom
sheet

If you’d like to receive callbacks of state changes, you can add a BottomSheetCallback:

mBottomSheetBehavior.setBottomSheetCallback(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
}
});

https://riptutorial.com/ 224
Modal bottom sheets with BottomSheetDialogFragment

You can realize a modal bottom sheets using a BottomSheetDialogFragment.

The BottomSheetDialogFragment is a modal bottom sheet.


This is a version of DialogFragment that shows a bottom sheet using BottomSheetDialog instead of a
floating dialog.

Just define the fragment:

public class MyBottomSheetDialogFragment extends BottomSheetDialogFragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.my_fragment_bottom_sheet, container);
}
}

Then use this code to show the fragment:

MyBottomSheetDialogFragment mySheetDialog = new MyBottomSheetDialogFragment();


FragmentManager fm = getSupportFragmentManager();
mySheetDialog.show(fm, "modalSheetDialog");

This Fragment will create a BottomSheetDialog.

Modal bottom sheets with BottomSheetDialog

The BottomSheetDialog is a dialog styled as a bottom sheet

Just use:

//Create a new BottomSheetDialog


BottomSheetDialog dialog = new BottomSheetDialog(context);
//Inflate the layout R.layout.my_dialog_layout
dialog.setContentView(R.layout.my_dialog_layout);
//Show the dialog
dialog.show();

In this case you don't need to attach a BottomSheet behavior.

Open BottomSheet DialogFragment in Expanded mode by default.

BottomSheet DialogFragment opens up in STATE_COLLAPSED by default. Which can be forced to open


to STATE_EXPANDEDand take up the full device screen with help of the following code template.

@NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) {

BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);

https://riptutorial.com/ 225
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
BottomSheetDialog d = (BottomSheetDialog) dialog;

FrameLayout bottomSheet = (FrameLayout)


d.findViewById(android.support.design.R.id.design_bottom_sheet);

BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
}
});

// Do something with your dialog like setContentView() or whatever


return dialog;
}

Although dialog animation is slightly noticeable but does the task of opening the DialogFragment
in full screen very well.

Read Bottom Sheets online: https://riptutorial.com/android/topic/5702/bottom-sheets

https://riptutorial.com/ 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

To add the BottomNavigationView follow these steps:

1. Add in your build.gradle the dependency:

compile 'com.android.support:design:25.1.0'

2. Add the BottomNavigationView in your layout:

<android.support.design.widget.BottomNavigationView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_navigation_menu"/>

3. Create the menu to populate the view:

<!-- res/menu/bottom_navigation_menu.xml -->

https://riptutorial.com/ 227
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/my_action1"
android:enabled="true"
android:icon="@drawable/my_drawable"
android:title="@string/text"
app:showAsAction="ifRoom" />
....
</menu>

4. Attach a listener for the click events:

//Get the view


BottomNavigationView bottomNavigationView = (BottomNavigationView)
findViewById(R.id.bottom_navigation);
//Attach the listener
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {

case R.id.my_action1:
//Do something...
break;

//...
}
return true;//returning false disables the Navigation bar animations
}
});

Checkout demo code at BottomNavigation-Demo

Customization of BottomNavigationView

Note : I am assuming that you know about how to use BottomNavigationView.

This example I will explain how to add selector for BottomNavigationView. So you can state on UI for
icons and texts.

Create drawable bottom_navigation_view_selector.xml as

<?xml version="1.0" encoding="utf-8"?>


<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/bottom_nv_menu_selected" android:state_checked="true" />
<item android:color="@color/bottom_nv_menu_default" />
</selector>

And use below attributes into BottomNavigationView in layout file

app:itemIconTint="@drawable/bottom_navigation_view_selector"

https://riptutorial.com/ 228
app:itemTextColor="@drawable/bottom_navigation_view_selector"

In above example, I have used same selector bottom_navigation_view_selector for


app:itemIconTint and app:itemTextColor both to keep text and icon colors same. But if
your design has different color for text and icon, you can define 2 different selectors
and use them.

Output will be similar to below

Handling Enabled / Disabled states

Create Selector for Enable/Disable Menu Item.

selector.xml

<?xml version="1.0" encoding="utf-8"?>


<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/white" android:state_enabled="true" />
<item android:color="@color/colorPrimaryDark" android:state_enabled="false" />
</selector>

design.xml

<android.support.design.widget.BottomNavigationView
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" />

Allowing more than 3 menus

This example is strictly a workaround since, currently there is no way to disable a behaviour
known as ShiftMode.

Create a function as such.

https://riptutorial.com/ 229
public static void disableMenuShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
try {
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
shiftingMode.setAccessible(true);
shiftingMode.setBoolean(menuView, false);
shiftingMode.setAccessible(false);
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
//noinspection RestrictedApi
item.setShiftingMode(false);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
item.setChecked(item.getItemData().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

BottomNavigationView navView = (BottomNavigationView)


findViewById(R.id.bottom_navigation_bar);
disableMenuShiftMode(navView);

Proguard Issue : Add following line proguard configuration file as well else, this wouldn't work.

-keepclassmembers class android.support.design.internal.BottomNavigationMenuView {


boolean mShiftingMode;
}

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.

Read BottomNavigationView online:


https://riptutorial.com/android/topic/7565/bottomnavigationview

https://riptutorial.com/ 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 AndroidManifest.xml file or dynamically via the
Context.registerReceiver() method.

public class MyReceiver extends BroadcastReceiver {


@Override
public void onReceive(Context context, Intent intent) {
//Your implementation goes here.
}
}

Here I have taken an example of ACTION_BOOT_COMPLETED which is fired by the system once the
Android has completed the boot process.

You can register a reciever in manifest file like this:

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<receiver android:name="MyReceiver">
<intent-filter>
<action android:name="android.intent.action.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.

https://riptutorial.com/ 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:

mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//Your implementation goes here.
}
}, new IntentFilter("Some Action"));

or in the AndroidManifest.xml file:

<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:

mContext.sendBroadcast(new Intent("Some Action"));

Additionally, the Intent can contain information, such as Strings, primitives, and Parcelables, that
can be viewed in onReceive.

Using LocalBroadcastManager

LocalBroadcastManager is used to send Broadcast Intents within an application, without exposing


them to unwanted listeners.

Using LocalBroadcastManager is more efficient and safer than using context.sendBroadcast()


directly, because you don't need to worry about any broadcasts faked by other Applications, which
may pose a security hazard.

Here is a simple example of sending and receiving local broadcasts:

BroadcastReceiver receiver = new BroadcastReceiver() {


@Override
public void onReceive(Context context, Intent intent) {

https://riptutorial.com/ 232
if (intent.getAction().equals("Some Action")) {
//Do something
}
}
});

LocalBroadcastManager manager = LocalBroadcastManager.getInstance(mContext);


manager.registerReceiver(receiver, new IntentFilter("Some Action"));

// onReceive() will be called as a result of this call:


manager.sendBroadcast(new Intent("Some Action"));//See also sendBroadcastSync

//Remember to unregister the receiver when you are done with it:
manager.unregisterReceiver(receiver);

Bluetooth Broadcast receiver

add permission in your manifest file

<uses-permission android:name="android.permission.BLUETOOTH" />

In your Fragment(or Activity)


• Add the receiver method

private BroadcastReceiver mBluetoothStatusChangedReceiver = new BroadcastReceiver() {


@Override
public void onReceive(Context context, Intent intent) {
final Bundle extras = intent.getExtras();
final int bluetoothState = extras.getInt(Constants.BUNDLE_BLUETOOTH_STATE);
switch(bluetoothState) {
case BluetoothAdapter.STATE_OFF:
// Bluetooth OFF
break;
case BluetoothAdapter.STATE_TURNING_OFF:
// Turning OFF
break;
case BluetoothAdapter.STATE_ON:
// Bluetooth ON
break;
case BluetoothAdapter.STATE_TURNING_ON:
// Turning ON
break;
}
};

Register broadcast

• Call this method on onResume()

private void registerBroadcastManager(){


final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getActivity());
manager.registerReceiver(mBluetoothStatusChangedReceiver, new
IntentFilter(Constants.BROADCAST_BLUETOOTH_STATE));

https://riptutorial.com/ 233
}

Unregister broadcast

• Call this method on onPause()

private void unregisterBroadcastManager(){


final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getActivity());
// Beacon
manager.unregisterReceiver(mBluetoothStatusChangedReceiver);
}

Enabling and disabling a Broadcast Receiver programmatically

To enable or disable a BroadcastReceiver, we need to get a reference to the PackageManager and we


need a ComponentName object containing the class of the receiver we want to enable/disable:

ComponentName componentName = new ComponentName(context, MyBroadcastReceiver.class);


PackageManager packageManager = context.getPackageManager();

Now we can call the following method to enable the BroadcastReceiver:

packageManager.setComponentEnabledSetting(
componentName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);

Or we can instead use COMPONENT_ENABLED_STATE_DISABLED to disable the receiver:

packageManager.setComponentEnabledSetting(
componentName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);

BroadcastReceiver to handle BOOT_COMPLETED events

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.

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

https://riptutorial.com/ 234
package="com.test.example" >
...
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

...

<application>
...

<receiver android:name="com.test.example.MyCustomBroadcastReceiver">
<intent-filter>
<!-- REGISTER TO RECEIVE BOOT_COMPLETED EVENTS -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>

MyCustomBroadcastReceiver.java

public class MyCustomBroadcastReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();

if(action != null) {
if (action.equals(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 BroadcastReceiver is basically a mechanism to relay Intents through the OS to perform specific


actions. A classic definition being

"A Broadcast receiver is an Android component which allows you to register for system
or application events."

LocalBroadcastManager is a way to send or receive broadcasts within an application process.


This mechanism has a lot of advantages

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.

A simple example of a LocalBroastManager is:

SenderActivity

https://riptutorial.com/ 235
Intent intent = new Intent("anEvent");
intent.putExtra("key", "This is an event");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

ReceiverActivity

1. Register a receiver

LocalBroadcastManager.getInstance(this).registerReceiver(aLBReceiver,
new IntentFilter("anEvent"));

2. A concrete object for performing action when the receiver is called

private BroadcastReceiver aLBReceiver = new BroadcastReceiver() {


@Override
public void onReceive(Context context, Intent intent) {
// perform action here.
}
};

3. unregister when the view is not visible any longer.

@Override
protected void onPause() {
// Unregister since the activity is about to be closed.
LocalBroadcastManager.getInstance(this).unregisterReceiver(aLBReceiver);
super.onDestroy();
}

Communicate two activities through custom Broadcast receiver

You can communicate two activities so that Activity A can be notified of an event happening in
Activity B.

Activity A

final String eventName = "your.package.goes.here.EVENT";

@Override
protected void onCreate(Bundle savedInstanceState) {
registerEventReceiver();
super.onCreate(savedInstanceState);
}

@Override
protected void onDestroy() {
unregisterEventReceiver(eventReceiver);
super.onDestroy();
}

private void registerEventReceiver() {


IntentFilter eventFilter = new IntentFilter();
eventFilter.addAction(eventName);
registerReceiver(eventReceiver, eventFilter);

https://riptutorial.com/ 236
}

private BroadcastReceiver eventReceiver = new BroadcastReceiver() {


@Override
public void onReceive(Context context, Intent intent) {
//This code will be executed when the broadcast in activity B is launched
}
};

Activity B

final String eventName = "your.package.goes.here.EVENT";

private void launchEvent() {


Intent eventIntent = new Intent(eventName);
this.sendBroadcast(eventIntent);
}

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

If we are using method sendStickyBroadcast(intent) the corresponding intent is sticky, meaning


the intent you are sending stays around after broadcast is complete. A StickyBroadcast as the
name suggests is a mechanism to read the data from a broadcast, after the broadcast is complete.
This can be used in a scenario where you may want to check say in an Activity's onCreate() the
value of a key in the intent before that Activity was launched.

Intent intent = new Intent("com.org.action");


intent.putExtra("anIntegerKey", 0);
sendStickyBroadcast(intent);

Using ordered broadcasts

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:

final int highPriority = 2;


final int lowPriority = 1;
final String action = "action";

// intent filter for first receiver with high priority


final IntentFilter firstFilter = new IntentFilter(action);
first Filter.setPriority(highPriority);
final BroadcastReceiver firstReceiver = new MyReceiver();

// intent filter for second receiver with low priority


final IntentFilter secondFilter = new IntentFilter(action);
secondFilter.setPriority(lowPriority);
final BroadcastReceiver secondReceiver = new MyReceiver();

https://riptutorial.com/ 237
// register our receivers
context.registerReceiver(firstReceiver, firstFilter);
context.registerReceiver(secondReceiver, secondFilter);

// send ordered broadcast


context.sendOrderedBroadcast(new Intent(action), null);

Furthermore broadcast receiver can abort ordered broadcast:

@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.

Android stopped state

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:

Intent intent = new Intent();


intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setComponent(new ComponentName(packageName, fullClassName));
sendBroadcast(intent);

Read BroadcastReceiver online: https://riptutorial.com/android/topic/1460/broadcastreceiver

https://riptutorial.com/ 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(R.color.colorAccent));

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:

https://riptutorial.com/ 239
https://riptutorial.com/ 240
https://riptutorial.com/android/topic/4291/building-backwards-compatible-apps

https://riptutorial.com/ 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(R.id.view) 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.

• Eliminate findViewById calls by using @BindView on fields.


• Group multiple views in a list or array. Operate on all of them at once with actions, setters, or
properties.
• Eliminate anonymous inner-classes for listeners by annotating methods with @OnClick and
others.
• Eliminate resource lookups by using resource annotations on fields.

More info: http://jakewharton.github.io/butterknife/

License

Copyright 2013 Jake Wharton

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

http://www.apache.org/licenses/LICENSE-2.0

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

https://riptutorial.com/ 242
Configure your project-level build.gradle to include the android-apt plugin:

buildscript {
repositories {
mavenCentral()
}

dependencies {
classpath 'com.jakewharton:butterknife-gradle-plugin:8.5.1'
}
}

Then, apply the android-apt plugin in your module-level build.gradle and add the ButterKnife
dependencies:

apply plugin: 'android-apt'

android {
...
}

dependencies {
compile 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton: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:

class ExampleActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Binding annotations
ButterKnife.bind(this);
// ...
}

// Or
class ExampleFragment extends Fragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(getContentView(), container, false);
// Binding annotations
ButterKnife.bind(this, view);

https://riptutorial.com/ 243
// ...
return view;
}

Snapshots of the development version are available in Sonatype's snapshots repository.

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 build.gradle:

buildscript {
dependencies {
classpath 'com.jakewharton:butterknife-gradle-plugin:8.5.1'
}
}

…and then apply to your module by adding these lines on the top of your library-level build.gradle:

apply plugin: 'com.android.library'


// ...
apply plugin: 'com.jakewharton.butterknife'

Now make sure you use R2 instead of R inside all ButterKnife annotations.

class ExampleActivity extends Activity {

// Bind xml resource to their View


@BindView(R2.id.user) EditText username;
@BindView(R2.id.pass) EditText password;

// Binding resources from drawable,strings,dimens,colors


@BindString(R.string.choose) String choose;
@BindDrawable(R.drawable.send) Drawable send;
@BindColor(R.color.cyan) int cyan;
@BindDimen(R.dimen.margin) Float generalMargin;

// Listeners
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}

// bind with butterknife in onCreate


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
// TODO continue
}

https://riptutorial.com/ 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

class ExampleActivity extends Activity {


@BindView(R.id.title) TextView title;
@BindView(R.id.subtitle) TextView subtitle;
@BindView(R.id.footer) TextView footer;

@Override public void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}

Binding Views in Fragments

public class FancyFragment extends Fragment {


@BindView(R.id.button1) Button button1;
@BindView(R.id.button2) Button button2;
private Unbinder unbinder;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
unbinder = ButterKnife.bind(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() {
super.onDestroy();
unbinder.unbind();
}
}

Binding Views in Dialogs


We can use ButterKnife.findById to find views on a View, Activity, or Dialog. It uses generics to

https://riptutorial.com/ 245
infer the return type and automatically performs the cast.

View view = LayoutInflater.from(context).inflate(R.layout.thing, null);


TextView firstName = ButterKnife.findById(view, R.id.first_name);
TextView lastName = ButterKnife.findById(view, R.id.last_name);
ImageView photo = ButterKnife.findById(view, R.id.photo);

Binding Views in ViewHolder


static class ViewHolder {
@BindView(R.id.title) TextView name;
@BindView(R.id.job_title) TextView jobTitle;

public ViewHolder(View view) {


ButterKnife.bind(this, view);
}
}

Binding Resources
Apart from being useful for binding views, one could also use ButterKnife to bind resources such
as those defined within strings.xml, drawables.xml, colors.xml, dimens.xml, etc.

public class ExampleActivity extends Activity {

@BindString(R.string.title) String title;


@BindDrawable(R.drawable.graphic) Drawable graphic;
@BindColor(R.color.red) int red; // int or ColorStateList field
@BindDimen(R.dimen.spacer) Float spacer; // int (for pixel size) or float (for exact
value) field

@Override
public void onCreate(Bundle savedInstanceState) {

// ...

ButterKnife.bind(this);
}

Binding View Lists


You can group multiple views into a List or array. This is very helpful when we need to perform
one action on multiple views at once.

@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })


List<EditText> nameViews;

https://riptutorial.com/ 246
//The apply method allows you to act on all the views in a list at once.
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);

//We can use Action and Setter interfaces allow specifying simple behavior.
static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {
@Override public void apply(View view, int index) {
view.setEnabled(false);
}
};
static final ButterKnife.Setter<View, Boolean> ENABLED = new ButterKnife.Setter<View,
Boolean>() {
@Override public void set(View view, Boolean value, int index) {
view.setEnabled(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(R.id.might_not_be_there) TextView mightNotBeThere;

@Optional
@OnClick(R.id.maybe_missing)
void onMaybeMissingClicked() {
// TODO ...
}

Binding Listeners using ButterKnife

OnClick Listener:

@OnClick(R.id.login)
public void login(View view) {
// Additional logic
}

All arguments to the listener method are optional:

@OnClick(R.id.login)
public void login() {
// Additional logic
}

Specific type will be automatically casted:

https://riptutorial.com/ 247
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}

Multiple IDs in a single binding for common event handling:

@OnClick({ R.id.door1, R.id.door2, R.id.door3 })


public void pickDoor(DoorView door) {
if (door.hasPrizeBehind()) {
Toast.makeText(this, "You win!", LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Try again", LENGTH_SHORT).show();
}
}

Custom Views can bind to their own listeners by not specifying an ID:

public class CustomButton extends Button {


@OnClick
public void onClick() {
// TODO
}
}

Unbinding views in ButterKnife

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:

public class MyFragment extends Fragment {


@BindView(R.id.textView) TextView textView;
@BindView(R.id.button) Button button;
private Unbinder unbinder;

@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle


savedInstanceState) {
View view = inflater.inflate(R.layout.my_fragment, container, false);
unbinder = ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}

@Override public void onDestroyView() {


super.onDestroyView();
unbinder.unbind();
}
}

Note: Calling unbind() in onDestroyView() is not required, but recommended as it


saves quite a bit of memory if your app has a large backstack.

https://riptutorial.com/ 248
Android Studio ButterKnife Plugin

Android ButterKnife Zelezny

Plugin for generating ButterKnife injections from selected layout XMLs in


activities/fragments/adapters.

Note : Make sure that you make the right click for your_xml_layou(R.layout.your_xml_layou) else
the Generate menu will not contain Butterknife injector option.

Link : Jetbrains Plugin Android ButterKnife Zelezny

Read ButterKnife online: https://riptutorial.com/android/topic/1072/butterknife

https://riptutorial.com/ 249
Chapter 46: Button
Syntax
• <Button ... />
• android:onClick="methodname"
• button.setOnClickListener(new OnClickListener(){...});
• public class classname implements View.OnLongClickListener

Examples
inline onClickListener

Say we have a button (we can create it programmatically, or bind it from a view using
findViewbyId(), etc...)

Button btnOK = (...)

Now, create an anonymous class and set it inline.

btnOk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Do stuff here...
}
});

Using the layout to define a click action

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" />

Then in your activity, create the handleClick method.

public void handleClick(View v) {


// Do whatever.
}

https://riptutorial.com/ 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.

public void doSomething(View v) {


switch(v.getId()) {
case R.id.button:
// Button was clicked, do something.
break;
case R.id.image:
// Image was clicked, do something else.
break;
}
}

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).

Listening to the long click events

To catch a long click and use it you need to provide appropriate listener to button:

View.OnLongClickListener listener = new View.OnLongClickListener() {


public boolean onLongClick(View v) {
Button clickedButton = (Button) v;
String buttonText = clickedButton.getText().toString();
Log.v(TAG, "button long pressed --> " + buttonText);
return true;
}
};

button.setOnLongClickListener(listener);

Defining external Listener

https://riptutorial.com/ 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.

For example, give help when long click on any element:

public class HelpLongClickListener implements View.OnLongClickListener


{
public HelpLongClickListener() {
}

@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:

HelpLongClickListener helpListener = new HelpLongClickListener(...);

button1.setOnClickListener(helpListener);
button2.setOnClickListener(helpListener);
label.setOnClickListener(helpListener);
button1.setOnClickListener(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.

Custom Click Listener to prevent multiple fast clicks

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 class SingleClickListener implements View.OnClickListener {

protected int defaultInterval;


private long lastTimeClicked = 0;

public SingleClickListener() {

https://riptutorial.com/ 252
this(1000);
}

public SingleClickListener(int minInterval) {


this.defaultInterval = minInterval;
}

@Override
public void onClick(View v) {
if (SystemClock.elapsedRealtime() - lastTimeClicked < defaultInterval) {
return;
}
lastTimeClicked = SystemClock.elapsedRealtime();
performClick(v);
}

public abstract void performClick(View v);

And in the class, the SingleClickListener is associated to the Button at stake

myButton = (Button) findViewById(R.id.my_button);


myButton.setOnClickListener(new SingleClickListener() {
@Override
public void performClick(View view) {
// do stuff
}
});

Customizing Button style

There are many possible ways of customizing the look of a Button. This example presents several
options:

Option 0: Use ThemeOverlay (currently the easiest/quickest way)

Create a new style in your styles file:

styles.xml

<resources>
<style name=“mybutton” parent=”ThemeOverlay.AppCompat.Ligth”>
<!-- 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

https://riptutorial.com/ 253
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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/Widget.AppCompat.Button.Colored"/>

</LinearLayout>

Option 1: Create your own button style

In values/styles.xml, create a new style for your button:

styles.xml

<resources>
<style name="mybuttonstyle" parent="@android:style/Widget.Button">
<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

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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"

https://riptutorial.com/ 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>

Option 2: Assign a drawable for each of your button states

Create an xml file into drawable folder called 'mybuttondrawable.xml' to define the drawable
resource of each of your button states:

drawable/mybutton.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<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

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android"
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" />

https://riptutorial.com/ 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

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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:background="@drawable/mybuttondrawable"/>

</LinearLayout>

Option 3: Add your button style to your App theme

You can override the default android button style in the definition of your app theme (in
values/styles.xml).

styles.xml

<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>

<style name="mybutton" parent="android:style/Widget.Button">


<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>

https://riptutorial.com/ 256
<item name="android:textStyle">bold</item>
<item name="android:background">@drawable/anydrawable</item>
</style>
</resources>

Option 4: Overlay a color on the default button style programatically

Just find you button in your activity and apply a color filter:

Button mybutton = (Button) findViewById(R.id.mybutton);


mybutton.getBackground().setColorFilter(anycolor, PorterDuff.Mode.MULTIPLY)

You can check different blending modes here and nice examples here.

Read Button online: https://riptutorial.com/android/topic/5607/button

https://riptutorial.com/ 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://appName.com. Then you have to add the following lines
to your desired Activity in the Manifest.xml file:

<action android:name="android.intent.action.VIEW" />


<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="appName.com" android:scheme="appSchema"/>

Explanation of the lines above:

• <category android:name="android.intent.category.BROWSABLE"/> makes the target activity allow


itself to be started by a web browser to display data referenced by a link.
• <data android:host="appName.com" android:scheme="appSchema"/> specifies our schema and
host of our callback URL.
• All together, these lines will cause the specific Activity to be opened whenever the callback
URL is called in a browser.

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://appName.com".
String CALLBACK_URL = getResources().getString(R.string.insta_callback);
Uri uri = getIntent().getData();
if (uri != null && uri.toString().startsWith(CALLBACK_URL)) {
String access_token = uri.getQueryParameter("access_token");
}
// Perform other operations here.
}

Now you have retrieved the access_token from Instagram, that is used in various API endpoints of
Instagram.

Read Callback URL online: https://riptutorial.com/android/topic/4790/callback-url

https://riptutorial.com/ 258
Chapter 48: Camera 2 API
Parameters

Parameter Details

A configured capture session for a CameraDevice, used for capturing


CameraCaptureSession images from the camera or reprocessing images captured from the
camera in the same session previously

CameraDevice A representation of a single camera connected to an Android device

The properties describing a CameraDevice. These properties are


CameraCharacteristics fixed for a given CameraDevice, and can be queried through the
CameraManager interface with getCameraCharacteristics(String)

A system service manager for detecting, characterizing, and


CameraManager connecting to CameraDevices. You can get an instance of this class by
calling Context.getSystemService()

An immutable package of settings and outputs needed to capture a


single image from the camera device. Contains the configuration for
the capture hardware (sensor, lens, flash), the processing pipeline,
CaptureRequest the control algorithms, and the output buffers. Also contains the list of
target Surfaces to send image data to for this capture. Can be
created by using a CaptureRequest.Builder instance, obtained by
calling createCaptureRequest(int)

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

https://riptutorial.com/ 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="android.permission.CAMERA"/>

We're about to create an activity (Camera2Activity.java) that fills a TextureView with the preview of
the device's camera.

The Activity we're going to use is a typical AppCompatActivity:

public class Camera2Activity extends AppCompatActivity {

Attributes (You may need to read the entire example to understand some of it)

The MAX_PREVIEW_SIZE guaranteed by Camera2 API is 1920x1080

private static final int MAX_PREVIEW_WIDTH = 1920;


private static final int MAX_PREVIEW_HEIGHT = 1080;

TextureView.SurfaceTextureListener handles several lifecycle events on a TextureView. In this case,


we're listening to those events. When the SurfaceTexture is ready, we initialize the camera. When
it size changes, we setup the preview coming from the camera accordingly

private final TextureView.SurfaceTextureListener mSurfaceTextureListener


= new TextureView.SurfaceTextureListener() {

@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) {
}

https://riptutorial.com/ 260
};

A CameraDevice represent one physical device's camera. In this attribute, we save the ID of the
current CameraDevice

private String mCameraId;

This is the view (TextureView) that we'll be using to "draw" the preview of the Camera

private TextureView mTextureView;

The CameraCaptureSession for camera preview

private CameraCaptureSession mCaptureSession;

A reference to the opened CameraDevice

private CameraDevice mCameraDevice;

The Size of camera preview.

private Size mPreviewSize;

CameraDevice.StateCallback is called when CameraDevice changes its state

private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
// This method is called when the camera is opened. We start camera preview here.
mCameraOpenCloseLock.release();
mCameraDevice = cameraDevice;
createCameraPreviewSession();
}

@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}

@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
finish();
}

};

https://riptutorial.com/ 261
An additional thread for running tasks that shouldn't block the UI

private HandlerThread mBackgroundThread;

A Handler for running tasks in the background

private Handler mBackgroundHandler;

An ImageReader that handles still image capture

private ImageReader mImageReader;

CaptureRequest.Builder for the camera preview

private CaptureRequest.Builder mPreviewRequestBuilder;

CaptureRequest generated by mPreviewRequestBuilder

private CaptureRequest mPreviewRequest;

A Semaphore to prevent the app from exiting before closing the camera.

private Semaphore mCameraOpenCloseLock = new Semaphore(1);

Constant ID of the permission request

private static final int REQUEST_CAMERA_PERMISSION = 1;

Android Lifecycle methods

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera2);

mTextureView = (TextureView) findViewById(R.id.texture);


}

@Override
public void onResume() {
super.onResume();
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 (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {

https://riptutorial.com/ 262
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}

@Override
public void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}

Camera2 related methods

Those are methods that uses the Camera2 APIs

private void openCamera(int width, int height) {


if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
requestCameraPermission();
return;
}
setUpCameraOutputs(width, height);
configureTransform(width, height);
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}

Closes the current camera

private void closeCamera() {


try {
mCameraOpenCloseLock.acquire();
if (null != mCaptureSession) {
mCaptureSession.close();
mCaptureSession = null;
}
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
if (null != mImageReader) {
mImageReader.close();
mImageReader = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
mCameraOpenCloseLock.release();
}

https://riptutorial.com/ 263
}

Sets up member variables related to camera

private void setUpCameraOutputs(int width, int height) {


CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);

// We don't use a front facing camera in this sample.


Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}

StreamConfigurationMap map = characteristics.get(


CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
continue;
}

// For still image captures, we use the largest available size.


Size largest = Collections.max(
Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
new CompareSizesByArea());
mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
ImageFormat.JPEG, /*maxImages*/2);
mImageReader.setOnImageAvailableListener(
null, mBackgroundHandler);

Point displaySize = new Point();


getWindowManager().getDefaultDisplay().getSize(displaySize);
int rotatedPreviewWidth = width;
int rotatedPreviewHeight = height;
int maxPreviewWidth = displaySize.x;
int maxPreviewHeight = displaySize.y;

if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {


maxPreviewWidth = MAX_PREVIEW_WIDTH;
}

if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {


maxPreviewHeight = MAX_PREVIEW_HEIGHT;
}

// 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(map.getOutputSizes(SurfaceTexture.class),
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
maxPreviewHeight, largest);

mCameraId = cameraId;
return;
}
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (NullPointerException e) {

https://riptutorial.com/ 264
// Currently an NPE is thrown when the Camera2API is used but not supported on the
// device this code runs.
Toast.makeText(Camera2Activity.this, "Camera2 API not supported on this device",
Toast.LENGTH_LONG).show();
}
}

Creates a new CameraCaptureSession for camera preview

private void createCameraPreviewSession() {


try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;

// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());

// This is the output Surface we need to start preview.


Surface surface = new Surface(texture);

// We set up a CaptureRequest.Builder with the output Surface.


mPreviewRequestBuilder
= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);

// Here, we create a CameraCaptureSession for camera preview.


mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {

@Override
public void onConfigured(@NonNull CameraCaptureSession
cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
}

// When the session is ready, we start displaying the preview.


mCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

// Finally, we start displaying the camera preview.


mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}

@Override
public void onConfigureFailed(
@NonNull CameraCaptureSession cameraCaptureSession) {
showToast("Failed");
}
}, null
);

https://riptutorial.com/ 265
} catch (CameraAccessException e) {
e.printStackTrace();
}
}

Permissions related methods For Android API 23+

private void requestCameraPermission() {


if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA))
{
new AlertDialog.Builder(Camera2Activity.this)
.setMessage("R string request permission")
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(Camera2Activity.this,
new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);
}
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();

}
})
.create();

} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(Camera2Activity.this, "ERROR: Camera permissions not granted",
Toast.LENGTH_LONG).show();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}

Background thread / handler methods

private void startBackgroundThread() {


mBackgroundThread = new HandlerThread("CameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}

https://riptutorial.com/ 266
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}

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

private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,


int textureViewHeight, int maxWidth, int maxHeight, Size
aspectRatio) {

// 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 = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
option.getHeight() == option.getWidth() * h / w) {
if (option.getWidth() >= textureViewWidth &&
option.getHeight() >= textureViewHeight) {
bigEnough.add(option);
} else {
notBigEnough.add(option);
}
}
}

// Pick the smallest of those big enough. If there is no one big enough, pick the
// largest of those not big enough.
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} else if (notBigEnough.size() > 0) {
return Collections.max(notBigEnough, new CompareSizesByArea());
} else {
Log.e("Camera2", "Couldn't find any suitable preview size");
return choices[0];
}
}

This method congfigures the neccesary Matrix transformation to mTextureView

private void configureTransform(int viewWidth, int viewHeight) {


if (null == mTextureView || null == mPreviewSize) {

https://riptutorial.com/ 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, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
} else if (Surface.ROTATION_180 == rotation) {
matrix.postRotate(180, centerX, centerY);
}
mTextureView.setTransform(matrix);
}

This method compares two Sizes based on their areas.

static class CompareSizesByArea implements Comparator<Size> {

@Override
public int compare(Size lhs, Size rhs) {
// We cast here to ensure the multiplications won't overflow
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}

Not much to see here

/**
* 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() {
Toast.makeText(Camera2Activity.this, text, Toast.LENGTH_SHORT).show();
}
});
}

Read Camera 2 API online: https://riptutorial.com/android/topic/619/camera-2-api

https://riptutorial.com/ 268
Chapter 49: Camera and Gallery
Examples
Taking full-sized photo from camera

To take a photo, first we need to declare required permissions in AndroidManifest.xml. We need


two permissions:

• - 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.

AndroidManifest.xml

<uses-feature android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.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.

private void dispatchTakePictureIntent() {


Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Log.e("DEBUG_TAG", "createFile", ex);
}
// Continue only if the File was successfully created
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}

private File createImageFile() throws IOException {


// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new
Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getAlbumDir();
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */

https://riptutorial.com/ 269
storageDir /* directory */
);

// Save a file: path for use with ACTION_VIEW intents


mCurrentPhotoPath = image.getAbsolutePath();
return image;
}

private File getAlbumDir() {


File storageDir = null;

if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {

storageDir = new File(Environment.getExternalStorageDirectory()


+ "/dcim/"
+ "MyRecipes");

if (!storageDir.mkdirs()) {
if (!storageDir.exists()) {
Log.d("CameraSample", "failed to create directory");
return null;
}
}

} else {
Log.v(getString(R.string.app_name), "External storage is not mounted READ/WRITE.");
}

return storageDir;
}

private void setPic() {

/* 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 */

/* Get the size of the ImageView */


int targetW = recipeImage.getWidth();
int targetH = recipeImage.getHeight();

/* Get the size of the image */


BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;

/* Figure out which way needs to be reduced less */


int scaleFactor = 2;
if ((targetW > 0) && (targetH > 0)) {
scaleFactor = Math.max(photoW / targetW, photoH / targetH);
}

/* Set bitmap options to scale the image decode target */


bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;

Matrix matrix = new Matrix();


matrix.postRotate(getRotation());

https://riptutorial.com/ 270
/* Decode the JPEG file into a Bitmap */
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix,
false);

/* Associate the Bitmap to the ImageView */


recipeImage.setImageBitmap(bitmap);
}

private float getRotation() {


try {
ExifInterface ei = new ExifInterface(mCurrentPhotoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);

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;
}
}

private void galleryAddPic() {


Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
}

private void handleBigCameraPhoto() {

if (mCurrentPhotoPath != null) {
setPic();
galleryAddPic();
}
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
handleBigCameraPhoto();
}
}

Take photo

Add a permission to access the camera to the AndroidManifest file:

https://riptutorial.com/ 271
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Xml file :

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<SurfaceView android:id="@+id/surfaceView" android:layout_height="0dip"
android:layout_width="0dip"></SurfaceView>
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/imageView"></ImageView>
</LinearLayout>

Activity

import java.io.IOException;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ImageView;

public class TakePicture extends Activity implements SurfaceHolder.Callback


{
//a variable to store a reference to the Image View at the main.xml file
private ImageView iv_image;
//a variable to store a reference to the Surface View at the main.xml file
private SurfaceView sv;

//a bitmap to display the captured image


private Bitmap bmp;

//Camera variables
//a surface holder
private SurfaceHolder sHolder;
//a variable to control the camera
private Camera mCamera;
//the camera parameters
private Parameters parameters;

/** Called when the activity is first created. */


@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

//get the Image View at the main.xml file


iv_image = (ImageView) findViewById(R.id.imageView);

https://riptutorial.com/ 272
//get the Surface View at the main.xml file
sv = (SurfaceView) findViewById(R.id.surfaceView);

//Get a surface
sHolder = sv.getHolder();

//add the callback interface methods defined below as the Surface View callbacks
sHolder.addCallback(this);

//tells Android that this surface will have its data constantly replaced
sHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
{
//get camera parameters
parameters = mCamera.getParameters();

//set camera parameters


mCamera.setParameters(parameters);
mCamera.startPreview();

//sets what code should be executed after the picture is taken


Camera.PictureCallback mCall = new Camera.PictureCallback()
{
@Override
public void onPictureTaken(byte[] data, Camera camera)
{
//decode the data obtained by the camera into a Bitmap
bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
String filename=Environment.getExternalStorageDirectory()
+ File.separator + "testimage.jpg";
FileOutputStream out = null;
try {
out = new FileOutputStream(filename);
bmp.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap
instance
// PNG is a lossless format, the compression factor (100) is ignored
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//set the iv_image
iv_image.setImageBitmap(bmp);
}
};

mCamera.takePicture(null, null, mCall);


}

@Override
public void surfaceCreated(SurfaceHolder holder)
{

https://riptutorial.com/ 273
// The Surface has been created, acquire the camera and tell it where
// to draw the preview.
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);

} catch (IOException exception) {


mCamera.release();
mCamera = null;
}
}

@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
//stop the preview
mCamera.stopPreview();
//release the camera
mCamera.release();
//unbind the camera from this object
mCamera = null;
}
}

How to start camera or gallery and save camera result to storage

First of all you need Uri and temp Folders and request codes :

public final int REQUEST_SELECT_PICTURE = 0x01;


public final int REQUEST_CODE_TAKE_PICTURE = 0x2;
public static String TEMP_PHOTO_FILE_NAME ="photo_";
Uri mImageCaptureUri;
File mFileTemp;

Then init mFileTemp :

public void initTempFile(){


String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {

mFileTemp = new File(Environment.getExternalStorageDirectory() + File.separator


+ getResources().getString(R.string.app_foldername) + File.separator
+ getResources().getString(R.string.pictures_folder)
, TEMP_PHOTO_FILE_NAME
+ System.currentTimeMillis() + ".jpg");
mFileTemp.getParentFile().mkdirs();
} else {
mFileTemp = new File(getFilesDir() + File.separator
+ getResources().getString(R.string.app_foldername)
+ File.separator + getResources().getString(R.string.pictures_folder)
, TEMP_PHOTO_FILE_NAME + System.currentTimeMillis() + ".jpg");
mFileTemp.getParentFile().mkdirs();
}
}

Opening Camera and Gallery intents :

https://riptutorial.com/ 274
public void openCamera(){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
try {
mImageCaptureUri = null;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
mImageCaptureUri = Uri.fromFile(mFileTemp);

} else {

mImageCaptureUri = InternalStorageContentProvider.CONTENT_URI;

}
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
intent.putExtra("return-data", true);
startActivityForResult(intent, REQUEST_CODE_TAKE_PICTURE);
} catch (Exception e) {

Log.d("error", "cannot take picture", e);


}
}

public void openGallery(){


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermission(Manifest.permission.READ_EXTERNAL_STORAGE,
getString(R.string.permission_read_storage_rationale),
REQUEST_STORAGE_READ_ACCESS_PERMISSION);
} else {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)),
REQUEST_SELECT_PICTURE);
}

Then in onActivityResult method :

@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 = data.getData();
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
Bitmap bitmapScaled = Bitmap.createScaledBitmap(bitmap, 800, 800, true);
Drawable drawable=new BitmapDrawable(bitmapScaled);

https://riptutorial.com/ 275
mImage.setImageDrawable(drawable);
mImage.setVisibility(View.VISIBLE);
} catch (IOException e) {
Log.v("act result", "there is an error : "+e.getContent());
}
} catch (Exception e) {
Log.v("act result", "there is an error : "+e.getContent());
}
break;
case REQUEST_CODE_TAKE_PICTURE:
try{
Bitmap bitmappicture = MediaStore.Images.Media.getBitmap(getContentResolver() ,
mImageCaptureUri);
mImage.setImageBitmap(bitmappicture);
mImage.setVisibility(View.VISIBLE);
}catch (IOException e){
Log.v("error camera",e.getMessage());
}
break;
}
super.onActivityResult(requestCode, resultCode, data);
}

You need theese permissions in AndroidManifest.xml :

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />


<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

And you need to handle runtime permissions such as Read/Write external storage etc ...

I am checking READ_EXTERNAL_STORAGE permission in my openGallery method :

My requestPermission method :

protected void requestPermission(final String permission, String rationale, final int


requestCode) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
showAlertDialog(getString(R.string.permission_title_rationale), rationale,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(BasePermissionActivity.this,
new String[]{permission}, requestCode);
}
}, getString(android.R.string.ok), null, getString(android.R.string.cancel));
} else {
ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
}
}

Then Override onRequestPermissionsResult method :

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
switch (requestCode) {

https://riptutorial.com/ 276
case REQUEST_STORAGE_READ_ACCESS_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
handleGallery();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}

showAlertDialog method :

protected void showAlertDialog(@Nullable String title, @Nullable String message,


@Nullable DialogInterface.OnClickListener
onPositiveButtonClickListener,
@NonNull String positiveText,
@Nullable DialogInterface.OnClickListener
onNegativeButtonClickListener,
@NonNull String negativeText) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(title);
builder.setMessage(message);
builder.setPositiveButton(positiveText, onPositiveButtonClickListener);
builder.setNegativeButton(negativeText, onNegativeButtonClickListener);
mAlertDialog = builder.show();
}

Set camera resolution

Set High resolution programmatically.

Camera mCamera = Camera.open();


Camera.Parameters params = mCamera.getParameters();

// Check what resolutions are supported by your camera


List<Size> sizes = params.getSupportedPictureSizes();

// Iterate through all available resolutions and choose one.


// The chosen resolution will be stored in mSize.
Size mSize;
for (Size size : sizes) {
Log.i(TAG, "Available resolution: "+size.width+" "+size.height);
mSize = size;
}
}

Log.i(TAG, "Chosen resolution: "+mSize.width+" "+mSize.height);


params.setPictureSize(mSize.width, mSize.height);
mCamera.setParameters(params);

Decode bitmap correctly rotated from the uri fetched with the intent

private static final String TAG = "IntentBitmapFetch";


private static final String COLON_SEPARATOR = ":";
private static final String IMAGE = "image";

https://riptutorial.com/ 277
@Nullable
public Bitmap getBitmap(@NonNull Uri bitmapUri, int maxDimen) {
InputStream is = context.getContentResolver().openInputStream(bitmapUri);
Bitmap bitmap = BitmapFactory.decodeStream(is, null, getBitmapOptions(bitmapUri,
maxDimen));

int imgRotation = getImageRotationDegrees(bitmapUri);

int endRotation = (imgRotation < 0) ? -imgRotation : imgRotation;


endRotation %= 360;
endRotation = 90 * (endRotation / 90);
if (endRotation > 0 && bitmap != null) {
Matrix m = new Matrix();
m.setRotate(endRotation);
Bitmap tmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
m, true);
if (tmp != null) {
bitmap.recycle();
bitmap = tmp;
}
}

return bitmap;
}

private BitmapFactory.Options getBitmapOptions(Uri uri, int imageMaxDimen){


BitmapFactory.Options options = new BitmapFactory.Options();
if (imageMaxDimen > 0) {
options.inJustDecodeBounds = true;
decodeImage(null, uri, options);
options.inSampleSize = calculateScaleFactor(options, imageMaxDimen);
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.RGB_565;
addInBitmapOptions(options);
}
}

private int calculateScaleFactor(@NonNull BitmapFactory.Options bitmapOptionsMeasureOnly, int


imageMaxDimen) {
int inSampleSize = 1;
if (bitmapOptionsMeasureOnly.outHeight > imageMaxDimen ||
bitmapOptionsMeasureOnly.outWidth > imageMaxDimen) {
final int halfHeight = bitmapOptionsMeasureOnly.outHeight / 2;
final int halfWidth = bitmapOptionsMeasureOnly.outWidth / 2;
while ((halfHeight / inSampleSize) > imageMaxDimen && (halfWidth / inSampleSize) >
imageMaxDimen) {
inSampleSize *= 2;
}
}
return inSampleSize;
}

public int getImageRotationDegrees(@NonNull Uri imgUri) {


int photoRotation = ExifInterface.ORIENTATION_UNDEFINED;

try {
boolean hasRotation = false;
//If image comes from the gallery and is not in the folder DCIM (Scheme: content://)
String[] projection = {MediaStore.Images.ImageColumns.ORIENTATION};
Cursor cursor = context.getContentResolver().query(imgUri, projection, null, null,
null);

https://riptutorial.com/ 278
if (cursor != null) {
if (cursor.getColumnCount() > 0 && cursor.moveToFirst()) {
photoRotation = cursor.getInt(cursor.getColumnIndex(projection[0]));
hasRotation = photoRotation != 0;
Log.d("Cursor orientation: "+ photoRotation);
}
cursor.close();
}

//If image comes from the camera (Scheme: file://) or is from the folder DCIM (Scheme:
content://)
if (!hasRotation) {
ExifInterface exif = new ExifInterface(getAbsolutePath(imgUri));
int exifRotation = exif.getAttributeInt(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: http://stackoverflow.com/a/20559418/2235133
String filePath = uri.getPath();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT &&
DocumentsContract.isDocumentUri(context, uri)) {
// Will return "image:x*"
String[] wholeID = TextUtils.split(DocumentsContract.getDocumentId(uri),
COLON_SEPARATOR);
// Split at colon, use second item in the array
String type = wholeID[0];
if (IMAGE.equalsIgnoreCase(type)) {//If it not type image, it means it comes from a
remote location, like Google Photos
String id = wholeID[1];
String[] column = {MediaStore.Images.Media.DATA};
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = context.getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
if (cursor != null) {
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);

https://riptutorial.com/ 279
}
cursor.close();
}
Log.d(TAG, "Fetched absolute path for uri" + uri);
}
}
return filePath;
}

Read Camera and Gallery online: https://riptutorial.com/android/topic/4789/camera-and-gallery

https://riptutorial.com/ 280
Chapter 50: Canvas drawing using
SurfaceView
Remarks
It's important to understand the basic concept of the surface view before using:

• It's basically just a hole in the current window


• Native UI can be placed on top of it
• Drawing is done using a dedicated, non UI thread
• Drawing is not hardware accelerated
• Uses two buffers: One is currently shown, one is used for drawing.
• unlockCanvasAndPost() swaps the buffers.

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 android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
/**
* Defines a custom SurfaceView class which handles the drawing thread
**/
public class BaseSurface extends SurfaceView implements SurfaceHolder.Callback,
View.OnTouchListener, Runnable
{

/**
* Holds the surface frame
*/
private SurfaceHolder holder;

/**
* Draw thread
*/

https://riptutorial.com/ 281
private Thread drawThread;

/**
* True when the surface is ready to draw
*/
private boolean surfaceReady = false;

/**
* Drawing thread flag
*/

private boolean drawingActive = false;

/**
* 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);

private static final String LOGTAG = "surface";

public BaseSurface(Context context, AttributeSet attrs)


{
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
setOnTouchListener(this);

// red
samplePaint.setColor(0xffff0000);
// smooth edges
samplePaint.setAntiAlias(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)
{
this.holder = holder;

if (drawThread != null)
{
Log.d(LOGTAG, "draw thread still active..");
drawingActive = false;
try
{

https://riptutorial.com/ 282
drawThread.join();
} 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
holder.getSurface().release();

this.holder = 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");
drawThread.join(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()

https://riptutorial.com/ 283
{
if (surfaceReady && drawThread == null)
{
drawThread = new Thread(this, "Draw thread");
drawingActive = true;
drawThread.start();
}
}

@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 (android.os.Build.BRAND.equalsIgnoreCase("google") &&
android.os.Build.MANUFACTURER.equalsIgnoreCase("asus") &&
android.os.Build.MODEL.equalsIgnoreCase("Nexus 7"))
{
Log.w(LOGTAG, "Sleep 500ms (Device: Asus Nexus 7)");
try
{
Thread.sleep(500);
} catch (InterruptedException ignored)
{
}
}
try
{
while (drawingActive)
{
if (holder == null)
{
return;
}

frameStartTime = System.nanoTime();
Canvas canvas = holder.lockCanvas();
if (canvas != null)
{
// clear the screen using black
canvas.drawARGB(255, 0, 0, 0);

try
{
// Your drawing here
canvas.drawRect(0, 0, getWidth() / 2, getHeight() / 2, samplePaint);
} finally
{

holder.unlockCanvasAndPost(canvas);
}
}

// calculate the time required to draw the frame in ms

https://riptutorial.com/ 284
frameTime = (System.nanoTime() - frameStartTime) / 1000000;

if (frameTime < MAX_FRAME_TIME) // faster than the max fps - limit the FPS
{
try
{
Thread.sleep(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.

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="sample.devcore.org.surfaceviewsample.MainActivity">

<sample.devcore.org.surfaceviewsample.BaseSurface
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 android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity


{

/**
* Surface object
*/
private BaseSurface surface;

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surface = (BaseSurface) findViewById(R.id.baseSurface);

https://riptutorial.com/ 285
}

@Override
protected void onResume()
{
super.onResume();
// start the drawing
surface.startDrawThread();
}

@Override
protected void onPause()
{
// stop the drawing to save cpu time
surface.stopDrawThread();
super.onPause();
}
}

Read Canvas drawing using SurfaceView online: https://riptutorial.com/android/topic/3754/canvas-


drawing-using-surfaceview

https://riptutorial.com/ 286
Chapter 51: Capturing Screenshots
Examples
Capturing Screenshot via Android Studio

1. Open Android Monitor Tab


2. Click on Screen Capture Button

Capturing Screenshot via Android Device Monitor

1. Open Android Device Monitor ( ie C:<ANDROID_SDK_LOCATION>\tools\monitor.bat)


2. Select your device
3. Click on Screen Capture Button

https://riptutorial.com/ 287
Capturing Screenshot via ADB

Example below saves a screenshot on Devices's Internal Storage.

adb shell screencap /sdcard/screen.png

Capturing Screenshot via ADB and saving directly in your PC

If you use Linux (or Windows with Cygwin), you can run:

adb shell screencap -p | sed 's/\r$//' > screenshot.png

Taking a screenshot of a particular view

If you want to take a screenshot of a particular View v, then you can use the following code:

Bitmap viewBitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.RGB_565);


Canvas viewCanvas = new Canvas(viewBitmap);
Drawable backgroundDrawable = v.getBackground();

if(backgroundDrawable != null){
// Draw the background onto the canvas.
backgroundDrawable.draw(viewCanvas);

https://riptutorial.com/ 288
}
else{
viewCanvas.drawColor(Color.GREEN);
// Draw the view onto the canvas.
v.draw(viewCanvas)
}

// Write the bitmap generated above into a file.


String fileStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
OutputStream outputStream = null;
try{
imgFile = new
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), fileStamp
+ ".png");
outputStream = new FileOutputStream(imgFile);
viewBitmap.compress(Bitmap.CompressFormat.PNG, 40, outputStream);
outputStream.close();
}
catch(Exception e){
e.printStackTrace();
}

Read Capturing Screenshots online: https://riptutorial.com/android/topic/4506/capturing-


screenshots

https://riptutorial.com/ 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

cardBackgroundColor Background color for CardView.

cardCornerRadius Corner radius for CardView.

cardElevation Elevation for CardView.

cardMaxElevation Maximum Elevation for CardView.

Add padding to CardView on v20 and before to prevent


cardPreventCornerOverlap
intersections between the Card content and rounded corners.

Add padding in API v21+ as well to have the same


cardUseCompatPadding measurements with previous versions. May be a boolean value,
such as "true" or "false".

Inner padding between the edges of the Card and children of


contentPadding
the CardView.

Inner padding between the bottom edge of the Card and


contentPaddingBottom
children of the CardView.

Inner padding between the left edge of the Card and children of
contentPaddingLeft
the CardView.

contentPaddingRight Elevation for 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

https://riptutorial.com/ 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 build.gradle file:

dependencies{
compile 'com.android.support:cardview-v7:25.2.0'
}

A number of the latest version may be found here

Official Documentation:
https://developer.android.com/reference/android/support/v7/widget/CardView.html
https://developer.android.com/training/material/lists-cards.html

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 build.gradle dependencies.

compile 'com.android.support:cardview-v7:25.1.1'

A number of the latest version may be found here

In your layout you can then add the following to get a card.

<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<!-- one child layout containing other layouts or views -->

</android.support.v7.widget.CardView>

https://riptutorial.com/ 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.

<?xml version="1.0" encoding="utf-8"?>


<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/card_view"
android:layout_margin="5dp"
card_view:cardBackgroundColor="#81C784"
card_view:cardCornerRadius="12dp"
card_view:cardElevation="3dp"
card_view:contentPadding="4dp" >

<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>
</android.support.v7.widget.CardView>

Customizing the CardView

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:

https://riptutorial.com/ 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

Note: card_view is a namespace defined in topmost parent layout view. xmlns:card_view="


http://schemas.android.com/apk/res-auto"

Here an example:

<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
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">

<!-- one child layout containing other layouts or views -->

</android.support.v7.widget.CardView>

You can also do it programmatically using:

card.setCardBackgroundColor(....);
card.setCardElevation(...);
card.setRadius(....);
card.setContentPadding();

Check the official javadoc for additional properties.

Adding Ripple animation

To enable the ripple animation in a CardView, add the following attributes:

<android.support.v7.widget.CardView
...
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground">
...
</android.support.v7.widget.CardView>

Using Images as Background in CardView (Pre-Lollipop device issues)

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.

We need to use an attribute card_view:cardPreventCornerOverlap="false" in the CardView. 1). In


XML use the following snippet.

https://riptutorial.com/ 293
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
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" />

</android.support.v7.widget.CardView>

2. In Java like this cardView.setPreventCornerOverlap(false).

Doing so removes an unwanted padding on the Card's edges. Here are some visual examples
related to this implementation.

1 Card with image background in API 21 (perfectly fine)

2 Card with image background in API 19 without attribute (notice the paddings around image)

https://riptutorial.com/ 294
3 FIXED Card with image background in API 19 with attribute
cardView.setPreventCornerOverlap(false) (Issue now fixed)

Also read about this on Documentation here


Original SOF post here

Animate CardView background color with TransitionDrawable

public void setCardColorTran(CardView card) {


ColorDrawable[] color = {new ColorDrawable(Color.BLUE), new ColorDrawable(Color.RED)};
TransitionDrawable trans = new TransitionDrawable(color);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
card.setBackground(trans);
} else {
card.setBackgroundDrawable(trans);
}
trans.startTransition(5000);
}

https://riptutorial.com/ 295
Read CardView online: https://riptutorial.com/android/topic/726/cardview

https://riptutorial.com/ 296
Chapter 53: Check Data Connection
Examples
Check data connection

This method is to check data connection by ping certain IP or Domain name.

public Boolean isDataConnected() {


try {
Process p1 = java.lang.Runtime.getRuntime().exec("ping -c 1 8.8.8.8");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
return reachable;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}

Check connection using ConnectivityManager

public static boolean isConnectedNetwork (Context context) {

ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo () != null && cm.getActiveNetworkInfo
().isConnectedOrConnecting ();

Use network intents to perform tasks while data is allowed

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
(intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)){
NetworkInfo info =
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
//perform your action when connected to a network
}

Read Check Data Connection online: https://riptutorial.com/android/topic/8670/check-data-


connection

https://riptutorial.com/ 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

Context A reference of Activity context

Remarks
If internet connected then method will return true or false.

Examples
Check if device has internet connectivity

Add the required network permissions to the application manifest file:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />


<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

/**
* 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 = connectivity.getAllNetworkInfo();

https://riptutorial.com/ 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 < info.length; i++) {
// check this interface for a connected state
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
Log.d("NetworkCheck", "isNetworkAvailable: Yes");
return true;
}
}
}
return false;
}

How to check network strength in android?

ConnectivityManager cm = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo Info = cm.getActiveNetworkInfo();
if (Info == null || !Info.isConnectedOrConnecting()) {
Log.i(TAG, "No connection");
} else {
int netType = Info.getType();
int netSubtype = Info.getSubtype();

if (netType == ConnectivityManager.TYPE_WIFI) {
Log.i(TAG, "Wifi connection");
WifiManager wifiManager = (WifiManager)
getApplication().getSystemService(Context.WIFI_SERVICE);
List<ScanResult> scanResult = wifiManager.getScanResults();
for (int i = 0; i < scanResult.size(); i++) {
Log.d("scanResult", "Speed of wifi"+scanResult.get(i).level);//The db
level of signal
}

// Need to get wifi strength


} else if (netType == ConnectivityManager.TYPE_MOBILE) {
Log.i(TAG, "GPRS/3G connection");
// Need to get differentiate between 3G/GPRS
}
}

How to check network strength

To check exact strength in decibels use this-

ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);


NetworkInfo Info = cm.getActiveNetworkInfo();
if (Info == null || !Info.isConnectedOrConnecting()) {
Log.i(TAG, "No connection");
} else {
int netType = Info.getType();
int netSubtype = Info.getSubtype();

if (netType == ConnectivityManager.TYPE_WIFI) {
Log.i(TAG, "Wifi connection");

https://riptutorial.com/ 299
WifiManager wifiManager = (WifiManager)
getApplication().getSystemService(Context.WIFI_SERVICE);
List<ScanResult> scanResult = wifiManager.getScanResults();
for (int i = 0; i < scanResult.size(); i++) {
Log.d("scanResult", "Speed of wifi"+scanResult.get(i).level);//The db level of
signal
}

// Need to get wifi strength


} else if (netType == ConnectivityManager.TYPE_MOBILE) {
Log.i(TAG, "GPRS/3G connection");
// Need to get differentiate between 3G/GPRS
}
}

To check Network type use this Class-

public class Connectivity {


/*
* These constants aren't yet available in my API level (7), but I need to
* handle these cases if they come up, on newer versions
*/
public static final int NETWORK_TYPE_EHRPD = 14; // Level 11
public static final int NETWORK_TYPE_EVDO_B = 12; // Level 9
public static final int NETWORK_TYPE_HSPAP = 15; // Level 13
public static final int NETWORK_TYPE_IDEN = 11; // Level 8
public static final int NETWORK_TYPE_LTE = 13; // Level 11

/**
* 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 = cm.getActiveNetworkInfo();
return (info != null && info.isConnected());
}

/**
* 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 = cm.getActiveNetworkInfo();

if ((info != null && info.isConnected())) {


return Connectivity.isConnectionFast(info.getType(),
info.getSubtype());
} else
return "No NetWork Access";

https://riptutorial.com/ 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) {
System.out.println("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:

return "NETWORK TYPE EDGE (2.75G) Speed: 100-120 Kbps"; // ~


// 50-100
// kbps
case TelephonyManager.NETWORK_TYPE_EVDO_0:
return "NETWORK TYPE EVDO_0"; // ~ 400-1000 kbps
case TelephonyManager.NETWORK_TYPE_EVDO_A:
return "NETWORK TYPE EVDO_A"; // ~ 600-1400 kbps
case TelephonyManager.NETWORK_TYPE_GPRS:
return "NETWORK TYPE GPRS (2.5G) Speed: 40-50 Kbps"; // ~ 100
// kbps
case TelephonyManager.NETWORK_TYPE_HSDPA:
return "NETWORK TYPE HSDPA (4G) Speed: 2-14 Mbps"; // ~ 2-14
// Mbps
case TelephonyManager.NETWORK_TYPE_HSPA:
return "NETWORK TYPE HSPA (4G) Speed: 0.7-1.7 Mbps"; // ~
// 700-1700
// kbps
case TelephonyManager.NETWORK_TYPE_HSUPA:
return "NETWORK TYPE HSUPA (3G) Speed: 1-23 Mbps"; // ~ 1-23
// Mbps
case TelephonyManager.NETWORK_TYPE_UMTS:
return "NETWORK TYPE UMTS (3G) Speed: 0.4-7 Mbps"; // ~ 400-7000
// kbps
// NOT AVAILABLE YET IN API LEVEL 7
case Connectivity.NETWORK_TYPE_EHRPD:
return "NETWORK TYPE EHRPD"; // ~ 1-2 Mbps
case Connectivity.NETWORK_TYPE_EVDO_B:
return "NETWORK_TYPE_EVDO_B"; // ~ 5 Mbps
case Connectivity.NETWORK_TYPE_HSPAP:
return "NETWORK TYPE HSPA+ (4G) Speed: 10-20 Mbps"; // ~ 10-20
// Mbps
case Connectivity.NETWORK_TYPE_IDEN:
return "NETWORK TYPE IDEN"; // ~25 kbps
case Connectivity.NETWORK_TYPE_LTE:
return "NETWORK TYPE LTE (4G) Speed: 10+ Mbps"; // ~ 10+ Mbps
// Unknown
case TelephonyManager.NETWORK_TYPE_UNKNOWN:
return "NETWORK TYPE UNKNOWN";
default:
return "";
}

https://riptutorial.com/ 301
} else {
return "";
}
}

Read Check Internet Connectivity online: https://riptutorial.com/android/topic/3918/check-internet-


connectivity

https://riptutorial.com/ 302
Chapter 55: CleverTap
Introduction
Quick hacks for the analytics and engagement SDK provided by CleverTap - Android

Remarks
Get your CleverTap credentials from https://clevertap.com.

Examples
Get an instance of the SDK to record events

CleverTapAPI cleverTap;
try {
cleverTap = CleverTapAPI.getInstance(getApplicationContext());
} catch (CleverTapMetaDataNotFoundException e) {
// thrown if you haven't specified your CleverTap Account ID or Token in your
AndroidManifest.xml
} catch (CleverTapPermissionsNotSatisfied e) {
// thrown if you haven’t requested the required permissions in your AndroidManifest.xml
}

Setting the debug level

In your custom application class, override the onCreate() method, add the line below:

CleverTapAPI.setDebugLevel(1);

Read CleverTap online: https://riptutorial.com/android/topic/9337/clevertap

https://riptutorial.com/ 303
Chapter 56: Colors
Examples
Color Manipulation

To manipulate colors we will modify the argb (Alpha, Red, Green and Blue) values of a color.

First extract RGB values from your color.

int yourColor = Color.parse("#ae1f67");

int red = Color.red(yourColor);


int green = Color.green(yourColor);
int blue = Color.blue(yourColor);

Now you can reduce or increase red, green, and blue values and combine them to be a color
again:

int newColor = Color.rgb(red, green, blue);

Or if you want to add some alpha to it, you can add it while creating the color:

int newColor = Color.argb(alpha, red, green, blue);

Alpha and RGB values should be in the range [0-225].

Read Colors online: https://riptutorial.com/android/topic/4986/colors

https://riptutorial.com/ 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

○ public void addView(View child, int index, ViewGroup.LayoutParams params)

○ public ConstraintLayout.LayoutParams generateLayoutParams(AttributeSet attrs)

○ public void onViewAdded(View view)

○ public void onViewRemoved(View view)

○ public void removeView(View view)

○ public void requestLayout()

○ protected boolean checkLayoutParams(ViewGroup.LayoutParams params)

○ protected ConstraintLayout.LayoutParams generateDefaultLayoutParams()

○ protected ViewGroup.LayoutParams
generateLayoutParams(ViewGroup.LayoutParams params)

○ protected void onLayout(boolean changed, int left, int top, int right, int bottom)

○ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

• ConstraintLayout.LayoutParams

○ public void resolveLayoutDirection(int layoutDirection)

○ public void validate()

○ protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr)

Parameters

https://riptutorial.com/ 305
Parameter Details

child The View to be added to the layout

index The index of the View in the layout hierarchy

params The LayoutParams of the View

attrs The AttributeSet that defines the LayoutParams

view The View that has been added or removed

changed Indicates if this View has changed size or position

left The left position, relative to the parent View

top The top position, relative to the parent View

right The right position, relative to the parent View

bottom The bottom position, relative to the parent View

widthMeasureSpec The horizontal space requirements imposed by the parent View

heightMeasureSpec The vertical space requirements imposed by the parent View

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.

Fore More About Constraint Layout:


https://codelabs.developers.google.com/codelabs/constraint-layout/index.html

Examples
Adding ConstraintLayout to your project

To work with ConstraintLayout, you need Android Studio Version 2.2 or newer and have at least

https://riptutorial.com/ 306
version 32 (or higher) of Android Support Repository.

1. Add the Constraint Layout library as a dependency in your build.gradle file:

dependencies {
compile 'com.android.support.constraint:constraint-layout:1.0.2'
}

2. Sync project

To add a new constraint layout to your 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 "android.support.constraint.ConstraintLayout" for the
Root Tag.
3. Click Finish.

Otherwise just add in a layout file:

<?xml version="1.0" encoding="utf-8"?>


<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

</android.support.constraint.ConstraintLayout>

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:

<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<!-- this view is linked to the bottomTextView -->


<TextView
android:id="@+id/topTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintBottom_toTopOf="@+id/bottomTextView"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainPacked="true"/>

<!-- this view is linked to the topTextView at the same time -->
<TextView

https://riptutorial.com/ 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"/>

</android.support.constraint.ConstraintLayout>

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.

Read ConstraintLayout online: https://riptutorial.com/android/topic/5076/constraintlayout

https://riptutorial.com/ 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 android.content.Context;
import android.os.Bundle;
import android.support.constraint.ConstraintLayout;
import android.support.constraint.ConstraintSet;
import android.support.transition.TransitionManager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {


ConstraintSet mConstraintSet1 = new ConstraintSet(); // create a Constraint Set
ConstraintSet mConstraintSet2 = new ConstraintSet(); // create a Constraint Set
ConstraintLayout mConstraintLayout; // cache the ConstraintLayout
boolean mOld = true;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context context = this;
mConstraintSet2.clone(context, R.layout.state2); // get constraints from layout
setContentView(R.layout.state1);
mConstraintLayout = (ConstraintLayout) findViewById(R.id.activity_main);
mConstraintSet1.clone(mConstraintLayout); // get constraints from ConstraintSet
}

public void foo(View view) {


TransitionManager.beginDelayedTransition(mConstraintLayout);
if (mOld = !mOld) {
mConstraintSet1.applyTo(mConstraintLayout); // set new constraints
} else {
mConstraintSet2.applyTo(mConstraintLayout); // set new constraints
}
}
}

Read ConstraintSet online: https://riptutorial.com/android/topic/9334/constraintset

https://riptutorial.com/ 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 android.provider package. With some restrictions, these providers are accessible to any
Android application.

Examples
Implementing a basic content provider class

1) Create a Contract 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
com.example.appname, you should give your provider the authority com.example.appname.provider.

public class MyContract {


public static final String CONTENT_AUTHORITY = "com.example.myApp";
public static final String PATH_DATATABLE = "dataTable";
public static final String TABLE_NAME = "dataTable";
}

https://riptutorial.com/ 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.

public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);


public static final Uri CONTENT_URI =
BASE_CONTENT_URI.buildUpon().appendPath(PATH_DATATABLE).build();

// define all columns of table and common functions required

2) Create the Helper Class

A helper class manages database creation and version management.

public class DatabaseHelper extends SQLiteOpenHelper {

// Increment the version when there is a change in the structure of database


public static final int DATABASE_VERSION = 1;
// The name of the database in the filesystem, you can choose this to be anything
public static final String DATABASE_NAME = "weather.db";

public DatabaseHelper(Context context) {


super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@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.
}
}

3) Create a class that extends ContentProvider class

public class MyProvider extends ContentProvider {

public DatabaseHelper dbHelper;

public static final UriMatcher matcher = buildUriMatcher();


public static final int DATA_TABLE = 100;
public static final int DATA_TABLE_DATE = 101;

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

https://riptutorial.com/ 311
that table. You can use the # wildcard to match with any number and * to match with any string.

public static UriMatcher buildUriMatcher() {


UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(CONTENT_AUTHORITY, MyContract.PATH_DATATABLE, DATA_TABLE);
uriMatcher.addURI(CONTENT_AUTHORITY, MyContract.PATH_DATATABLE + "/#", DATA_TABLE_DATE);
return uriMatcher;
}

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:

uriMatcher.addURI(CONTENT_AUTHORITY, "/example", 1);


uriMatcher.addURI(CONTENT_AUTHORITY, "/*", 2);

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 uriMatcher.match("/example"), then the
UriMatcher will stop looking for matches once it encounters the /* path and return the wrong
result!

You will then need to override these functions:

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;
}

getType(): Return the MIME type corresponding to a content URI

@Override
public String getType(Uri uri) {
final int match = matcher.match(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.

https://riptutorial.com/ 312
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Cursor retCursor = dbHelper.getReadableDatabase().query(
MyContract.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
retCursor.setNotificationUri(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 = dbHelper.getWritableDatabase();
long id = db.insert(MyContract.TABLE_NAME, null, values);
return ContentUris.withAppendedId(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 = dbHelper.getWritableDatabase();
int rowsDeleted = db.delete(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 = dbHelper.getWritableDatabase();
int rowsUpdated = db.update(MyContract.TABLE_NAME, values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}

4) Update manifest file

<provider
android:authorities="com.example.myApp"
android:name=".DatabaseProvider"/>

Read ContentProvider online: https://riptutorial.com/android/topic/3075/contentprovider

https://riptutorial.com/ 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

Standard usage in Activity:

Context context = getApplicationContext();

Standard usage in Fragment:

Context context = getActivity().getApplicationContext();

this (when in a class that extends from Context, such as the Application, Activity, Service and
IntentService classes)

TextView textView = new TextView(this);

another this example:

https://riptutorial.com/ 314
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);

Read Context online: https://riptutorial.com/android/topic/9774/context

https://riptutorial.com/ 315
Chapter 61: Convert vietnamese string to
english string Android
Examples
example:

String myStr = convert("Lê Minh Thoại là người Việt Nam");

converted:

"Le Minh Thoai la nguoi Viet Nam"

Chuyển chuỗi Tiếng Việt thành chuỗi không dấu

public static String convert(String str) {


str = str.replaceAll("à|á|ạ|ả|ã|â|ầ|ấ|ậ|ẩ|ẫ|ă|ằ|ắ|ặ|ẳ|ẵ", "a");
str = str.replaceAll("è|é|ẹ|ẻ|ẽ|ê|ề|ế|ệ|ể|ễ", "e");
str = str.replaceAll("ì|í|ị|ỉ|ĩ", "i");
str = str.replaceAll("ò|ó|ọ|ỏ|õ|ô|ồ|ố|ộ|ổ|ỗ|ơ|ờ|ớ|ợ|ở|ỡ", "o");
str = str.replaceAll("ù|ú|ụ|ủ|ũ|ư|ừ|ứ|ự|ử|ữ", "u");
str = str.replaceAll("ỳ|ý|ỵ|ỷ|ỹ", "y");
str = str.replaceAll("đ", "d");

str = str.replaceAll("À|Á|Ạ|Ả|Ã|Â|Ầ|Ấ|Ậ|Ẩ|Ẫ|Ă|Ằ|Ắ|Ặ|Ẳ|Ẵ", "A");


str = str.replaceAll("È|É|Ẹ|Ẻ|Ẽ|Ê|Ề|Ế|Ệ|Ể|Ễ", "E");
str = str.replaceAll("Ì|Í|Ị|Ỉ|Ĩ", "I");
str = str.replaceAll("Ò|Ó|Ọ|Ỏ|Õ|Ô|Ồ|Ố|Ộ|Ổ|Ỗ|Ơ|Ờ|Ớ|Ợ|Ở|Ỡ", "O");
str = str.replaceAll("Ù|Ú|Ụ|Ủ|Ũ|Ư|Ừ|Ứ|Ự|Ử|Ữ", "U");
str = str.replaceAll("Ỳ|Ý|Ỵ|Ỷ|Ỹ", "Y");
str = str.replaceAll("Đ", "D");
return str;
}

Read Convert vietnamese string to english string Android online:


https://riptutorial.com/android/topic/10946/convert-vietnamese-string-to-english-string-android

https://riptutorial.com/ 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.

CoordinatorLayout is intended for two primary use cases:

:As a top-level application decor or chrome layout

: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 CoordinatorLayout.Behavior 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

To create a Behavior just extend the CoordinatorLayout.Behavior class.

Extend the CoordinatorLayout.Behavior


Example:

public class MyBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {

/**
* Default constructor.
*/
public MyBehavior() {

https://riptutorial.com/ 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);
}
}

This behavior need to be attached to a child View of a CoordinatorLayout to be called.

Attach a Behavior programmatically


MyBehavior myBehavior = new MyBehavior();
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams)
view.getLayoutParams();
params.setBehavior(myBehavior);

Attach a Behavior in XML


You can use the layout_behavior attribute to attach the behavior in XML:

<View
android:layout_height="...."
android:layout_width="...."
app:layout_behavior=".MyBehavior" />

Attach a Behavior automatically


If you are working with a custom view you can attach the behavior using the
@CoordinatorLayout.DefaultBehavior annotation:

@CoordinatorLayout.DefaultBehavior(MyBehavior.class)
public class MyView extends ..... {

Using the SwipeDismissBehavior

The SwipeDismissBehavior works on any View and implements the functionality of swipe to dismiss
in our layouts with a CoordinatorLayout.

Just use:

https://riptutorial.com/ 318
final SwipeDismissBehavior<MyView> swipe = new SwipeDismissBehavior();

//Sets the swipe direction for this behavior.


swipe.setSwipeDirection(
SwipeDismissBehavior.SWIPE_DIRECTION_ANY);

//Set the listener to be used when a dismiss event occurs


swipe.setListener(
new SwipeDismissBehavior.OnDismissListener() {
@Override public void onDismiss(View view) {
//......
}

@Override
public void onDragStateChanged(int state) {
//......
}
});

//Attach the SwipeDismissBehavior to a view


LayoutParams coordinatorParams =
(LayoutParams) mView.getLayoutParams();
coordinatorParams.setBehavior(swipe);

Create dependencies between Views

You can use the CoordinatorLayout.Behavior to create dependencies between views. You can
anchor a View to another View by:

• using the layout_anchor attribute.


• creating a custom Behavior and implementing the layoutDependsOn method returning true.

For example, in order to create a Behavior for moving an ImageView when another one is moved
(example Toolbar), perform the following steps:

• Create the custom Behavior:

public class MyBehavior extends CoordinatorLayout.Behavior<ImageView> {...}

• 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;
}

• Whenever the method layoutDependsOn returns true the method onDependentViewChanged is


called:

@Override

https://riptutorial.com/ 319
public boolean onDependentViewChanged(CoordinatorLayout parent, ImageView child, View
dependency) {
// Implement here animations, translations, or movements; always related to the
provided dependency.
float translationY = Math.min(0, dependency.getTranslationY() -
dependency.getHeight());
child.setTranslationY(translationY);
}

Read CoordinatorLayout and Behaviors online:


https://riptutorial.com/android/topic/5714/coordinatorlayout-and-behaviors

https://riptutorial.com/ 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.

long A parameter provided in onTick() that tells how long the


millisUntilFinished CountDownTimer has remaining. In 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."

TextView textView = (TextView)findViewById(R.id.text_view);

CountDownTimer countDownTimer = new CountDownTimer(30000, 1000) {


public void onTick(long millisUntilFinished) {
textView.setText(String.format(Locale.getDefault(), "%d sec.", millisUntilFinished /
1000L));
}

public void onFinish() {


textView.setText("Done.");
}
}.start();

A More Complex Example

In this example, we will pause/resume the CountDownTimer based off of the Activity lifecycle.

https://riptutorial.com/ 321
private static final long TIMER_DURATION = 60000L;
private static final long TIMER_INTERVAL = 1000L;

private CountDownTimer mCountDownTimer;


private TextView textView;

private long mTimeRemaining;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

textView = (TextView)findViewById(R.id.text_view); // Define in xml layout.

mCountDownTimer = new CountDownTimer(TIMER_DURATION, TIMER_INTERVAL) {

@Override
public void onTick(long millisUntilFinished) {
textView.setText(String.format(Locale.getDefault(), "%d sec.", millisUntilFinished
/ 1000L));
mTimeRemaining = millisUntilFinished; // Saving timeRemaining in Activity for
pause/resume of CountDownTimer.
}

@Override
public void onFinish() {
textView.setText("Done.");
}
}.start();
}

@Override
protected void onResume() {
super.onResume();

if (mCountDownTimer == null) { // Timer was paused, re-create with saved time.


mCountDownTimer = new CountDownTimer(timeRemaining, INTERVAL) {
@Override
public void onTick(long millisUntilFinished) {
textView.setText(String.format(Locale.getDefault(), "%d sec.",
millisUntilFinished / 1000L));
timeRemaining = millisUntilFinished;
}

@Override
public void onFinish() {
textView.setText("Done.");
}
}.start();
}
}

@Override
protected void onPause() {
super.onPause();
mCountDownTimer.cancel();
mCountDownTimer = null;
}

https://riptutorial.com/ 322
Read Count Down Timer online: https://riptutorial.com/android/topic/6063/count-down-timer

https://riptutorial.com/ 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.

How to Configure Fabric-Crashlytics


Step 1: Change your build.gradle:

Add the plugin repo and the gradle plugin:

buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
}

dependencies {
// The Fabric Gradle plugin uses an open ended version to react
// quickly to Android tooling updates
classpath 'io.fabric.tools:gradle:1.+'
}
}

Apply the plugin:

apply plugin: 'com.android.application'


//Put Fabric plugin after Android plugin
apply plugin: 'io.fabric'

Add the Fabric repo:

repositories {
maven { url 'https://maven.fabric.io/public' }
}

Add the Crashlyrics Kit:

https://riptutorial.com/ 324
dependencies {

compile('com.crashlytics.sdk.android:crashlytics:2.6.6@aar') {
transitive = true;
}
}

Step 2: Add Your API Key and the INTERNET permission in AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
... >

<meta-data
android:name="io.fabric.ApiKey"
android:value="25eeca3bb31cd41577e097cabd1ab9eee9da151d"
/>

</application>

<uses-permission android:name="android.permission.INTERNET" />


</manifest>

Step 3: Init the Kit at runtime in you code, for example:

public class MainActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//Init the KIT


Fabric.with(this, new Crashlytics());

setContentView(R.layout.activity_main);
}
}

Step 4: Build project. To build and run:

Using the Fabric IDE plugin


Kits can be installed using the Fabric IDE plugin for Android Studio or IntelliJ following this link.

https://riptutorial.com/ 325
After installing the plugin, restart Android Studio and login with your account using Android
Studio.

( short key > CTRL + L)

https://riptutorial.com/ 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 :

https://riptutorial.com/ 327
Then hit Install. You don't need to add it manually this time like above gradle plugin, instead it
will build for you.

https://riptutorial.com/ 328
Done!

Crash Reporting with ACRA

Step 1: Add the dependency of latest ACRA AAR to your application gradle(build.gradle).

Step 2: In your application class(the class which extends Application; if not create it) Add a
@ReportsCrashes annotation and override the attachBaseContext() method.

Step 3: Initialize the ACRA class in your application class

@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,

https://riptutorial.com/ 329
ReportField.USER_CRASH_DATE,
ReportField.APP_VERSION_CODE,
ReportField.APP_VERSION_NAME,
ReportField.ANDROID_VERSION,
ReportField.DEVICE_ID,
ReportField.BUILD,
ReportField.BRAND,
ReportField.DEVICE_FEATURES,
ReportField.PACKAGE_NAME,
ReportField.REPORT_ID,
ReportField.STACK_TRACE,
},
mode = NOTIFICATION_TYPE(TOAST,DIALOG,NOTIFICATION)
resToastText = R.string.crash_text_toast)

public class MyApplication extends Application {


@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// Initialization of ACRA
ACRA.init(this);
}
}

Where AUTH_USERNAME and AUTH_PASSWORD are the credentials of your desired backends
.

Step 4: Define the Application class in AndroidManifest.xml

<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="android.permission.INTERNET"/>

In case if you want to send the silent report to the backend then just use the below method to
achieve it.

ACRA.getErrorReporter().handleSilentException(e);

Force a Test Crash With Fabric

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!"

https://riptutorial.com/ 330
android:onClick="forceCrash"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />

Throw a RuntimeException

public void forceCrash(View view) {


throw new RuntimeException("This is a crash");
}

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.

Capture crashes using Sherlock

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

How to integrate Sherlock with your application?

You just need to add Sherlock as a gradle dependency in your project.

dependencies {
compile('com.github.ajitsing:sherlock:1.0.1@aar') {
transitive = true
}
}

After syncing your android studio, initialize Sherlock in your Application class.

package com.singhajit.login;

import android.app.Application;

import com.singhajit.sherlock.core.Sherlock;

public class SampleApp extends Application {


@Override
public void onCreate() {
super.onCreate();
Sherlock.init(this);
}
}

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

https://riptutorial.com/ 331
Read Crash Reporting Tools online: https://riptutorial.com/android/topic/3871/crash-reporting-tools

https://riptutorial.com/ 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.

Then, update the sources by executing: sudo apt-get update.

Installing Additional Dependencies


All required additional dependencies can be installed by the following command:

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

Preparing the system for development


Now that all the dependencies are installed, let us prepare the system for development by
executing:

sudo curl --create-dirs -L -o /etc/udev/rules.d/51-android.rules -O -L


https://raw.githubusercontent.com/snowdream/51-android/master/51-android.rules
sudo chmod 644 /etc/udev/rules.d/51-android.rules
sudo chown root /etc/udev/rules.d/51-android.rules
sudo service udev restart
adb kill-server
sudo killall adb

Finally, let us set up the cache and the repo by the following commands:

https://riptutorial.com/ 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.

Read Create Android Custom ROMs online: https://riptutorial.com/android/topic/9212/create-


android-custom-roms

https://riptutorial.com/ 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
Gravity.TOP, Gravity.BOTTOM, Gravity.LEFT, Gravity.RIGHT.

xOffset Horizontal offset of the toast message.

yOffset Vertical offset of the toast message.

Duration of the toast show. We can set either Toast.LENGTH_SHORT or


duration
Toast.LENGTH_LONG

Remarks
Toast message is a simple way of providing feedback to user about something is happening. If

https://riptutorial.com/ 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.
https://developer.android.com/reference/android/widget/Toast.html

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.

public class ToastGenerate {


private static ToastGenerate ourInstance;

public ToastGenerate (Context context) {


this.context = context;
}
public static ToastGenerate getInstance(Context context) {
if (ourInstance == null)
ourInstance = new ToastGenerate(context);
return ourInstance;
}

//pass message and message type to this method


public void createToastMessage(String message,int type){

//inflate the custom layout


LayoutInflater layoutInflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

LinearLayout toastLayout = (LinearLayout)


layoutInflater.inflate(R.layout.layout_custome_toast,null);
TextView toastShowMessage = (TextView)
toastLayout.findViewById(R.id.textCustomToastTopic);

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);

}
}

https://riptutorial.com/ 336
//Failure toast message method
private final void createFailToast(LinearLayout toastLayout,TextView
toastMessage,String message){

toastLayout.setBackgroundColor(context.getResources().getColor(R.color.button_alert_normal));
toastMessage.setText(message);
toastMessage.setTextColor(context.getResources().getColor(R.color.white));
showToast(context,toastLayout);
}

//warning toast message method


private final void createWarningToast( LinearLayout toastLayout, TextView
toastMessage, String message) {

toastLayout.setBackgroundColor(context.getResources().getColor(R.color.warning_toast));
toastMessage.setText(message);
toastMessage.setTextColor(context.getResources().getColor(R.color.white));
showToast(context, toastLayout);
}
//success toast message method
private final void createSuccessToast(LinearLayout toastLayout,TextView
toastMessage,String message){

toastLayout.setBackgroundColor(context.getResources().getColor(R.color.success_toast));

toastMessage.setText(message);
toastMessage.setTextColor(context.getResources().getColor(R.color.white));
showToast(context,toastLayout);
}

private void showToast(View view){


Toast toast = new Toast(context);
toast.setGravity(Gravity.TOP,0,0); // show message in the top of the device
toast.setDuration(Toast.LENGTH_SHORT);
toast.setView(view);
toast.show();
}
}

Read Create Singleton Class for Toast Message online:


https://riptutorial.com/android/topic/10843/create-singleton-class-for-toast-message

https://riptutorial.com/ 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:

public class SmileyView extends View {


private Paint mCirclePaint;
private Paint mEyeAndMouthPaint;

private float mCenterX;


private float mCenterY;
private float mRadius;
private RectF mArcBounds = new RectF();

public SmileyView(Context context) {


this(context, null, 0);
}

public SmileyView(Context context, AttributeSet attrs) {


this(context, attrs, 0);
}

public SmileyView(Context context, AttributeSet attrs, int defStyleAttr) {


super(context, attrs, defStyleAttr);
initPaints();
}

private void initPaints() {/* ... */}

@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:

private void initPaints() {


mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setStyle(Paint.Style.FILL);

https://riptutorial.com/ 338
mCirclePaint.setColor(Color.YELLOW);
mEyeAndMouthPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mEyeAndMouthPaint.setStyle(Paint.Style.STROKE);
mEyeAndMouthPaint.setStrokeWidth(16 * getResources().getDisplayMetrics().density);
mEyeAndMouthPaint.setStrokeCap(Paint.Cap.ROUND);
mEyeAndMouthPaint.setColor(Color.BLACK);
}

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 = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);

int size = Math.min(w, h);


setMeasuredDimension(size, size);
}

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 = Math.min(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
canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint);
// draw eyes
float eyeRadius = mRadius / 5f;
float eyeOffsetX = mRadius / 3f;
float eyeOffsetY = mRadius / 3f;
canvas.drawCircle(mCenterX - eyeOffsetX, mCenterY - eyeOffsetY, eyeRadius,
mEyeAndMouthPaint);
canvas.drawCircle(mCenterX + eyeOffsetX, mCenterY - eyeOffsetY, eyeRadius,
mEyeAndMouthPaint);
// draw mouth
float mouthInset = mRadius /3f;

https://riptutorial.com/ 339
mArcBounds.set(mouthInset, mouthInset, mRadius * 2 - mouthInset, mRadius * 2 -
mouthInset);
canvas.drawArc(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="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.example.app.SmileyView
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:

Adding attributes to views

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/attrs.xml
(create it if necessary). The following file defines a color attribute for our smiley's face color

https://riptutorial.com/ 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="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent">

<com.example.app.SmileyView
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:

public class SmileyView extends View {


// ...

public SmileyView(Context context) {


this(context, null);
}

public SmileyView(Context context, AttributeSet attrs) {


this(context, attrs, 0);
}

public SmileyView(Context context, AttributeSet attrs, int defStyleAttr) {


super(context, attrs, defStyleAttr);

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SmileyView,


defStyleAttr, 0);
mFaceColor = a.getColor(R.styleable.SmileyView_smileyColor, Color.TRANSPARENT);
mFaceExpression = a.getInteger(R.styleable.SmileyView_smileyExpression,
Expression.HAPPY);
// Important: always recycle the TypedArray
a.recycle();

https://riptutorial.com/ 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:

<!-- styles.xml -->


<style name="DefaultSmileyStyle">
<item name="smileyColor">#ffff00</item>
<item name="smileyExpression">happy</item>
</style>

Which gets applied in our SmileyView by adding it as the last parameter of the call to
obtainStyledAttributes (see code in step 3):

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SmileyView,


defStyleAttr, R.style.DefaultSmileyViewStyle);

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:

<!-- attrs.xml -->


<attr name="smileyStyle" format="reference" />

Which we then provide a style for in our app theme (here we just reuse the default style from
step 4):

<!-- themes.xml -->


<style name="AppTheme" parent="AppBaseTheme">
<item name="smileyStyle">@style/DefaultSmileyStyle</item>
</style>

Creating a compound view

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.

https://riptutorial.com/ 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:

<?xml version="1.0" encoding="utf-8"?>


<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<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.

The compound ViewGroup

Once you have the XML file, create the custom view group.

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.ImageView;
import android.widget.TextView;

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 {

https://riptutorial.com/ 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 android.view.ViewGroup 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.

// 1. Implement superclass constructors.


public ContactView(Context context) {
super(context);
init(context, null);
}

// two extra constructors left out to keep the example shorter

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ContactView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}

// 2. Initialize the view by inflating an XML using `this` as parent


private TextView mName;
private TextView mPhoneNumber;
private ImageView mPhoto;

private void init(Context context, AttributeSet attrs) {


LayoutInflater.from(context).inflate(R.layout.contact_view, this, true);
mName = (TextView) findViewById(R.id.name);
mPhoneNumber = (TextView) findViewById(R.id.phone_number);
mPhoto = (ImageView) findViewById(R.id.photo);
}

// 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

// of this code will be copy-pasted all over the place (worse).


public void setContact(Contact contact) {
mName.setText(contact.getName());
mPhoneNumber.setText(contact.getPhoneNumber());
if (contact.hasPhoto()) {
mPhoto.setVisibility(View.VISIBLE);
mPhoto.setImageBitmap(contact.getPhoto());
} else {
mPhoto.setVisibility(View.GONE);
}
}
}

The init(Context, AttributeSet) method is where you would read any custom XML attributes as
explained in Adding Attributes to Views.

With these pieces in place, you can use it in your app.

Usage in XML

https://riptutorial.com/ 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="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<!-- The compound view becomes like any other view XML element -->
<myapp.ContactView
android:id="@+id/contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<android.support.v7.widget.RecyclerView
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 RecyclerView.Adapter 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 android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;

public class ContactsAdapter extends RecyclerView.Adapter<ContactsViewHolder> {

private final Context context;

public ContactsAdapter(final Context context) {


this.context = context;
}

@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 = this.getItem(position);
holder.setContact(contact); // <--- this
}

static class ContactsViewHolder extends RecyclerView.ViewHolder {

public ContactsViewHolder(ContactView itemView) {


super(itemView);
}

https://riptutorial.com/ 345
public void setContact(Contact contact) {
((ContactView) itemView).setContact(contact); // <--- this
}
}
}

CustomView performance tips

Do not allocate new objects in onDraw

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint(); //Do not allocate here
}

Instead of drawing drawables in canvas...

drawable.setBounds(boundsRect);

drawable.draw(canvas);

Use a Bitmap for faster drawing:

canvas.drawBitmap(bitmap, srcRect, boundsRect, paint);

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!

// Save the canvas state


int save = canvas.save();

https://riptutorial.com/ 346
// Rotate the canvas by providing the center point as pivot and angle
canvas.rotate(pivotX, pivotY, angle);
// Draw whatever you want
// Basically whatever you draw here will be drawn as per the angle you rotated the canvas
canvas.drawBitmap(...);
// Now restore your your canvas to its original state
canvas.restore(save);
// Unless canvas is restored to its original state, further draw will also be rotated.

Compound view for SVG/VectorDrawable as drawableRight

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.

Module Name : custom_edit_drawable (short name for


prefix- c_d_e)
"c_d_e_" prefix to use so that app module resources should not override them by mistake.
Example : "abc" prefix is used by google in support library.

build.gradle

dependencies {
compile 'com.android.support:appcompat-v7:25.3.1'
}

use AppCompat >= 23

Layout file : c_e_d_compound_view.xml

<?xml version="1.0" encoding="utf-8"?>


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<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" />

<!--make sure you are not using ImageView instead of this-->


<android.support.v7.widget.AppCompatImageView
android:id="@+id/drawbleRight_search"
android:layout_width="30dp"
android:layout_height="30dp"

https://riptutorial.com/ 347
android:layout_gravity="right|center_vertical"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" />
</FrameLayout>

Custom Attributes : attrs.xml

<?xml version="1.0" encoding="utf-8"?>


<resources>
<declare-styleable name="EditTextWithDrawable">
<attr name="c_e_d_drawableRightSVG" format="reference" />
<attr name="c_e_d_hint" format="string" />
<attr name="c_e_d_textSize" format="dimension" />
<attr name="c_e_d_textColor" format="color" />
</declare-styleable>
</resources>

Code : EditTextWithDrawable.java

public class EditTextWithDrawable extends FrameLayout {


public AppCompatImageView mDrawableRight;
public EditText mEditText;

public EditTextWithDrawable(Context context) {


super(context);
init(null);
}

public EditTextWithDrawable(Context context, AttributeSet attrs) {


super(context, attrs);
init(attrs);
}

public EditTextWithDrawable(Context context, AttributeSet attrs, int defStyleAttr) {


super(context, attrs, defStyleAttr);
init(attrs);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public EditTextWithDrawable(Context context, AttributeSet attrs, int defStyleAttr, int
defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs);
}

private void init(AttributeSet attrs) {


if (attrs != null && !isInEditMode()) {
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.c_e_d_compound_view, this, true);
mDrawableRight = (AppCompatImageView) ((FrameLayout) getChildAt(0)).getChildAt(1);
mEditText = (EditText) ((FrameLayout) getChildAt(0)).getChildAt(0);

TypedArray attributeArray = getContext().obtainStyledAttributes(


attrs,
R.styleable.EditTextWithDrawable);

https://riptutorial.com/ 348
int drawableRes =
attributeArray.getResourceId(
R.styleable.EditTextWithDrawable_c_e_d_drawableRightSVG, -1);
if (drawableRes != -1) {
mDrawableRight.setImageResource(drawableRes);
}

mEditText.setHint(attributeArray.getString(
R.styleable.EditTextWithDrawable_c_e_d_hint));
mEditText.setTextColor(attributeArray.getColor(
R.styleable.EditTextWithDrawable_c_e_d_textColor, Color.BLACK));
int textSize =
attributeArray.getDimensionPixelSize(R.styleable.EditTextWithDrawable_c_e_d_textSize, 15);
mEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
android.view.ViewGroup.LayoutParams layoutParams =
mDrawableRight.getLayoutParams();
layoutParams.width = (textSize * 3) / 2;
layoutParams.height = (textSize * 3) / 2;
mDrawableRight.setLayoutParams(layoutParams);

attributeArray.recycle();
}
}
}

Example : How to use above view


Layout : activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<com.customeditdrawable.AppEditTextWithDrawable
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 : MainActivity.java

public class MainActivity extends AppCompatActivity {


EditTextWithDrawable mEditTextWithDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEditTextWithDrawable= (EditTextWithDrawable) findViewById(R.id.edt_search_emp);
}
}

https://riptutorial.com/ 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) {

int x = (int) event.getX();


int y = (int) event.getY();
int action = event.getAction();

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:

• Android official documentation: Responding to Touch Events

Read Creating Custom Views online: https://riptutorial.com/android/topic/1446/creating-custom-


views

https://riptutorial.com/ 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:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

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.

Assigning a view to the WindowManager


You can retrieve a window manager instance as follows:

WindowManager mWindowManager = (WindowManager)


mContext.getSystemService(Context.WINDOW_SERVICE);

In order to define the position of your view, you have to create some layout parameters as follows:

WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(


ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,
PixelFormat.TRANSLUCENT);
mLayoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;

Now, you can assign your view together with the created layout parameters to the window
manager instance as follows:

mWindowManager.addView(yourView, mLayoutParams);

Voila! Your view has been successfully placed on top of all other applications.

Note: You view will not be put on top of the keyguard.

Granting SYSTEM_ALERT_WINDOW Permission on android 6.0 and above

https://riptutorial.com/ 351
From android 6.0 this permission needs to grant dynamically,

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

Throwing below permission denied error on 6.0,

Caused by: android.view.WindowManager$BadTokenException: Unable to add window


android.view.ViewRootImpl$W@86fb55b -- permission denied for this window type

Solution :-

Requesting Overlay permission as below,

if(!Settings.canDrawOverlays(this)){
// ask for setting
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION);
}

Check for the result,

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OVERLAY_PERMISSION) {
if (Settings.canDrawOverlays(this)) {
// permission granted...
}else{
// permission not granted...
}
}
}

Read Creating Overlay (always-on-top) Windows online:


https://riptutorial.com/android/topic/6214/creating-overlay--always-on-top--windows

https://riptutorial.com/ 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:

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.package"
android:versionCode="1"
android:versionName="1.0" >

<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="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>

</application>

</manifest>

Now our splash-screen will be called as the first activity.

Here is an example splashscreen that also handles some critical app elements:

public class Splash extends Activity{

public final int SPLASH_DISPLAY_LENGTH = 3000;

private void checkPermission() {

https://riptutorial.com/ 353
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WAKE_LOCK) !=
PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this,Manifest.permission.INTERNET) !=
PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED) {//Can add
more as per requirement

ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WAKE_LOCK,
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_NETWORK_STATE},
123);
}

}
@Override
protected void onCreate(Bundle sis){
super.onCreate(sis);
//set the content view. The XML file can contain nothing but an image, such as a logo
or the app icon
setContentView(R.layout.splash);

//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 (Build.VERSION.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);
Locale.setDefault(locale);
Configuration config = new Configuration ();
config.locale = locale;
Splash.this.getResources().updateConfiguration(config,
Splash.this.getResources().getDisplayMetrics()) ;

//after three seconds, it will execute all of this code.


//as such, we then want to redirect to the master-activity
Intent mainIntent = new Intent(Splash.this, MainActivity.class);
Splash.this.startActivity(mainIntent);

//then we finish this class. Dispose of it as it is longer needed


Splash.this.finish();
}
}, SPLASH_DISPLAY_LENGTH);

public void onPause(){


super.onPause();
finish();
}

https://riptutorial.com/ 354
}

Splash screen with animation

This example shows a simple but effective splash screen with animation that can be created by
using Android Studio.

Step 1: Create an animation


Create a new directory named anim in the res directory. Right-click it and create a new Animation
Resource file named fade_in.xml:

Then, put the following code into the fade_in.xml file:

<?xml version="1.0" encoding="utf-8"?>


<set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true" >
<alpha
android:duration="1000"
android:fromAlpha="0.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="1.0" />
</set>

Step 2: Create an activity


Create an empty activity using Android Studio named Splash. Then, put the following code into it:

public class Splash extends AppCompatActivity {


Animation anim;
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
imageView=(ImageView)findViewById(R.id.imageView2); // Declare an imageView to show
the animation.
anim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.fade_in); //
Create the animation.
anim.setAnimationListener(new Animation.AnimationListener() {
@Override

https://riptutorial.com/ 355
public void onAnimationStart(Animation animation) {
}

@Override
public void onAnimationEnd(Animation animation) {
startActivity(new Intent(this,HomeActivity.class));
// HomeActivity.class is the activity to go after showing the splash screen.
}

@Override
public void onAnimationRepeat(Animation animation) {
}
});
imageView.startAnimation(anim);
}
}

Next, put the following code into the layout file:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_splash"
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="your_packagename"
android:orientation="vertical"
android:background="@android:color/white">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/imageView2"
android:layout_weight="1"
android:src="@drawable/Your_logo_or_image" />
</LinearLayout>

Step 3: Replace the default launcher


Turn your Splash activity into a launcher by adding the following code to the AndroidManifest file:

<activity
android:name=".Splash"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>

Then, remove the default launcher activity by removing the following code from the

https://riptutorial.com/ 356
AndroidManifest file:

<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>

Read Creating Splash screen online: https://riptutorial.com/android/topic/9316/creating-splash-


screen

https://riptutorial.com/ 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:

[project root directory]


[library root directory]
[gradle]
build.gradle //project level
gradle.properties
gradlew
gradlew.bat
local.properties
settings.gradle //this is important!

Your settings.gradle file must contain the following:

include ':[library root directory]'

Your [library root directory] must contain the following:

[libs]
[src]
[main]
[java]
[library package]
[test]
[java]
[library package]
build.gradle //"app"-level
proguard-rules.pro

Your "app"-level build.gradle file must contain the following:

apply plugin: 'com.android.library'

android {
compileSdkVersion 23
buildToolsVersion "23.0.2"

defaultConfig {
minSdkVersion 14
targetSdkVersion 23

https://riptutorial.com/ 358
}
}

With that, your project should be working fine!

Using library in project as a module

To use the library, you must include it as a dependency with the following line:

compile project(':[library root directory]')

Create a library available on Jitpack.io

Perform the following steps to create the library:

1. Create a GitHub account.

2. Create a Git repository containing your library project.

3. Modify your library project's build.gradle file by adding the following code:

apply plugin: 'com.github.dcendents.android-maven'

...

// Build a jar with source files.


task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}

task javadoc(type: Javadoc) {


failOnError false
source = android.sourceSets.main.java.sourceFiles
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += configurations.compile
}

// Build a jar with javadoc.


task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}

artifacts {
archives sourcesJar
archives javadocJar
}

Make sure that you commit/push the above changes to GitHub.

4. Create a release from the current code on Github.

5. Run gradlew install on your code.

https://riptutorial.com/ 359
6. Your library is now available by the following dependency:

compile 'com.github.[YourUser]:[github repository name]:[release tag]'

Read Creating your own libraries for Android applications online:


https://riptutorial.com/android/topic/4118/creating-your-own-libraries-for-android-applications

https://riptutorial.com/ 360
Chapter 71: Custom Fonts
Examples
Putting a custom font in your app

1. Go to the (project folder)


2. Then app -> src -> main.
3. Create folder 'assets -> fonts' into the main folder.
4. Put your 'fontfile.ttf' into the fonts folder.

Initializing a font

private Typeface myFont;

// A good practice might be to call this in onCreate() of a custom


// Application class and pass 'this' as Context. Your font will be ready to use
// as long as your app lives
public void initFont(Context context) {
myFont = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Light.ttf");
}

Using a custom font in a TextView

public void setFont(TextView textView) {


textView.setTypeface(myFont);
}

Apply font on TextView by xml (Not required Java code)

TextViewPlus.java:

public class TextViewPlus extends TextView {


private static final String TAG = "TextView";

public TextViewPlus(Context context) {


super(context);
}

public TextViewPlus(Context context, AttributeSet attrs) {


super(context, attrs);
setCustomFont(context, attrs);
}

public TextViewPlus(Context context, AttributeSet attrs, int defStyle) {


super(context, attrs, defStyle);
setCustomFont(context, attrs);
}

private void setCustomFont(Context ctx, AttributeSet attrs) {

https://riptutorial.com/ 361
TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.TextViewPlus);
String customFont = a.getString(R.styleable.TextViewPlus_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}

public boolean setCustomFont(Context ctx, String asset) {


Typeface typeface = null;
try {
typeface = Typeface.createFromAsset(ctx.getAssets(), asset);
} catch (Exception e) {
Log.e(TAG, "Unable to load typeface: "+e.getMessage());
return false;
}

setTypeface(typeface);
return true;
}
}

attrs.xml: (Where to place res/values)

<?xml version="1.0" encoding="utf-8"?>


<resources>
<declare-styleable name="TextViewPlus">
<attr name="customFont" format="string"/>
</declare-styleable>
</resources>

How to use:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:foo="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">

<com.mypackage.TextViewPlus
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">
</com.mypackage.TextViewPlus>
</LinearLayout>

Custom font in canvas text

Drawing text in canvas with your font from assets.

Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/SomeFont.ttf");


Paint textPaint = new Paint();
textPaint.setTypeface(typeface);
canvas.drawText("Your text here", x, y, textPaint);

https://riptutorial.com/ 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.

public class TypefaceUtils {

private static final Hashtable<String, Typeface> sTypeFaces = new 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 = sTypeFaces.get(fileName);

if (tempTypeface == null) {
tempTypeface = Typeface.createFromAsset(context.getAssets(), fileName);
sTypeFaces.put(fileName, tempTypeface);
}

return tempTypeface;
}

Usage:

Typeface typeface = TypefaceUtils.getTypeface(context, "RobotoSlab-Bold.ttf");


setTypeface(typeface);

Custom font to whole activity

public class ReplaceFont {

public static void changeDefaultFont(Context context, String oldFont, String assetsFont) {


Typeface typeface = Typeface.createFromAsset(context.getAssets(), assetsFont);
replaceFont(oldFont, typeface);
}

private static void replaceFont(String oldFont, Typeface typeface) {


try {
Field myField = Typeface.class.getDeclaredField(oldFont);
myField.setAccessible(true);
myField.set(null, typeface);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}

https://riptutorial.com/ 363
Then in your activity, in onCreate() method:

// Put your font to assets folder...

ReplaceFont.changeDefaultFont(getApplication(), "DEFAULT", "LinLibertine.ttf");

Working with fonts in Android O

Android O changes the way to work with fonts.

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.

In order to add a new font, you have to do the following:

• Create a new resource directory: res/font.


• Add your font files into this font folder. For example, by adding myfont.ttf, you will be able to
use this font via R.font.myfont.

You can also create your own font family by adding the following XML file into the res/font
directory:

<?xml version="1.0" encoding="utf-8"?>


<font-family xmlns:android="http://schemas.android.com/apk/res/android">
<font
android:fontStyle="normal"
android:fontWeight="400"
android:font="@font/lobster_regular" />
<font
android:fontStyle="italic"
android:fontWeight="400"
android:font="@font/lobster_italic" />
</font-family>

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:

<style name="customfontstyle" parent="@android:style/TextAppearance.Small">


<item name="android:fontFamily">@font/myfont</item>
</style>

• In your code, by using the following lines of code:

https://riptutorial.com/ 364
Typeface typeface = getResources().getFont(R.font.myfont);
textView.setTypeface(typeface);

Read Custom Fonts online: https://riptutorial.com/android/topic/3358/custom-fonts

https://riptutorial.com/ 365
Chapter 72: Dagger 2
Syntax
• @Module
• @Component(dependencies={OtherComponent.class}, modules={ModuleA.class,
ModuleB.class})
• DaggerMyComponent.create()
• DaggerMyComponent.builder().myModule(newMyModule()).create()

Remarks
Not to confuse with dagger by square, the predecessor to dagger 2.

Examples
Component setup for Application and Activity injection

A basic AppComponent that depends on a single AppModule to provide application-wide singleton


objects.

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {

void inject(App app);

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 {

private final Application mApplication;

public AppModule(Application application) {


mApplication = application;
}

@Singleton
@Provides
Gson provideGson() {
return new Gson();
}

https://riptutorial.com/ 366
@Singleton
@Provides
Context provideContext() {
return mApplication;
}
}

A subclassed application to setup dagger and the singleton component.

public class App extends Application {

@Inject
AppComponent mAppComponent;

@Override
public void onCreate() {
super.onCreate();

DaggerAppComponent.builder().appModule(new AppModule(this)).build().inject(this);
}

public AppComponent getAppComponent() {


return mAppComponent;
}
}

Now an activity scoped component that depends on the AppComponent to gain access to the
singleton objects.

@ActivityScope
@Component(dependencies = AppComponent.class, modules = ActivityModule.class)
public interface MainActivityComponent {

void inject(MainActivity activity);


}

And a reusable ActivityModule that will provide basic dependencies, like a FragmentManager

@Module
public class ActivityModule {

private final AppCompatActivity mActivity;

public ActivityModule(AppCompatActivity activity) {


mActivity = activity;
}

@ActivityScope
public AppCompatActivity provideActivity() {
return mActivity;
}

@ActivityScope
public FragmentManager provideFragmentManager(AppCompatActivity activity) {
return activity.getSupportFragmentManager();

https://riptutorial.com/ 367
}
}

Putting everything together we're set up and can inject our activity and be sure to use the same
Gson throughout out app!

public class MainActivity extends AppCompatActivity {

@Inject
Gson mGson;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

DaggerMainActivityComponent.builder()
.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

Classes without dependencies can easily be created by dagger.

public class Engine {

@Inject // <-- Annotate your constructor.


public Engine() {
}
}

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.

public class Car {

https://riptutorial.com/ 368
private Engine engine;

@Inject
public Car(Engine engine) {
this.engine = 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

• it can create it by using constructor injection


• a module of the component can provide it
• it can be provided by the parent component (if it is a @Subcomponent)
• it can use an object exposed by a component it depends on (component dependencies)

Using @Subcomponent instead of @Component(dependencies={...})

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
void inject(App app);

Context provideContext();
Gson provideGson();

MainActivityComponent mainActivityComponent(ActivityModule activityModule);


}

@ActivityScope
@Subcomponent(modules = ActivityModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}

public class MainActivity extends AppCompatActivity {

@Inject
Gson mGson;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

((App)getApplication()).getAppComponent()
.mainActivityComponent(new ActivityModule(this)).inject(this);
}
}

How to add Dagger 2 in build.gradle

https://riptutorial.com/ 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.

For Gradle >= 2.2

dependencies {
// apt command comes from the android-apt plugin
annotationProcessor 'com.google.dagger:dagger-compiler:2.8'
compile 'com.google.dagger:dagger:2.8'
provided 'javax.annotation:jsr250-api:1.0'
}

For Gradle < 2.2

To use Dagger 2 it's necessary to add android-apt plugin, add this to the root build.gradle:

buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}

Then the application module's build.gradle should contain:

apply plugin: 'com.android.application'


apply plugin: 'com.neenbedankt.android-apt'

android {

}

final DAGGER_VERSION = '2.0.2'


dependencies {

compile "com.google.dagger:dagger:${DAGGER_VERSION}"
apt "com.google.dagger:dagger-compiler:${DAGGER_VERSION}"
}

Reference: https://github.com/codepath/android_guides/wiki/Dependency-Injection-with-Dagger-2

Creating a component from multiple modules

Dagger 2 supports creating a component from multiple modules. You can create your component
this way:

@Singleton
@Component(modules = {GeneralPurposeModule.class, SpecificModule.class})
public interface MyMultipleModuleComponent {
void inject(MyFragment myFragment);
void inject(MyService myService);

https://riptutorial.com/ 370
void inject(MyController myController);
void inject(MyActivity myActivity);
}

The two references modules GeneralPurposeModule and SpecificModule can then be implemented as
follows:

GeneralPurposeModule.java

@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();
}
}

SpecificModule.java

@Singleton
@Module
public class SpecificModule {
@Provides @Singleton
public RetrofitController getRetrofitController(Retrofit retrofit){
RetrofitController retrofitController = new RetrofitController();
retrofitController.setRetrofit(retrofit);
return retrofitController;
}

@Provides @Singleton
public MyService getMyService(RetrofitController retrofitController){
MyService myService = new MyService();
myService.setRetrofitController(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

https://riptutorial.com/ 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.

Read Dagger 2 online: https://riptutorial.com/android/topic/3088/dagger-2

https://riptutorial.com/ 372
Chapter 73: Data Binding Library
Remarks
Setup

Before using data binding, you must enable the plugin in your build.gradle.

android {
....
dataBinding {
enabled = true
}
}

Note: Data binding was added to the Android Gradle plugin in version 1.5.0

Binding class names

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

Gradle (Module:app) Configuration

android {
....
dataBinding {
enabled = true
}
}

Data model

public class Item {


public String name;
public String description;

public Item(String name, String description) {


this.name = name;
this.description = description;

https://riptutorial.com/ 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 @{model.fieldname}, where model
is the variable's name and fieldname is the field you want to access.

item_detail_activity.xml:

<?xml version="1.0" encoding="utf-8"?>


<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="com.example.Item"/>
</data>

<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="@{item.name}"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.description}"/>

</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.

This binding can then be used in an Activity like so:

public class ItemDetailActivity extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ItemDetailActivityBinding binding = DataBindingUtil.setContentView(this,
R.layout.item_detail_activity);
Item item = new Item("Example item", "This is an example item.");
binding.setItem(item);
}
}

Binding with an accessor method

https://riptutorial.com/ 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

public class Item {


private String name;

public String getName() {


return name;
}
}

Layout XML

<?xml version="1.0" encoding="utf-8"?>


<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="com.example.Item"/>
</data>

<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<!-- Since the "name" field is private on our data model,


this binding will utilize the public getName() method instead. -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>

</LinearLayout>
</layout>

Referencing classes

Data model

public class Item {


private String name;

public String getName() {


return name;
}
}

Layout XML

You must import referenced classes, just as you would in Java.

<?xml version="1.0" encoding="utf-8"?>


<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>

https://riptutorial.com/ 375
<import type="android.view.View"/>
<variable name="item" type="com.example.Item"/>
</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="@{item.name}"
android:visibility="@{item.name == null ? View.VISIBLE : View.GONE"/>

</LinearLayout>
</layout>

Note: The package java.lang.* is imported automatically by the system. (The same is made by
JVM for Java)

Databinding in Fragment

Data Model

public class Item {


private String name;

public String getName() {


return name;
}

public void setName(String name){


this.name = name;
}

Layout XML

<?xml version="1.0" encoding="utf-8"?>


<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="com.example.Item"/>
</data>

<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="@{item.name}"/>

https://riptutorial.com/ 376
</LinearLayout>
</layout>

Fragment

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable
Bundle savedInstanceState) {
FragmentTest binding = DataBindingUtil.inflate(inflater, R.layout.fragment_test,
container, false);
Item item = new Item();
item.setName("Thomas");
binding.setItem(item);
return binding.getRoot();
}

Built-in two-way Data Binding

Two-way Data-Binding supports the following attributes:

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

https://riptutorial.com/ 377
Usage

<layout ...>
<data>
<variable type="com.example.myapp.User" name="user"/>
</data>
<RelativeLayout ...>
<EditText android:text="@={user.firstName}" .../>
</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.

Data binding in RecyclerView Adapter

It's also possible to use data binding within your RecyclerView Adapter.

Data model

public class Item {


private String name;

public String getName() {


return name;
}
}

XML Layout

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"/>

Adapter class

public class ListItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private Activity host;


private List<Item> items;

public ListItemAdapter(Activity activity, List<Item> items) {


this.host = activity;
this.items = items;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// inflate layout and retrieve binding
ListItemBinding binding = DataBindingUtil.inflate(host.getLayoutInflater(),

https://riptutorial.com/ 378
R.layout.list_item, parent, false);

return new ItemViewHolder(binding);


}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Item item = items.get(position);

ItemViewHolder itemViewHolder = (ItemViewHolder)holder;


itemViewHolder.bindItem(item);
}

@Override
public int getItemCount() {
return items.size();
}

private static class ItemViewHolder extends RecyclerView.ViewHolder {


ListItemBinding binding;

ItemViewHolder(ListItemBinding binding) {
super(binding.getRoot());
this.binding = binding;
}

void bindItem(Item item) {


binding.setItem(item);
binding.executePendingBindings();
}
}
}

Click listener with Binding

Create interface for clickHandler

public interface ClickHandler {


public void onButtonClick(View v);
}

Layout XML

<?xml version="1.0" encoding="utf-8"?>


<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>
<variable
name="handler"
type="com.example.ClickHandler"/>
</data>

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
android:layout_width="wrap_content"

https://riptutorial.com/ 379
android:layout_height="wrap_content"
android:text="click me"
android:onClick="@{handler.onButtonClick}"/>
</RelativeLayout>
</layout>

Handle event in your Activity

public class MainActivity extends Activity implements ClickHandler {

private ActivityMainBinding binding;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
binding.setHandler(this);
}

@Override
public void onButtonClick(View v) {
Toast.makeText(context,"Button clicked",Toast.LENGTH_LONG).show();
}
}

Custom event using lambda expression

Define Interface

public interface ClickHandler {


public void onButtonClick(User user);
}

Create Model class

public class User {


private String name;

public User(String name) {


this.name = name;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}
}

Layout XML

<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>

https://riptutorial.com/ 380
<variable
name="handler"
type="com.example.ClickHandler"/>

<variable
name="user"
type="com.example.User"/>
</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="@{user.name}"
android:onClick="@{() -> handler.onButtonClick(user)}"/>
</RelativeLayout>
</layout>

Activity code :

public class MainActivity extends Activity implements ClickHandler {

private ActivityMainBinding binding;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
binding.setUser(new User("DataBinding User"));
binding.setHandler(this);
}

@Override
public void onButtonClick(User user) {
Toast.makeText(MainActivity.this,"Welcome " +
user.getName(),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

public class BindingUtil {


@BindingAdapter({"bind:autoAdapter"})
public static void setAdapter(AutoCompleteTextView view, ArrayAdapter<String>
pArrayAdapter) {
view.setAdapter(pArrayAdapter);
}
@BindingAdapter({"bind:onKeyListener"})
public static void setOnKeyListener(AutoCompleteTextView view , View.OnKeyListener
pOnKeyListener)
{
view.setOnKeyListener(pOnKeyListener);
}

https://riptutorial.com/ 381
}

Handler class

public class Handler extends BaseObservable {


private ArrayAdapter<String> roleAdapter;

public ArrayAdapter<String> getRoleAdapter() {


return roleAdapter;
}
public void setRoleAdapter(ArrayAdapter<String> pRoleAdapter) {
roleAdapter = pRoleAdapter;
}
}

XML

<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/tools" >

<data>
<variable
name="handler"
type="com.example.Handler" />
</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="@{handler.roleAdapter}" />

</LinearLayout>
</layout>

Default value in Data Binding

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

android:text="@{user.name, default=`Preview Text`}"

https://riptutorial.com/ 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

DataBinding with custom variables(int,boolean)

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="http://schemas.android.com/apk/res/android">

<data>

<import type="android.view.View" />

<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 ? View.VISIBLE : View.GONE}" />

</RelativeLayout>
</layout>

and set its value from java class.

binding.setSelected(true);

Databinding in Dialog

public void doSomething() {


DialogTestBinding binding = DataBindingUtil
.inflate(LayoutInflater.from(context), R.layout.dialog_test, null, false);

Dialog dialog = new Dialog(context);


dialog.setContentView(binding.getRoot());
dialog.show();
}

Pass widget as reference in BindingAdapter

Layout XML

https://riptutorial.com/ 383
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<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){
Glide.with(view.getContext()).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) {
progressBar.setVisibility(View.GONE);
return false;
}
}).into(view);
}

Read Data Binding Library online: https://riptutorial.com/android/topic/111/data-binding-library

https://riptutorial.com/ 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 static final int SALT_BYTES = 8;


private static final int PBK_ITERATIONS = 1000;
private static final String ENCRYPTION_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String PBE_ALGORITHM = "PBEwithSHA256and128BITAES-CBC-BC";

private EncryptedData encrypt(String password, byte[] data) throws NoSuchPaddingException,


NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, BadPaddingException,
IllegalBlockSizeException, InvalidAlgorithmParameterException {
EncryptedData encData = new EncryptedData();
SecureRandom rnd = new SecureRandom();
encData.salt = new byte[SALT_BYTES];
encData.iv = new byte[16]; // AES block size
rnd.nextBytes(encData.salt);
rnd.nextBytes(encData.iv);

PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), encData.salt, PBK_ITERATIONS);


SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(PBE_ALGORITHM);
Key key = secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
IvParameterSpec ivSpec = new IvParameterSpec(encData.iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
encData.encryptedData = cipher.doFinal(data);
return encData;
}

private byte[] decrypt(String password, byte[] salt, byte[] iv, byte[] encryptedData) throws
NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException,
InvalidAlgorithmParameterException {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, PBK_ITERATIONS);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(PBE_ALGORITHM);
Key key = secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
return cipher.doFinal(encryptedData);

https://riptutorial.com/ 385
}

private static class EncryptedData {


public byte[] salt;
public byte[] iv;
public byte[] encryptedData;
}

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, encData.salt, encData.iv, encData.encryptedData);
String decDataAsString = new String(decryptedData, "UTF-8");
Toast.makeText(this, decDataAsString, Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}

Read Data Encryption/Decryption online: https://riptutorial.com/android/topic/3471/data-


encryption-decryption

https://riptutorial.com/ 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("" + account.name, "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

https://riptutorial.com/ 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 sSyncAdapter.getSyncAdapterBinder();
}
}

Authenticator

public class Authenticator extends AbstractAccountAuthenticator {


// Simple constructor
public Authenticator(Context context) {
super(context);
}

// Editing properties is not supported


@Override
public Bundle editProperties(
AccountAuthenticatorResponse r, String s) {
throw new UnsupportedOperationException();
}

// Don't add additional accounts


@Override
public Bundle addAccount(
AccountAuthenticatorResponse r,
String s,
String s2,
String[] strings,
Bundle bundle) throws NetworkErrorException {
return null;
}

https://riptutorial.com/ 388
// Ignore attempts to confirm credentials
@Override
public Bundle confirmCredentials(
AccountAuthenticatorResponse r,
Account account,
Bundle bundle) throws NetworkErrorException {
return null;
}

// Getting an authentication token is not supported


@Override
public Bundle getAuthToken(
AccountAuthenticatorResponse r,
Account account,
String s,
Bundle bundle) throws NetworkErrorException {
throw new UnsupportedOperationException();
}

// Getting a label for the auth token is not supported


@Override
public String getAuthTokenLabel(String s) {
throw new UnsupportedOperationException();
}

// Updating user credentials is not supported


@Override
public Bundle updateCredentials(
AccountAuthenticatorResponse r,
Account account,
String s, Bundle bundle) throws NetworkErrorException {
throw new UnsupportedOperationException();
}

// Checking features for the account is not supported


@Override
public Bundle hasFeatures(
AccountAuthenticatorResponse r,
Account account, String[] strings) throws NetworkErrorException {
throw new UnsupportedOperationException();
}
}

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

https://riptutorial.com/ 389
* return the authenticator's IBinder.
*/
@Override
public IBinder onBind(Intent intent) {
return mAuthenticator.getIBinder();
}
}

AndroidManifest.xml additions

<uses-permission android:name="android.permission.GET_ACCOUNTS" />


<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />

<service
android:name=".syncAdapter.SyncService"
android:exported="true">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>

<service android:name=".authenticator.AuthenticatorService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>

<provider
android:name=".provider.StubProvider"
android:authorities="com.yourpackage.provider"
android:exported="false"
android:syncable="true" />

res/xml/authenticator.xml

<?xml version="1.0" encoding="utf-8"?>


<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.yourpackage"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:smallIcon="@mipmap/ic_launcher" />

res/xml/syncadapter.xml

<?xml version="1.0" encoding="utf-8"?>


<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.yourpackage.android"
android:allowParallelSyncs="false"
android:contentAuthority="com.yourpackage.provider"
android:isAlwaysSyncable="true"
android:supportsUploading="false"

https://riptutorial.com/ 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(

https://riptutorial.com/ 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

public Account CreateSyncAccount(Context context, String accountName) {


// Create the account type and default account
Account newAccount = new Account(
accountName, "com.yourpackage");
// Get an instance of the Android account manager
AccountManager accountManager =
(AccountManager) context.getSystemService(
ACCOUNT_SERVICE);
/*
* Add the account and account type, no password or user data
* If successful, return the Account object, otherwise report an error.
*/
if (accountManager.addAccountExplicitly(newAccount, null, null)) {
/*
* If you don't set android:syncable="true" in
* in your <provider> element in the manifest,
* then call context.setIsSyncable(account, AUTHORITY, 1)
* here.
*/
} else {
/*
* The account exists or some other error occurred. Log this, report it,
* or handle it internally.
*/
}
return newAccount;
}

Forcing a Sync

Bundle bundle = new Bundle();


bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true);
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
ContentResolver.requestSync(null, MyContentProvider.getAuthority(), bundle);

Read Data Synchronization with Sync Adapter online:


https://riptutorial.com/android/topic/1944/data-synchronization-with-sync-adapter

https://riptutorial.com/ 392
Chapter 76: Date and Time Pickers
Examples
Material DatePicker

add below dependencies to build.gradle file in dependency section. (this is an unOfficial library for
date picker)

compile 'com.wdullaer:materialdatetimepicker:2.3.0'

Now we have to open DatePicker on Button click event.

So create one Button on xml file like below.

<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"/>

and in MainActivity use this way.

public class MainActivity extends AppCompatActivity implements


DatePickerDialog.OnDateSetListener{

Button button;
Calendar calendar ;
DatePickerDialog datePickerDialog ;
int Year, Month, Day ;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

calendar = Calendar.getInstance();

Year = calendar.get(Calendar.YEAR) ;
Month = calendar.get(Calendar.MONTH);
Day = calendar.get(Calendar.DAY_OF_MONTH);

Button dialog_bt_date = (Button)findViewById(R.id.dialog_bt_date);


dialog_bt_date.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

datePickerDialog = DatePickerDialog.newInstance(MainActivity.this, Year,

https://riptutorial.com/ 393
Month, Day);

datePickerDialog.setThemeDark(false);

datePickerDialog.showYearPickerFirst(false);

datePickerDialog.setAccentColor(Color.parseColor("#0072BA"));

datePickerDialog.setTitle("Select Date From DatePickerDialog");

datePickerDialog.show(getFragmentManager(), "DatePickerDialog");

}
});
}

@Override
public void onDateSet(DatePickerDialog view, int Year, int Month, int Day) {

String date = "Selected Date : " + Day + "-" + Month + "-" + Year;

Toast.makeText(MainActivity.this, date, Toast.LENGTH_LONG).show();


}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.abc_main_menu, menu);
return true;
}

Output :

https://riptutorial.com/ 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 DatePickerDialog.OnDateSetListener.

public void showDatePicker(Context context,int initialYear, int initialMonth, int initialDay)

https://riptutorial.com/ 395
{
DatePickerDialog datePickerDialog = new DatePickerDialog(context,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker datepicker,int year ,int month, int day)
{
//this condition is necessary to work properly on all android versions
if(view.isShown()){
//You now have the selected year, month and day
}

}
}, initialYear, initialMonth , initialDay);

//Call show() to simply show the dialog


datePickerDialog.show();

Please note that month is a int starting from 0 for January to 11 for December

Read Date and Time Pickers online: https://riptutorial.com/android/topic/2836/date-and-time-


pickers

https://riptutorial.com/ 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.

Add the following to your styles.xml:

<style name="AppTheme" parent="Theme.AppCompat.DayNight">


<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>

The themes you can extend from to add day night theme switching capability are the following:

• "Theme.AppCompat.DayNight"
• "Theme.AppCompat.DayNight.NoActionBar"
• "Theme.AppCompat.DayNight.DarkActionBar"

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 colors.xml in the res/values directory
and another colors.xml in the res/values-night directory and define day/night colors appropriately.

To switch the theme, call the AppCompatDelegate.setDefaultNightMode(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:

AppCompatDelegate.setDefaultNightMode(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.

https://riptutorial.com/ 397
It is also possible to get the current night mode status using the getDefaultNightMode() method. For
example:

int modeType = AppCompatDelegate.getDefaultNightMode();

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.

Read DayNight Theme (AppCompat v23.2 / API 14+) online:


https://riptutorial.com/android/topic/7650/daynight-theme--appcompat-v23-2---api-14plus-

https://riptutorial.com/ 398
Chapter 78: Define step value (increment) for
custom RangeSeekBar
Introduction
A customization of the Android RangeSeekBar proposed by Alex Florescu at
https://github.com/anothem/android-range-seek-bar

It allows to define a step value (increment), when moving the seek bar

Remarks
1- Add the increment attribute in attrs.xml

<attr name="increment" format="integer|float"/>

2- Define a default value in RangeSeekBar.java and create the attribute also

private static final int DEFAULT_INCREMENT = 1;


private int increment;

3- Init the increment value in private void init(Context context, AttributeSet attrs)

if (attrs == null)
increment = DEFAULT_INCREMENT;
else
increment = a.getInt(R.styleable.RangeSeekBar_increment, DEFAULT_INCREMENT);

4- Define the increment value in protected synchronized void onDraw(@NonNull Canvas canvas)

You'll have to replace the minText and maxText value. So instead of :

• minText = valueToString(getSelectedMinValue());
• maxText = valueToString(getSelectedMaxValue());

You'll have : int x;

x = (int) ((getSelectedMinValue().intValue()+increment)/increment);
x = x*increment;
if (x<absoluteMaxValue.intValue())
minText = ""+x;
else
minText=""+(absoluteMaxValue.intValue()-increment);

x = (int) ((getSelectedMaxValue().intValue()+increment)/increment);
x = x*increment;
maxText = ""+x;

https://riptutorial.com/ 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" />

Read Define step value (increment) for custom RangeSeekBar online:


https://riptutorial.com/android/topic/8627/define-step-value--increment--for-custom-rangeseekbar

https://riptutorial.com/ 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

Java Singleton Pattern

To implement Singleton pattern, we have different approaches but all of them have following
common concepts.

• Private constructor to restrict instantiation of the class from other classes.


• Private static variable of the same class that is the only instance of the class.
• Public static method that returns the instance of the class, this is the global access
• point for outer world to get the instance of the singleton class.

/**
* 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;
}
}

https://riptutorial.com/ 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.

Implementing the observer pattern


1. The broadcaster has to provide methods that permit receivers to subscribe and unsubscribe
to it. When the broadcaster fires an event, subscribers need to be notified that an event has
occurred:

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.
}

Read Design Patterns online: https://riptutorial.com/android/topic/9949/design-patterns

https://riptutorial.com/ 402
Chapter 80: Detect Shake Event in Android
Examples
Shake Detector in Android Example

public class ShakeDetector implements SensorEventListener {

private static final float SHAKE_THRESHOLD_GRAVITY = 2.7F;


private static final int SHAKE_SLOP_TIME_MS = 500;
private static final int SHAKE_COUNT_RESET_TIME_MS = 3000;

private OnShakeListener mListener;


private long mShakeTimestamp;
private int mShakeCount;

public void setOnShakeListener(OnShakeListener listener) {


this.mListener = listener;
}

public interface OnShakeListener {


public void onShake(int count);
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// ignore
}

@Override
public void onSensorChanged(SensorEvent event) {

if (mListener != null) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];

float gX = x / SensorManager.GRAVITY_EARTH;
float gY = y / SensorManager.GRAVITY_EARTH;
float gZ = z / SensorManager.GRAVITY_EARTH;

// gForce will be close to 1 when there is no movement.


float gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ);

if (gForce > SHAKE_THRESHOLD_GRAVITY) {


final long now = System.currentTimeMillis();
// ignore shake events too close to each other (500ms)
if (mShakeTimestamp + SHAKE_SLOP_TIME_MS > now) {
return;
}

// reset the shake count after 3 seconds of no shakes


if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) {
mShakeCount = 0;
}

https://riptutorial.com/ 403
mShakeTimestamp = now;
mShakeCount++;

mListener.onShake(mShakeCount);
}
}
}
}

Using Seismic shake detection

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() {
sd.start(sm);
}

@Override
protected void onPause() {
sd.stop();
}

To define the a different acceleration threshold use sd.setSensitivity(sensitivity) with a


sensitivity of SENSITIVITY_LIGHT, SENSITIVITY_MEDIUM, SENSITIVITY_HARD or any other reasonable
integer value. The given default values range from 11 to 15.

Installation

compile 'com.squareup:seismic:1.0.2'

Read Detect Shake Event in Android online: https://riptutorial.com/android/topic/4501/detect-


shake-event-in-android

https://riptutorial.com/ 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.

// Get display metrics


DisplayMetrics metrics = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(metrics);

These DisplayMetrics hold a series of information about the devices screen, like its density or size:

// Get width and height in pixel


Integer heightPixels = metrics.heightPixels;
Integer widthPixels = metrics.widthPixels;

Get screen density

To get the screens density, we also can make use of the Windowmanagers DisplayMetrics. This is
a quick example:

// Get density in dpi


DisplayMetrics metrics = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(metrics);
int densityInDpi = metrics.densityDpi;

Formula px to dp, dp to px conversation

DP to Pixel:

private int dpToPx(int dp)


{
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}

Pixel to DP:

private int pxToDp(int px)


{
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}

Read Device Display Metrics online: https://riptutorial.com/android/topic/4207/device-display-


metrics

https://riptutorial.com/ 405
Chapter 82: Dialog
Parameters

Line Description

show(); Shows the dialog

sets the ContentView of the dialog to your custom


setContentView(R.layout.yourlayout);
layout.

dismiss() Closes the dialog

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 AlertDialog.Builder() class.
Following the Builder Pattern, all members of the AlertDialog.Builder 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

AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(


MainActivity.this);

alertDialogBuilder.setTitle("Title Dialog");
alertDialogBuilder
.setMessage("Message Dialog")
.setCancelable(true)
.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int arg1) {


// Handle Positive Button

}
})
.setNegativeButton("No",
new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int arg1) {

https://riptutorial.com/ 406
// Handle Negative Button
dialog.cancel();
}
});

AlertDialog alertDialog = alertDialogBuilder.create();


alertDialog.show();

A Basic Alert Dialog

AlertDialog.Builder builder = new AlertDialog.Builder(context);


//Set Title
builder.setTitle("Reset...")
//Set Message
.setMessage("Are you sure?")
//Set the icon of the dialog
.setIcon(drawable)
//Set the positive button, in this case, OK, which will dismiss the dialog and do
everything in the onClick method
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// Reset
}
});
AlertDialog dialog = builder.create();
//Now, any time you can call on:
dialog.show();
//So you can show the dialog.

Now this code will achieve this:

(Image source: WikiHow)

Date Picker within DialogFragment

xml of the Dialog:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

https://riptutorial.com/ 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 class ChooseDate extends DialogFragment implements View.OnClickListener {

private DatePicker datePicker;


private Button acceptButton;

private boolean isDateSetted = false;


private int year;
private int month;
private int day;

private DateListener listener;

public interface DateListener {


onDateSelected(int year, int month, int day);
}

public ChooseDate(){}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.dialog_year_picker, container);

getDialog().setTitle(getResources().getString("TITLE"));

datePicker = (DatePicker) rootView.findViewById(R.id.datePicker);


acceptButton = (Button) rootView.findViewById(R.id.buttonAccept);
acceptButton.setOnClickListener(this);

if (isDateSetted) {
datePicker.updateDate(year, month, day);
}

return rootView;
}

@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.buttonAccept:

https://riptutorial.com/ 408
int year = datePicker.getYear();
int month = datePicker.getMonth() + 1; // months start in 0
int day = datePicker.getDayOfMonth();

listener.onDateSelected(year, month, day);


break;
}
this.dismiss();
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
listener = (DateListener) context;
}

public void setDate(int year, int month, int day) {

this.year = year;
this.month = month;
this.day = day;
this.isDateSetted = true;
}

Activity calling the dialog:

public class MainActivity extends AppCompatActivity implements ChooseDate.DateListener{

private int year;


private int month;
private int day;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

private void showDateDialog();


}

private void showDateDialog(){


ChooseDate pickDialog = new ChooseDate();
// We could set a date
// pickDialog.setDate(23, 10, 2016);
pickDialog.show(getFragmentManager(), "");
}

@Override
onDateSelected(int year, int month, int day){
this.day = day;
this.month = month;
this.year = year;
}
}

DatePickerDialog

https://riptutorial.com/ 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.

How to show dialog:

DatePickerDialog datePickerDialog = new DatePickerDialog(context, listener, year, month, day);


datePickerDialog.show();

You can get DataPicker widget from dialog above, to get access to more functions, and for
example set minimum date in milliseconds:

DatePicker datePicker = datePickerDialog.getDatePicker();


datePicker.setMinDate(System.currentTimeMillis());

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.

Also we can limit range of date, which user can pick.

By setting minimum date in milliseconds

//In this case user can pick date only from future
datePicker.setMinDate(System.currentTimeMillis());

By setting maximum date in milliseconds

//In this case user can pick date only, before following week.
datePicker.setMaxDate(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(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:

Sample use of DatePickerDialog

public class SampleActivity extends AppCompatActivity implements


DatePickerDialog.OnDateSetListener {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

https://riptutorial.com/ 410
...
}

private void showDatePicker() {


//We need calendar to set current date as initial date in DatePickerDialog.
Calendar calendar = new GregorianCalendar(Locale.getDefault());
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);

DatePickerDialog datePickerDialog = new DatePickerDialog(this, this, year, month,


day);
datePickerDialog.show();
}

@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

Adding Material Design AlertDialog to your app using Appcompat

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 android.app 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
build.gradle file:

dependencies {
compile 'com.android.support:appcompat-v7:24.2.1'
//........
}

Be sure to import the correct class:

https://riptutorial.com/ 411
import android.support.v7.app.AlertDialog;

Then Create AlertDialog like this:

AlertDialog.Builder builder = new AlertDialog.Builder(this);


builder.setTitle("Are you sure?");
builder.setMessage("You'll lose all photos and media!");
builder.setPositiveButton("ERASE", null);
builder.setNegativeButton("CANCEL", null);
builder.show();

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
AlertDialog.Builder setAdapter.

private void showDialog()


{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Choose any item");

final List<String> lables = new ArrayList<>();


lables.add("Item 1");
lables.add("Item 2");
lables.add("Item 3");
lables.add("Item 4");

ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,


android.R.layout.simple_dropdown_item_1line, lables);
builder.setAdapter(dataAdapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this,"You have selected " +
lables.get(which),Toast.LENGTH_LONG).show();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}

Perhaps, if we don't need any particular ListView, we can use a basic way:

AlertDialog.Builder builder = new AlertDialog.Builder(this);


builder.setTitle("Select an item")
.setItems(R.array.your_array, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// The 'which' argument contains the index position of the selected item
Log.v(TAG, "Selected item on position " + which);
}
});
builder.create().show();

Custom Alert Dialog with EditText

https://riptutorial.com/ 412
void alertDialogDemo() {
// get alert_dialog.xml view
LayoutInflater li = LayoutInflater.from(getApplicationContext());
View promptsView = li.inflate(R.layout.alert_dialog, null);

AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(


getApplicationContext());

// set alert_dialog.xml to alertdialog builder


alertDialogBuilder.setView(promptsView);

final EditText userInput = (EditText) promptsView.findViewById(R.id.etUserInput);

// set dialog message


alertDialogBuilder
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// get user input and set it to result
// edit text
Toast.makeText(getApplicationContext(), "Entered:
"+userInput.getText().toString(), Toast.LENGTH_LONG).show();
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});

// create alert dialog


AlertDialog alertDialog = alertDialogBuilder.create();

// show it
alertDialog.show();
}

Xml file: res/layout/alert_dialog.xml

<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>

https://riptutorial.com/ 413
Fullscreen Custom Dialog with no background and no title

in styles.xml add your custom style:

<?xml version="1.0" encoding="utf-8"?>


<resources>
<style name="AppBaseTheme" parent="@android:style/Theme.Light.NoTitleBar.Fullscreen">
</style>
</resources>

Create your custom layout for the dialog: fullscreen.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
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 android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;

public class FullscreenActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//You can set no content for the activity.
Dialog mDialog = new Dialog(this, R.style.AppBaseTheme);
mDialog.setContentView(R.layout.fullscreen);
mDialog.show();
}
}

Alert Dialog with Multi-line Title

The setCustomTitle() method of AlertDialog.Builder 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.

AlertDialog.Builder builder = new AlertDialog.Builder(context, Theme_Material_Light_Dialog);

https://riptutorial.com/ 414
builder.setCustomTitle(inflate(context, R.layout.my_dialog_title, null))
.setView(inflate(context, R.layout.my_dialog, null))
.setPositiveButton("OK", null);

Dialog dialog = builder.create();


dialog.show();

my_dialog_title.xml:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">

<TextView
style="@android:style/TextAppearance.Small"
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:

<?xml version="1.0" encoding="utf-8"?>


<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:scrollbars="vertical">

<TextView
style="@android:style/TextAppearance.Small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:text="Hello world!"/>

<TextView
style="@android:style/TextAppearance.Small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:text="Hello world again!"/>

<TextView
style="@android:style/TextAppearance.Small"

https://riptutorial.com/ 415
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:text="Hello world again!"/>

<TextView

style="@android:style/TextAppearance.Small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:text="Hello world again!"/>

</LinearLayout>
</ScrollView>

Read Dialog online: https://riptutorial.com/android/topic/1225/dialog

https://riptutorial.com/ 416
Chapter 83: Displaying Google Ads
Examples
Basic Ad Setup

You'll need to add the following to your dependencies:

compile 'com.google.firebase:firebase-ads:10.2.1'

and then put this in the same file.

apply plugin: 'com.google.gms.google-services'

Next you'll need to add relevant information into your strings.xml.

<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.

<com.google.android.gms.ads.AdView
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">
</com.google.android.gms.ads.AdView>

And last but not least, throw this in your onCreate.

MobileAds.initialize(getApplicationContext(), "ca-app-pub-YOUR_ID");
AdView mAdView = (AdView) findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder().build();
mAdView.loadAd(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.

Make sure you have necessary permissions in your Manifest file:

<uses-permission android:name="android.permission.INTERNET" />


<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

https://riptutorial.com/ 417
1. Go to your AdMob account.

2. Click on Monetize tab.

3. Select or Create the app and choose the platform.

4. Select Interstitial and give an ad unit name.

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 'com.google.firebase:firebase-ads:10.2.1'

This one should be on the bottom.

apply plugin: 'com.google.gms.google-services'

Add your Ad unit ID to your strings.xml file

<string name="interstitial_full_screen">ca-app-pub-00000000/00000000</string>

Add ConfigChanges and meta-data to your manifest:

<activity
android:name="com.google.android.gms.ads.AdActivity"

android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScree

android:theme="@android:style/Theme.Translucent" />

and

<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />

Activity:

public class AdActivity extends AppCompatActivity {

private String TAG = AdActivity.class.getSimpleName();


InterstitialAd mInterstitialAd;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);

mInterstitialAd = new InterstitialAd(this);

https://riptutorial.com/ 418
// set the ad unit ID
mInterstitialAd.setAdUnitId(getString(R.string.interstitial_full_screen));

AdRequest adRequest = new AdRequest.Builder()


.build();

// Load ads into Interstitial Ads


mInterstitialAd.loadAd(adRequest);

mInterstitialAd.setAdListener(new AdListener() {
public void onAdLoaded() {
showInterstitial();
}
});
}

private void showInterstitial() {


if (mInterstitialAd.isLoaded()) {
mInterstitialAd.show();
}
}

This AdActivity will show a full screen ad now.

Read Displaying Google Ads online: https://riptutorial.com/android/topic/5984/displaying-google-


ads

https://riptutorial.com/ 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.

https://riptutorial.com/ 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:

https://riptutorial.com/ 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.

You can find more information here: https://developer.android.com/training/monitoring-device-


state/doze-standby.html

Examples
Exclude app from using doze mode

1. Open phone's settings


2. open battery
3. open menu and select "battery optimization"
4. from the dropdown menu select "all apps"
5. select the app you want to whitelist
6. select "don't optimize"

https://riptutorial.com/ 422
Now this app will show under not optimized apps.

An app can check whether it's whitelisted by calling isIgnoringBatteryOptimizations()

Whitelisting an Android application programmatically

Whitelisting won't disable the doze mode for your app, but you can do that by using network and
hold-wake locks.

Whitelisting an Android application programmatically can be done as follows:

boolean isIgnoringBatteryOptimizations = pm.isIgnoringBatteryOptimizations(getPackageName());


if(!isIgnoringBatteryOptimizations){
Intent intent = new Intent();
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, MY_IGNORE_OPTIMIZATION_REQUEST);
}

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 =
pm.isIgnoringBatteryOptimizations(getPackageName());
if(isIgnoringBatteryOptimizations){
// Ignoring battery optimization
}else{
// Not ignoring battery optimization
}
}
}

Read Doze Mode online: https://riptutorial.com/android/topic/4719/doze-mode

https://riptutorial.com/ 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.

Using framework APIs on SDK 21+:

Drawable d = context.getDrawable(R.drawable.ic_launcher);
d.setTint(Color.WHITE);

Using android.support.v4 library on SDK 4+:

//Load the untinted resource


final Drawable drawableRes = ContextCompat.getDrawable(context, R.drawable.ic_launcher);
//Wrap it with the compatibility library so it can be altered
Drawable tintedDrawable = DrawableCompat.wrap(drawableRes);
//Apply a coloured tint
DrawableCompat.setTint(tintedDrawable, Color.WHITE);
//At this point you may use the tintedDrawable just as you usually would
//(and drawableRes can be discarded)

//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.

You can replace usages of Color.WHITE using the methods below

When targetting older API's:

getResources().getColor(R.color.your_color);

Or on newer targets:

ContextCompat.getColor(context, R.color.your_color);

Make View with rounded corners

Create drawable file named with custom_rectangle.xml in drawable folder:

https://riptutorial.com/ 424
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >

<solid android:color="@android:color/white" />

<corners android:radius="10dip" />

<stroke
android:width="1dp"
android:color="@android:color/white" />

</shape>

Now apply rectangle background on View:

mView.setBackGround(R.drawlable.custom_rectangle);

Reference screenshot:

Circular View

For a circular View (in this case TextView) create a drawble round_view.xml in drawble folder:

<?xml version="1.0" encoding="utf-8"?>


<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#FAA23C" />
<stroke android:color="#FFF" android:width="2dp" />
</shape>

Assign the drawable to the View:

<TextView
android:id="@+id/game_score"
android:layout_width="60dp"
android:layout_height="60dp"

https://riptutorial.com/ 425
android:background="@drawable/round_score"
android:padding="6dp"
android:text="100"
android:textColor="#fff"
android:textSize="20sp"
android:textStyle="bold"
android:gravity="center" />

Now it should look like the orange circle:

Custom Drawable

Extend your class with Drawable and override these methods

public class IconDrawable extends Drawable {


/**
* Paint for drawing the shape
*/
private Paint paint;
/**
* Icon drawable to be drawn to the center of the shape
*/
private Drawable icon;
/**
* Desired width and height of icon
*/
private int desiredIconHeight, desiredIconWidth;

/**
* 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) {
this.icon = icon;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(backgroundColor);
desiredIconWidth = 50;
desiredIconHeight = 50;
}

@Override
public void draw(Canvas canvas) {
//if we are setting this drawable to a 80dpX80dp imageview

https://riptutorial.com/ 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
canvas.drawCircle(bounds.centerX(), bounds.centerY(), bounds.centerX(), paint);
//set the icon drawable's bounds to the center of the shape
icon.setBounds(bounds.centerX() - (desiredIconWidth / 2), bounds.centerY() -
(desiredIconHeight / 2), (bounds.centerX() - (desiredIconWidth / 2)) + desiredIconWidth,
(bounds.centerY() - (desiredIconHeight / 2)) + desiredIconHeight);
//draw the icon to the bounds
icon.draw(canvas);

@Override
public void setAlpha(int alpha) {
//sets alpha to your whole shape
paint.setAlpha(alpha);
}

@Override
public void setColorFilter(ColorFilter colorFilter) {
//sets color filter to your whole shape
paint.setColorFilter(colorFilter);
}

@Override
public int getOpacity() {
//give the desired opacity of the shape
return PixelFormat.TRANSLUCENT;
}
}

Declare a ImageView in your layout

<ImageView
android:layout_width="80dp"
android:id="@+id/imageView"
android:layout_height="80dp" />

Set your custom drawable to the ImageView

IconDrawable iconDrawable=new
IconDrawable(ContextCompat.getDrawable(this,android.R.drawable.ic_media_play),ContextCompat.getColor(th

imageView.setImageDrawable(iconDrawable);

Screenshot

Read Drawables online: https://riptutorial.com/android/topic/4841/drawables

https://riptutorial.com/ 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.

Retrieving the Value

Getting the value of the text entered into an EditText is as follows:

EditText simpleEditText = (EditText) findViewById(R.id.et_simple);


String strValue = simpleEditText.getText().toString();

Further Entry Customization

We might want to limit the entry to a single-line of text (avoid newlines):

<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"

https://riptutorial.com/ 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"
/>

Displaying Placeholder Hints

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

Changing the bottom line color

Assuming you are using the AppCompat library, you can override the styles colorControlNormal,
colorControlActivated, and colorControlHighlight:

<style name="Theme.App.Base" parent="Theme.AppCompat.Light.DarkActionBar">


<item name="colorControlNormal">#d32f2f</item>
<item name="colorControlActivated">#ff5722</item>
<item name="colorControlHighlight">#f44336</item>
</style>

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:

https://riptutorial.com/ 429
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_fragment,
container);
}

Listening for EditText Input

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.

Displaying Floating Label Feedback

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.

Customizing the InputType

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>

Most common input types include:

Type Description

textUri Text that will be used as a URI

textEmailAddress Text that will be used as an e-mail address

textPersonName Text that is the name of a person

textPassword Text that is a password that should be obscured

number A numeric only field

phone For entering a phone number

date For entering a date

https://riptutorial.com/ 430
Type Description

time For entering a time

textMultiLine Allow multiple lines of text in the field

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

textAutoCorrect Normal text keyboard that corrects commonly misspelled words

You can set multiple inputType attributes if needed (separated by '|').


Example:

<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" />

You can see a list of all available input types here.

`inputype` attribute

inputype attribute in EditText widget: (tested on Android 4.4.3 and 2.3.3)

<EditText android:id="@+id/et_test" android:inputType="?????"/>

textLongMessage= Keyboard: alphabet/default. Enter button: Send/Next. Emotion: yes. Case:


lowercase. Suggestion: yes. Add. chars: , and . and everything

textFilter= Keyboard: alphabet/default. Enter button: Send/Next. Emotion: yes. Case: lowercase.
Suggestion: no. Add. chars: , and . and everything

textCapWords= Keyboard: alphabet/default. Enter button: Send/Next. Emotion: yes. Case:


Camel Case. Suggestion: yes. Add. chars: , and . and everything

textCapSentences= Keyboard: alphabet/default. Enter button: Send/Next. Emotion: yes. Case:

https://riptutorial.com/ 431
Sentence case. Suggestion: yes. Add. chars: , and . and everything

time= Keyboard: numeric. Enter button: Send/Next. Emotion: no. Case: -. Suggestion: no. Add.
chars: :

textMultiLine= Keyboard: alphabet/default. Enter button: nextline. Emotion: yes. Case:


lowercase. Suggestion: yes. Add. chars: , and . and everything

number= Keyboard: numeric. Enter button: Send/Next. Emotion: no. Case: -. Suggestion: no.
Add. chars: nothing

textEmailAddress= Keyboard: alphabet/default. Enter button: Send/Next. Emotion: no. Case:


lowercase. Suggestion: no. Add. chars: @ and . and everything

(No type)= Keyboard: alphabet/default. Enter button: nextline. Emotion: yes. Case: lowercase.
Suggestion: yes. Add. chars: , and . and everything

textPassword= Keyboard: alphabet/default. Enter button: Send/Next. Emotion: no. Case:


lowercase. Suggestion: no. 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

textShortMessage= Keyboard: alphabet/default. Enter button: emotion. 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

textCapCharacters= Keyboard: alphabet/default. Enter button: Send/Next. Emotion: yes. Case:


UPPERCASE. Suggestion: yes. Add. chars: , and . and everything

phone= Keyboard: numeric. Enter button: Send/Next. Emotion: no. Case: -. Suggestion: no.
Add. chars: *** # . - / () W P N , +**

textPersonName= Keyboard: alphabet/default. Enter button: Send/Next. Emotion: yes. Case:


lowercase. Suggestion: yes. Add. chars: , and . and everything

Note: Auto-capitalization setting will change the default behavior.

Note 2: In the Numeric keyboard, ALL numbers are English 1234567890.

Note 3: Correction/Suggestion setting will change the default behavior.

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

https://riptutorial.com/ 432
hideSoftInputFromWindow and passing in the token of the window containing your focused view.
The code to do the following:

public void hideSoftKeyboard()


{
InputMethodManager inputMethodManager = (InputMethodManager)
getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}

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.

public void setupUI(View view)


{
String s = "inside";
//Set up touch listener for non-text box views to hide keyboard.
if (!(view instanceof EditText)) {

view.setOnTouchListener(new View.OnTouchListener() {

public boolean onTouch(View v, MotionEvent event) {


hideSoftKeyboard();
return false;
}

});
}

//If a layout container, iterate over children and seed recursion.


if (view instanceof ViewGroup) {

for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {

View innerView = ((ViewGroup) view).getChildAt(i);

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.

Note: In this just I am using setCompoundDrawablesWithIntrinsicBounds, So if you


want to change the icon position you can achieve that using
setCompoundDrawablesWithIntrinsicBounds in setIcon.

public class MKEditText extends AppCompatEditText {

public interface IconClickListener {


public void onClick();

https://riptutorial.com/ 433
}

private IconClickListener mIconClickListener;

private static final String TAG = MKEditText.class.getSimpleName();

private final int EXTRA_TOUCH_AREA = 50;


private Drawable mDrawable;
private boolean touchDown;

public MKEditText(Context context, AttributeSet attrs, int defStyle) {


super(context, attrs, defStyle);
}

public MKEditText(Context context) {


super(context);
}

public MKEditText(Context context, AttributeSet attrs) {


super(context, attrs);
}

public void showRightIcon() {


mDrawable = ContextCompat.getDrawable(getContext(), R.drawable.ic_android_black_24dp);

setIcon();
}

public void setIconClickListener(IconClickListener iconClickListener) {


mIconClickListener = iconClickListener;
}

private void setIcon() {


Drawable[] drawables = getCompoundDrawables();

setCompoundDrawablesWithIntrinsicBounds(drawables[0], drawables[1], mDrawable,


drawables[3]);

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) event.getX();
switch (event.getAction()) {
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) {
mIconClickListener.onClick();

https://riptutorial.com/ 434
}
return true;
}
touchDown = false;
break;

}
return super.onTouchEvent(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,

MKEditText mkEditText = (MKEditText) findViewById(R.id.password);


mkEditText.showRightIcon();
mkEditText.setIconClickListener(new MKEditText.IconClickListener() {
@Override
public void onClick() {
// You can do action here for the icon.

}
});

Read EditText online: https://riptutorial.com/android/topic/5843/edittext

https://riptutorial.com/ 435
Chapter 87: Email Validation
Examples
Email address validation

Add the following method to check whether an email address is valid or not:

private boolean isValidEmailId(String email){


return Pattern.compile("^(([\\w-]+\\.)+[\\w-]+|([a-zA-Z]{1}|[\\w-]{2,}))@"
+ "((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\.([0-1]?"
+ "[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\."
+ "([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\.([0-1]?"
+ "[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
+ "([a-zA-Z]+[\\w-]+\\.)+[a-zA-Z]{2,4})$").matcher(email).matches();
}

The above method can easily be verified by converting the text of an EditText widget into a String:

if(isValidEmailId(edtEmailId.getText().toString().trim())){
Toast.makeText(getApplicationContext(), "Valid Email Address.", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(), "InValid Email Address.",
Toast.LENGTH_SHORT).show();
}

Email Address validation with using Patterns

if (Patterns.EMAIL_ADDRESS.matcher(email).matches()){
Log.i("EmailCheck","It is valid");
}

Read Email Validation online: https://riptutorial.com/android/topic/5605/email-validation

https://riptutorial.com/ 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:

https://riptutorial.com/ 437
https://riptutorial.com/ 438
2. A drop shadow below the device frame.
3. A screen glare across device frame and screenshot.

https://riptutorial.com/ 439
https://riptutorial.com/ 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.

Resolving Errors while starting emulator

https://riptutorial.com/ 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/IntelHAXM.exe.

Follow the on-screen instructions to complete installation.

Or for OS X you can do it without onscreen prompts like this:


/extras/intel/Hardware_Accelerated_Execution_Manager/HAXM\ installation

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.

Read Emulator online: https://riptutorial.com/android/topic/122/emulator

https://riptutorial.com/ 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:

AlertDialog.Builder builder1 = new AlertDialog.Builder(youractivity.this);

builder1.setMessage(Html.fromHtml("your message,<a href=\"http://www.google.com\">link</a>"));

builder1.setCancelable(false);
builder1.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});

AlertDialog Alert1 = builder1.create();


Alert1 .show();
((TextView)Alert1.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance(

Read Enhancing Alert Dialogs online: https://riptutorial.com/android/topic/10163/enhancing-alert-


dialogs

https://riptutorial.com/ 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.

Limitations of 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

In order to use icon fonts, just follow the steps below:

• Add the font file to your project

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

https://riptutorial.com/ 444
the .ttf font file into a folder named fonts (name it as you wish) in the assets folder:

• Create a Helper Class

Now, create the following helper class, so that you can avoid repeating the initialisation code
for the font:

public class FontManager {


public static final String ROOT = "fonts/";
FONT_AWESOME = ROOT + "myfont.ttf";
public static Typeface getTypeface(Context context) {
return Typeface.createFromAsset(context.getAssets(), FONT_AWESOME);
}
}

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:

Button button=(Button) findViewById(R.id.button);


Typeface iconFont=FontManager.getTypeface(getApplicationContext());
button.setTypeface(iconFont);

Now, the button typeface has been changed to the newly created icon font.

• Pick up the icons you want

Open the styles.css 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”;
}

https://riptutorial.com/ 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”>&#xe001; </string>
<string name=”icon_arrow_circle_left”>&#xe002; </string>
<string name=”icon_arrow_circle-o_down”>&#xe003; </string>
<string name=”icon_arrow_circle_o_left”>&#xe004; </string>
</resources>

• Use the icons in your code

Now, you may use your font in various views, for example, as follows:

button.setText(getString(R.string.icon_arrow_circle_left))

You may also create button text views using icon fonts:

https://riptutorial.com/ 446
TabLayout with icon fonts

public class TabAdapter extends FragmentPagerAdapter {

CustomTypefaceSpan fonte;
List<Fragment> fragments = new ArrayList<>(4);
private String[] icons = {"\ue001","\uE002","\uE003","\uE004"};

public TabAdapter(FragmentManager fm, CustomTypefaceSpan fonte) {


super(fm);
this.fonte = fonte
for (int i = 0; i < 4; i++){
fragments.add(MyFragment.newInstance());
}
}

public List<Fragment> getFragments() {


return fragments;
}

@Override
public Fragment getItem(int position) {
return fragments.get(position);
}

https://riptutorial.com/ 447
@Override
public CharSequence getPageTitle(int position) {
SpannableStringBuilder ss = new SpannableStringBuilder(icons[position]);
ss.setSpan(fonte,0,ss.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
ss.setSpan(new RelativeSizeSpan(1.5f),0,ss.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE );
return ss;
}

@Override
public int getCount() {
return 4;
}

• In this example, myfont.ttf is in Assets folder. Creating Assets folder


• In your activity class

//..
TabLayout tabs;
ViewPager tabs_pager;
public CustomTypefaceSpan fonte;
//..

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
fm = getSupportFragmentManager();
fonte = new
CustomTypefaceSpan("icomoon",Typeface.createFromAsset(getAssets(),"myfont.ttf"));
this.tabs = ((TabLayout) hasViews.findViewById(R.id.tabs));
this.tabs_pager = ((ViewPager) hasViews.findViewById(R.id.tabs_pager));
//...
}

@Override
protected void onStart() {
super.onStart();
//..
tabs_pager.setAdapter(new TabAdapter(fm,fonte));
tabs.setupWithViewPager(tabs_pager);
//..

Read Enhancing Android Performance Using Icon Fonts online:


https://riptutorial.com/android/topic/3642/enhancing-android-performance-using-icon-fonts

https://riptutorial.com/ 448
Chapter 91: Exceptions
Examples
NetworkOnMainThreadException

From the documentation:

The exception that is thrown when an application attempts to perform a networking


operation on its main thread.

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.

Here's an example of a code fragment that may cause that exception:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Uri.Builder builder = new Uri.Builder().scheme("http").authority("www.google.com");


HttpURLConnection urlConnection = null;
BufferedReader reader = null;
URL url;
try {
url = new URL(builder.build().toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
} catch (IOException e) {
Log.e("TAG","Connection error", e);
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("TAG", "Error closing stream", e);
}
}
}
}
}

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.

https://riptutorial.com/ 449
To avoid this exception, your network operations must always run in a background task via an
AsyncTask, Thread, IntentService, etc.

private class MyAsyncTask extends AsyncTask<String, Integer, Void> {

@Override
protected Void doInBackground(String[] params) {
Uri.Builder builder = new Uri.Builder().scheme("http").authority("www.google.com");
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
URL url;
try {
url = new URL(builder.build().toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
} catch (IOException e) {
Log.e("TAG","Connection error", e);
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} 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:

android.content.ActivityNotFoundException : Unable to find explicit activity class;


have you declared this activity in your AndroidManifest.xml?

In this case, check if you have declared your activity in the AndroidManifest.xml file.

The simplest way to declare your Activity in AndroidManifest.xml is:

<activity android:name="com.yourdomain.YourStoppedActivity" />

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.

https://riptutorial.com/ 450
You have some options:

1. Use a large application heap

Add the "largeHeap" option to the application tag in your AndroidManifest.xml. This will make more
memory available to your app but will likely not fix the root issue.

<application largeHeap="true" ... >

2. Recycle your bitmaps

After loading a bitmap, be sure to recycle it and free up memory:

if (bitmap != null && !bitmap.isRecycled())


bitmap.recycle();

3. Load sampled bitmaps into memory

Avoid loading the entire bitmap into memory at once by sampling a reduced size, using
BitmapOptions and inSampleSize.

See Android documentation for example

DexException

com.android.dex.DexException: Multiple dex files define Lcom/example/lib/Class;

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:

https://riptutorial.com/ 451
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
try {
Thread
.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {

@Override
public void uncaughtException(Thread thread, Throwable e) {
Log.e(TAG,
"Uncaught Exception thread: "+thread.getName()+"
"+e.getStackTrace());
handleUncaughtException (thread, e);
}
});
} catch (SecurityException e) {
Log.e(TAG,
"Could not set the Default Uncaught Exception Handler:"
+e.getStackTrace());
}
}

private void handleUncaughtException (Thread thread, Throwable e){


Log.e(TAG, "uncaughtException:");
e.printStackTrace();
}
}

Registering own Handler for unexpected exceptions

This is how you can react to exceptions which have not been catched, similar to the system's
standard "Application XYZ has crashed"

import android.app.Application;
import android.util.Log;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
* 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() {
super.onCreate();

// Setup handler for uncaught exceptions.


final Thread.UncaughtExceptionHandler defaultHandler =
Thread.getDefaultUncaughtExceptionHandler();

https://riptutorial.com/ 452
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable e) {
try {
handleUncaughtException(e);
System.exit(1);
} catch (Throwable e2) {
Log.e(TAG, "Exception in custom exception handler", e2);
defaultHandler.uncaughtException(thread, e);
}
}
});
}

private void handleUncaughtException(Throwable e) throws IOException {


Log.e(TAG, "Uncaught exception logged to local file", e);

// Create a new unique file


final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.US);
String timestamp;
File file = null;
while (file == null || file.exists()) {
timestamp = dateFormat.format(new Date());
file = new File(getFilesDir(), "crashLog_" + timestamp + ".txt");
}
Log.i(TAG, "Trying to create log file " + file.getPath());
file.createNewFile();

// Write the stacktrace to the file


FileWriter writer = null;
try {
writer = new FileWriter(file, true);
for (StackTraceElement element : e.getStackTrace()) {
writer.write(element.toString());
}
} finally {
if (writer != null) writer.close();
}

// You can (and probably should) also display a dialog to notify the user
}
}

Then register this Application class in your AndroidManifest.xml:

<application android:name="de.ioxp.arkmobile.MyApplication" >

Read Exceptions online: https://riptutorial.com/android/topic/112/exceptions

https://riptutorial.com/ 453
Chapter 92: ExoPlayer
Examples
Add ExoPlayer to the project

Via jCenter

including the following in your project's build.gradle file:

compile 'com.google.android.exoplayer: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

Instantiate your ExoPlayer:

exoPlayer = ExoPlayer.Factory.newInstance(RENDERER_COUNT, minBufferMs, minRebufferMs);

To play audio only you can use these values:

RENDERER_COUNT = 1 //since you want to render simple audio


minBufferMs = 1000
minRebufferMs = 5000

Both buffer values can be tweaked according to your requirements.

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:

DataSource dataSource = new DefaultUriDataSource(context, null);

Then create the sampleSource:

ExtractorSampleSource sampleSource = new ExtractorSampleSource(


uri, dataSource, new Mp3Extractor(), RENDERER_COUNT, requestedBufferSize);

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:

https://riptutorial.com/ 454
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);

Finally call prepare on your exoPlayer instance:

exoPlayer.prepare(audioRenderer);

To start playback call:

exoPlayer.setPlayWhenReady(true);

Main steps to play video & audio using the standard TrackRenderer
implementations

// 1. Instantiate the player.


player = ExoPlayer.Factory.newInstance(RENDERER_COUNT);
// 2. Construct renderers.
MediaCodecVideoTrackRenderer videoRenderer = ...
MediaCodecAudioTrackRenderer audioRenderer = ...
// 3. Inject the renderers through prepare.
player.prepare(videoRenderer, audioRenderer);
// 4. Pass the surface to the video renderer.
player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
// 5. Start playback.
player.setPlayWhenReady(true);
...
player.release(); // Don’t forget to release when done!

Read ExoPlayer online: https://riptutorial.com/android/topic/6248/exoplayer

https://riptutorial.com/ 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

TAG A String used while logging

FacebookSignInHelper A static reference to facebook helper

CallbackManager A callback for facebook operations

Activity A context

An array that contains all permission required from facebook to


PERMISSION_LOGIN
login.

loginCallback A callback for facebook login

Examples
How to add Facebook Login in Android

Add below dependencies to your build.gradle

// Facebook login
compile 'com.facebook.android:facebook-android-sdk:4.21.1'

Add below helper class to your utility package:

/**
* Created by Andy
* An utility for Facebook
*/
public class FacebookSignInHelper {
private static final String TAG = FacebookSignInHelper.class.getSimpleName();
private static FacebookSignInHelper facebookSignInHelper = null;

https://riptutorial.com/ 456
private CallbackManager callbackManager;
private Activity mActivity;
private static final Collection<String> PERMISSION_LOGIN = (Collection<String>)
Arrays.asList("public_profile", "user_friends","email");
private FacebookCallback<LoginResult> loginCallback;

public static FacebookSignInHelper newInstance(Activity context) {


if (facebookSignInHelper == null)
facebookSignInHelper = new FacebookSignInHelper(context);
return facebookSignInHelper;
}

public FacebookSignInHelper(Activity mActivity) {


try {
this.mActivity = mActivity;
// Initialize the SDK before executing any other operations,
// especially, if you're using Facebook UI elements.
FacebookSdk.sdkInitialize(this.mActivity);
callbackManager = CallbackManager.Factory.create();
loginCallback = new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
// You are logged into Facebook
}

@Override
public void onCancel() {
Log.d(TAG, "Facebook: Cancelled by user");
}

@Override
public void onError(FacebookException error) {
Log.d(TAG, "FacebookException: " + error.getMessage());
}
};
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* To login user on facebook without default Facebook button
*/
public void loginUser() {
try {
LoginManager.getInstance().registerCallback(callbackManager, loginCallback);
LoginManager.getInstance().logInWithReadPermissions(this.mActivity,
PERMISSION_LOGIN);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* To log out user from facebook
*/
public void signOut() {

https://riptutorial.com/ 457
// Facebook sign out
LoginManager.getInstance().logOut();
}

public CallbackManager getCallbackManager() {


return callbackManager;
}

public FacebookCallback<LoginResult> getLoginCallback() {


return loginCallback;
}

/**
* 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 = context.getPackageManager().getPackageInfo(
context.getPackageName(),
PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
keyHash = Base64.encodeToString(md.digest(), Base64.DEFAULT);
Log.d(TAG, "KeyHash:" + keyHash);
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return keyHash;
}
}

Add below code in Your Activity:

FacebookSignInHelper facebookSignInHelper =
FacebookSignInHelper.newInstance(LoginActivity.this, fireBaseAuthHelper);
facebookSignInHelper.loginUser();

Add below code to your OnActivityResult:

facebookSignInHelper.getCallbackManager().onActivityResult(requestCode, resultCode, data);

Setting permissions to access data from the Facebook profile

If you want to retrieve the details of a user's Facebook profile, you need to set permissions for the
same:

https://riptutorial.com/ 458
loginButton = (LoginButton)findViewById(R.id.login_button);

loginButton.setReadPermissions(Arrays.asList("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).

Create your own custom button for Facebook login

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">

<com.facebook.login.widget.LoginButton
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 com.facebook.login.widget.LoginButton 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

https://riptutorial.com/ 459
button:

//The original Facebook button


LoginButton loginButton = (LoginButton)findViewById(R.id.login_button);

//Our custom Facebook button


fb = (Button) findViewById(R.id.fb);

public void onClickFacebookButton(View view) {


if (view == fb) {
loginButton.performClick();
}
}

Great! Now the button looks something like this:

A minimalistic guide to Facebook login/signup implementation

1. You have to setup the prerequisites.

2. Add the Facebook activity to the AndroidManifest.xml file:

<activity
android:name="com.facebook.FacebookActivity"
android:configChanges= "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:label="@string/app_name" />

3. Add the login button to your layout XML file:

<com.facebook.login.widget.LoginButton
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:

loginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {


@Override
public void onSuccess(LoginResult loginResult) {
// Completed without error. You might want to use the retrieved data here.
}

@Override
public void onCancel() {

https://riptutorial.com/ 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.
}
});

Logging out of Facebook

Facebook SDK 4.0 onwards, this is how we logout:

com.facebook.login.LoginManager.getInstance().logOut();

For versions before 4.0, the logging out is gone by explicitly clearing the access token:

Session session = Session.getActiveSession();


session.closeAndClearTokenInformation();

Read Facebook SDK for Android online: https://riptutorial.com/android/topic/3919/facebook-sdk-


for-android

https://riptutorial.com/ 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:

1. Download and install jdk8.

2. Add the following to your project’s main build.gradle

buildscript {
repositories {
mavenCentral()
}

dependencies {
classpath 'me.tatarka:gradle-retrolambda:3.2.3'
}
}

3. Now add this to your application module’s build.gradle

apply plugin: 'com.android.application' // or apply plugin: 'java'


apply plugin: 'me.tatarka.retrolambda'

4. Add these lines to your application module’s build.gradle to inform the IDE of the language
level:

android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

https://riptutorial.com/ 462
Example:

So things like this:

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
log("Clicked");
}
});

Become this:

button.setOnClickListener(v -> log("Clicked"));

Read Fast way to setup Retrolambda on an android project. online:


https://riptutorial.com/android/topic/8822/fast-way-to-setup-retrolambda-on-an-android-project-

https://riptutorial.com/ 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 best performance in server side and android client

Provide simple toJSONString() and parseObject() methods to convert Java objects to JSON and
vice-versa

Allow pre-existing unmodifiable objects to be converted to and from JSON

Extensive support of Java Generics

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

You can look at example in Fastjson library

Encode

import com.alibaba.fastjson.JSON;

Group group = new Group();


group.setId(0L);
group.setName("admin");

User guestUser = new User();


guestUser.setId(2L);
guestUser.setName("guest");

User rootUser = new User();

https://riptutorial.com/ 464
rootUser.setId(3L);
rootUser.setName("root");

group.addUser(guestUser);
group.addUser(rootUser);

String jsonString = JSON.toJSONString(group);

System.out.println(jsonString);

Output

{"id":0,"name":"admin","users":[{"id":2,"name":"guest"},{"id":3,"name":"root"}]}

Decode

String jsonString = ...;


Group group = JSON.parseObject(jsonString, Group.class);

Group.java

public class Group {

private Long id;


private String name;
private List<User> users = new ArrayList<User>();

public Long getId() {


return id;
}

public void setId(Long id) {


this.id = id;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}

public List<User> getUsers() {


return users;
}

public void setUsers(List<User> users) {


this.users = users;
}

public void addUser(User user) {


users.add(user);
}
}

User.java

https://riptutorial.com/ 465
public class User {

private Long id;


private String name;

public Long getId() {


return id;
}

public void setId(Long id) {


this.id = id;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}
}

Convert the data of type Map to JSON String

Code

Group group = new Group();


group.setId(1);
group.setName("Ke");

User user1 = new User();


user1.setId(2);
user1.setName("Liu");

User user2 = new User();


user2.setId(3);
user2.setName("Yue");
group.getList().add(user1);
group.getList().add(user2);

Map<Integer, Object> map = new HashMap<Integer,Object>();


map.put(1, "No.1");
map.put(2, "No.2");
map.put(3, group.getList());

String jsonString = JSON.toJSONString(map);


System.out.println(jsonString);

Output

{1:"No.1",2:"No.2",3:[{"id":2,"name":"Liu"},{"id":3,"name":"Yue"}]}

Read Fastjson online: https://riptutorial.com/android/topic/10865/fastjson

https://riptutorial.com/ 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: https://docs.fastlane.tools/

Source Code: https://github.com/fastlane/fastlane

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.

To build and deploy all flavors use:

fastlane android beta

To build a single APK and deploy use:

fastlane android beta app:flavorName

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

1. android argument tells fastlane that we will use :android platform.


2. Inside :android platform you can have multiple lanes. Currently, I have only :beta lane. The
second argument from the command above specifies the lane we want to use.
3. options[:app]
4. There are two Gradle tasks. First, it runs gradle clean. If you provided a flavor with app key,
fastfile runs gradle assembleReleaseFlavor. Otherwise, it runs gradle assembleRelease to build
all build flavors.
5. If we are building for all flavors, an array of generated APK file names is stored inside
SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS. We use this to loop through generated files and
deploy them to Beta by Crashlytics. notifications and groups fields are optional. They are
used to notify testers registered for the app on Beta by Crashlytics.
6. If you are familiar with Crashlytics, you might know that to activate an app in the portal, you
have to run it on a device and use it first. Otherwise, Crashlytics will assume the app inactive

https://riptutorial.com/ 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"] = "https://hooks.slack.com/servic...."
end

lane :beta do |options|


# Clean and build the Release version of the app.
# Usage `fastlane android beta app:flavorName`

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 |

puts "Uploading APK to Crashlytics: " + 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]

https://riptutorial.com/ 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

error do |lane, exception|


slack(
message: exception.message,
success: false,
default_payloads: [:git_branch, :lane, :test_result]
)
end
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.

For example: fastlane installAll type:Debug

https://riptutorial.com/ 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.

lane :installAll do |options|

gradle(task: "clean")

gradle(task: "assemble",
build_type: options[:type])

lane_context[SharedValues::GRADLE_ALL_APK_OUTPUT_PATHS].each do | apk |

puts "Uploading APK to Device: " + apk

begin
adb(
command: "install -r #{apk}"
)
rescue => ex
puts ex
end
end
end

Read fastlane online: https://riptutorial.com/android/topic/8215/fastlane

https://riptutorial.com/ 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 java.io 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 File.delete() you can call Context.deleteFile(), and
instead of applying File.listFiles() recursively you can call Context.fileList() to get the list of all
your app specific files with somewhat less code. However, they do not provide extra functionality
beyond standard java.io 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.

Your activity could contain the following code, for instance:

File myFolder = getFilesDir();


File myFile = new File(myFolder, "myData.bin");

Writing raw array of bytes

File myFile = new File(getFilesDir(), "myData.bin");


FileOutputStream out = new FileOutputStream(myFile);

// Write four bytes one two three four:


out.write(new byte [] { 1, 2, 3, 4}
out.close()

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.

https://riptutorial.com/ 471
Serializing the object

The old good Java object serialization is available for you in Android. you can define Serializable
classes like:

class Cirle implements Serializable {


final int radius;
final String name;

Circle(int radius, int name) {


this.radius = radius;
this.name = name;
}
}

and then write then to the ObjectOutputStream:

File myFile = new File(getFilesDir(), "myObjects.bin");


FileOutputStream out = new FileOutputStream(myFile);
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(out));

oout.writeObject(new Circle(10, "One"));


oout.writeObject(new Circle(12, "Two"));

oout.close()

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.

Writing to external storage (SD card)

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.

Accessing external storage requires permissions in you Android manifest:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

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.

https://riptutorial.com/ 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.

Solving "Invisible MTP files" problem.

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:

File file = new File(Environment.getExternalStoragePublicDirectory(


Environment.DIRECTORY_DOCUMENTS), "theDocument.txt");
FileOutputStream out = new FileOutputStream(file)

... (write the document)

out.close()
MediaScannerConnection.scanFile(this, new String[] {file.getPath()}, null, null);
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
Uri.fromFile(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.

Working with big files

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:

class FileOperation extends AsyncTask<String, Void, File> {

@Override
protected File doInBackground(String... params) {
try {
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS), "bigAndComplexDocument.odf");
FileOutputStream out = new FileOutputStream(file)

... (write the document)

out.close()
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

https://riptutorial.com/ 473
protected void onPreExecute() {
// This is called before we begin
}

@Override
protected void onProgressUpdate(Void... values) {
// Unlikely required for this example
}
}
}

and then

new FileOperation().execute("Some parameters");

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.

Read FileIO with Android online: https://riptutorial.com/android/topic/8689/fileio-with-android

https://riptutorial.com/ 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:

Specify the directories in which the files you


want to share are placed
To share files we'll use a FileProvider, a class allowing secure file sharing between apps. A
FileProvider can only share files in predefined directories, so let's define these.

1. Create a new XML file that will contain the paths, e.g. res/xml/filepaths.xml

2. Add the paths

<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="pdf_folder" path="documents/"/>
</paths>

Define a FileProvider and link it with the file


paths
This is done in the manifest:

<manifest>
...
<application>
...
<provider
android:name="android.support.v4.context.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
...
</application>

https://riptutorial.com/ 475
...
</manifest>

Generate the URI for the file


To share the file we must provide an identifier for the file. This is done by using a URI (Uniform
Resource Identifier).

// We assume the file we want to load is in the documents/ subdirectory


// of the internal storage
File documentsPath = new File(Context.getFilesDir(), "documents");
File file = new File(documentsPath, "sample.pdf");
// This can also in one line of course:
// File file = new File(Context.getFilesDir(), "documents/sample.pdf");

Uri uri = FileProvider.getUriForFile(getContext(), "com.mydomain.fileprovider", file);

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.

Share the file with other apps


We use ShareCompat to share the file with other apps:

Intent intent = ShareCompat.IntentBuilder.from(getContext())


.setType("application/pdf")
.setStream(uri)
.setChooserTitle("Choose bar")
.createChooserIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Context.startActivity(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.

Read FileProvider online: https://riptutorial.com/android/topic/6266/fileprovider

https://riptutorial.com/ 476
Chapter 99: Fingerprint API in android
Remarks
see also

Github sample project

Android developer blogspot

Android Developer site

Examples
Adding the Fingerprint Scanner in Android application

Android supports fingerprint api from Android 6.0 (Marshmallow) SDK 23

To use this feature in your app, first add the USE_FINGERPRINT permission in your
manifest.

<uses-permission
android:name="android.permission.USE_FINGERPRINT" />

Here the procedure to follow

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.

KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
keyPairGenerator.initialize(
new KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.setUserAuthenticationRequired(true)
.build());
keyPairGenerator.generateKeyPair();

By setting KeyGenParameterSpec.Builder.setUserAuthenticationRequired to true, you


can permit the use of the key only after the user authenticate it including when
authenticated with the user's fingerprint.

KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");


keyStore.load(null);
PublicKey publicKey =
keyStore.getCertificate(MainActivity.KEY_NAME).getPublicKey();

https://riptutorial.com/ 477
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
PrivateKey key = (PrivateKey) keyStore.getKey(KEY_NAME, null);

Then start listening to a fingerprint on the fingerprint sensor by calling


FingerprintManager.authenticate with a Cipher initialized with the symmetric key
created. Or alternatively you can fall back to server-side verified password as an
authenticator.

Create and initialise the FingerprintManger from fingerprintManger.class

getContext().getSystemService(FingerprintManager.class)

To authenticate use FingerprintManger api and create subclass using

FingerprintManager.AuthenticationCallback and override the methods

onAuthenticationError
onAuthenticationHelp
onAuthenticationSucceeded
onAuthenticationFailed

To Start

To startListening the fingerPrint event call authenticate method with crypto

fingerprintManager
.authenticate(cryptoObject, mCancellationSignal, 0 , this, null);

Cancel

to stop listenting the scanner call

android.os.CancellationSignal;

Once the fingerprint (or password) is verified, the


FingerprintManager.AuthenticationCallback#onAuthenticationSucceeded() callback is
called.

@Override

public void onAuthenticationSucceeded(AuthenticationResult result) {

How to use Android Fingerprint API to save user passwords

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

https://riptutorial.com/ 478
and decrypted in the following manner:

Encryption:

1. User gives helper the desired non-encrypted password.


2. User is required to provide fingerprint.
3. Once authenticated, the helper obtains a key from the KeyStore and encrypts the password
using a Cipher.
4. Password and IV salt (IV is recreated for every encryption and is not reused) are saved to
shared preferences to be used later in the decryption process.

Decryption:

1. User requests to decrypt the password.


2. User is required to provide fingerprint.
3. The helper builds a Cipher using the IV and once user is authenticated, the KeyStore obtains
a key from the KeyStore and deciphers the password.

public class FingerPrintAuthHelper {

private static final String FINGER_PRINT_HELPER = "FingerPrintAuthHelper";


private static final String ENCRYPTED_PASS_SHARED_PREF_KEY =
"ENCRYPTED_PASS_SHARED_PREF_KEY";
private static final String LAST_USED_IV_SHARED_PREF_KEY = "LAST_USED_IV_SHARED_PREF_KEY";
private static final String MY_APP_ALIAS = "MY_APP_ALIAS";

private KeyguardManager keyguardManager;


private FingerprintManager fingerprintManager;

private final Context context;


private KeyStore keyStore;
private KeyGenerator keyGenerator;

private String lastError;

public interface Callback {


void onSuccess(String savedPass);

void onFailure(String message);

void onHelp(int helpCode, String helpString);


}

public FingerPrintAuthHelper(Context context) {


this.context = context;
}

public String getLastError() {


return lastError;
}

@TargetApi(Build.VERSION_CODES.M)
public boolean init() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
setError("This Android version does not support fingerprint authentication");
return false;

https://riptutorial.com/ 479
}

keyguardManager = (KeyguardManager) context.getSystemService(KEYGUARD_SERVICE);


fingerprintManager = (FingerprintManager)
context.getSystemService(FINGERPRINT_SERVICE);

if (!keyguardManager.isKeyguardSecure()) {
setError("User hasn't enabled Lock Screen");
return false;
}

if (!hasPermission()) {
setError("User hasn't granted permission to use Fingerprint");
return false;
}

if (!fingerprintManager.hasEnrolledFingerprints()) {
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 = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" +
KeyProperties.BLOCK_MODE_CBC + "/" +
KeyProperties.ENCRYPTION_PADDING_PKCS7);

Key key = keyStore.getKey(MY_APP_ALIAS, null);


if (key == null) {
return null;
}
if(mode == Cipher.ENCRYPT_MODE) {
cipher.init(mode, key);
byte[] iv = cipher.getIV();
saveIv(iv);
} else {
byte[] lastIv = getLastIv();
cipher.init(mode, key, new IvParameterSpec(lastIv));
}
return cipher;
}

@NonNull
@RequiresApi(api = Build.VERSION_CODES.M)
private KeyGenParameterSpec createKeyGenParameterSpec() {
return new KeyGenParameterSpec.Builder(MY_APP_ALIAS, KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build();
}

https://riptutorial.com/ 480
@RequiresApi(api = Build.VERSION_CODES.M)
private boolean initKeyStore() {
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore");
keyStore.load(null);
if (getLastIv() == null) {
KeyGenParameterSpec keyGeneratorSpec = createKeyGenParameterSpec();
keyGenerator.init(keyGeneratorSpec);
keyGenerator.generateKey();
}
} catch (Throwable t) {
setError("Failed init of keyStore & keyGenerator: " + t.getMessage());
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);
FingerprintManager.CryptoObject crypto = new
FingerprintManager.CryptoObject(cipher);
fingerprintManager.authenticate(crypto, cancellationSignal, 0, authListener,
null);
} else {
authListener.getCallback().onFailure("User hasn't granted permission to use
Fingerprint");
}
} catch (Throwable t) {
authListener.getCallback().onFailure("An error occurred: " + t.getMessage());
}
}

private String getSavedEncryptedPassword() {


SharedPreferences sharedPreferences = getSharedPreferences();
if (sharedPreferences != null) {
return sharedPreferences.getString(ENCRYPTED_PASS_SHARED_PREF_KEY, null);
}
return null;
}

private void saveEncryptedPassword(String encryptedPassword) {


SharedPreferences.Editor edit = getSharedPreferences().edit();
edit.putString(ENCRYPTED_PASS_SHARED_PREF_KEY, encryptedPassword);
edit.commit();
}

private byte[] getLastIv() {


SharedPreferences sharedPreferences = getSharedPreferences();
if (sharedPreferences != null) {
String ivString = sharedPreferences.getString(LAST_USED_IV_SHARED_PREF_KEY, null);

if (ivString != null) {
return decodeBytes(ivString);
}

https://riptutorial.com/ 481
}
return null;
}

private void saveIv(byte[] iv) {


SharedPreferences.Editor edit = getSharedPreferences().edit();
String string = encodeBytes(iv);
edit.putString(LAST_USED_IV_SHARED_PREF_KEY, string);
edit.commit();
}

private SharedPreferences getSharedPreferences() {


return context.getSharedPreferences(FINGER_PRINT_HELPER, 0);
}

@RequiresApi(api = Build.VERSION_CODES.M)
private boolean hasPermission() {
return ActivityCompat.checkSelfPermission(context,
Manifest.permission.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(password.isEmpty()) {
setError("Password is empty");
return false;
}

if (cipher == null) {
setError("Could not create cipher");
return false;
}

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();


CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream,
cipher);
byte[] bytes = password.getBytes(Charset.defaultCharset());
cipherOutputStream.write(bytes);
cipherOutputStream.flush();
cipherOutputStream.close();
saveEncryptedPassword(encodeBytes(outputStream.toByteArray()));
} catch (Throwable t) {
setError("Encryption failed " + t.getMessage());
return false;
}

https://riptutorial.com/ 482
return true;
}

private byte[] decodeBytes(String s) {


final int len = s.length();

// "111" is not a valid hex encoding.


if( len%2 != 0 )
throw new IllegalArgumentException("hexBinary needs to be even-length: "+s);

byte[] out = new byte[len/2];

for( int i=0; i<len; i+=2 ) {


int h = hexToBin(s.charAt(i ));
int l = hexToBin(s.charAt(i+1));
if( h==-1 || l==-1 )
throw new IllegalArgumentException("contains illegal character for hexBinary:
"+s);

out[i/2] = (byte)(h*16+l);
}

return out;
}

private static int hexToBin( char ch ) {


if( '0'<=ch && ch<='9' ) return ch-'0';
if( 'A'<=ch && ch<='F' ) return ch-'A'+10;
if( 'a'<=ch && ch<='f' ) return ch-'a'+10;
return -1;
}

private static final char[] hexCode = "0123456789ABCDEF".toCharArray();

public String encodeBytes(byte[] data) {


StringBuilder r = new StringBuilder(data.length*2);
for ( byte b : data) {
r.append(hexCode[(b >> 4) & 0xF]);
r.append(hexCode[(b & 0xF)]);
}
return r.toString();
}

@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);

ArrayList<Byte> values = new ArrayList<>();


int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte) nextByte);
}
cipherInputStream.close();

byte[] bytes = new byte[values.size()];

https://riptutorial.com/ 483
for (int i = 0; i < values.size(); i++) {
bytes[i] = values.get(i).byteValue();
}

retVal = new String(bytes, Charset.defaultCharset());


}
return retVal;
}

private void setError(String error) {


lastError = error;
Log.w(FINGER_PRINT_HELPER, lastError);
}

@RequiresApi(Build.VERSION_CODES.M)
protected class FingerPrintAuthenticationListener extends
FingerprintManager.AuthenticationCallback {

protected final Callback callback;

public FingerPrintAuthenticationListener(@NonNull Callback callback) {


this.callback = callback;
}

public void onAuthenticationError(int errorCode, CharSequence errString) {


callback.onFailure("Authentication error [" + errorCode + "] " + errString);
}

/**
* 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) {
callback.onHelp(helpCode, helpString.toString());
}

/**
* Called when a fingerprint is recognized.
* @param result An object containing authentication-related data
*/
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result)
{
}

/**
* Called when a fingerprint is valid but not recognized.
*/
public void onAuthenticationFailed() {
callback.onFailure("Authentication failed");
}

public @NonNull
Callback getCallback() {
return callback;
}

https://riptutorial.com/ 484
@RequiresApi(api = Build.VERSION_CODES.M)
private class FingerPrintEncryptPasswordListener extends FingerPrintAuthenticationListener
{

private final String password;

public FingerPrintEncryptPasswordListener(Callback callback, String password) {


super(callback);
this.password = password;
}

public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result)


{
Cipher cipher = result.getCryptoObject().getCipher();
try {
if (encryptPassword(cipher, password)) {
callback.onSuccess("Encrypted");
} else {
callback.onFailure("Encryption failed");
}

} catch (Exception e) {
callback.onFailure("Encryption failed " + e.getMessage());
}
}
}

@RequiresApi(Build.VERSION_CODES.M)
protected class FingerPrintDecryptPasswordListener extends
FingerPrintAuthenticationListener {

public FingerPrintDecryptPasswordListener(@NonNull Callback callback) {


super(callback);
}

public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result)


{
Cipher cipher = result.getCryptoObject().getCipher();
try {
String savedPass = decipher(cipher);
if (savedPass != null) {
callback.onSuccess(savedPass);
} else {
callback.onFailure("Failed deciphering");
}

} catch (Exception e) {
callback.onFailure("Deciphering failed " + e.getMessage());
}
}
}
}

This activity below is a very basic example of how to get a user saved password and interact with
the helper.

public class MainActivity extends AppCompatActivity {

private TextView passwordTextView;

https://riptutorial.com/ 485
private FingerPrintAuthHelper fingerPrintAuthHelper;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
passwordTextView = (TextView) findViewById(R.id.password);
errorTextView = (TextView) findViewById(R.id.error);

View savePasswordButton = findViewById(R.id.set_password_button);


savePasswordButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
fingerPrintAuthHelper.savePassword(passwordTextView.getText().toString(),
new CancellationSignal(), getAuthListener(false));
}
}
});

View getPasswordButton = findViewById(R.id.get_password_button);


getPasswordButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
fingerPrintAuthHelper.getPassword(new CancellationSignal(),
getAuthListener(true));
}
}
});
}

// Start the finger print helper. In case this fails show error to user
private void startFingerPrintAuthHelper() {
fingerPrintAuthHelper = new FingerPrintAuthHelper(this);
if (!fingerPrintAuthHelper.init()) {
errorTextView.setText(fingerPrintAuthHelper.getLastError());
}
}

@NonNull
private FingerPrintAuthHelper.Callback getAuthListener(final boolean isGetPass) {
return new FingerPrintAuthHelper.Callback() {
@Override
public void onSuccess(String result) {
if (isGetPass) {
errorTextView.setText("Success!!! Pass = " + result);
} else {
errorTextView.setText("Encrypted pass = " + result);
}
}

@Override
public void onFailure(String message) {
errorTextView.setText("Failed - " + message);
}

@Override
public void onHelp(int helpCode, String helpString) {
errorTextView.setText("Help needed - " + helpString);
}
};

https://riptutorial.com/ 486
}
}

Read Fingerprint API in android online: https://riptutorial.com/android/topic/7523/fingerprint-api-in-


android

https://riptutorial.com/ 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

Firebase - Extended documentation:


There is another tag where you can find more topics and examples about the use of Firebase.

Other related topics:


• Firebase Realtime DataBase
• Firebase App Indexing
• Firebase Crash Reporting
• Firebase Cloud Messaging

Examples
Create a Firebase user

public class SignUpActivity extends BaseAppCompatActivity {

@BindView(R.id.tIETSignUpEmail)
EditText mEditEmail;
@BindView(R.id.tIETSignUpPassword)
EditText mEditPassword;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}

@OnClick(R.id.btnSignUpSignUp)
void signUp() {

FormValidationUtils.clearErrors(mEditEmail, mEditPassword);

if (FormValidationUtils.isBlank(mEditEmail)) {

https://riptutorial.com/ 488
mEditEmail.setError("Please enter email");
return;
}

if (!FormValidationUtils.isEmailValid(mEditEmail)) {
mEditEmail.setError("Please enter valid email");
return;
}

if (TextUtils.isEmpty(mEditPassword.getText())) {
mEditPassword.setError("Please enter password");
return;
}

createUserWithEmailAndPassword(mEditEmail.getText().toString(),
mEditPassword.getText().toString());
}

private void createUserWithEmailAndPassword(String email, String password) {


DialogUtils.showProgressDialog(this, "", getString(R.string.str_creating_account),
false);
mFirebaseAuth
.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
Toast.makeText(SignUpActivity.this,
task.getException().getMessage(),
Toast.LENGTH_SHORT).show();
DialogUtils.dismissProgressDialog();
} else {
Toast.makeText(SignUpActivity.this,
R.string.str_registration_successful, Toast.LENGTH_SHORT).show();
DialogUtils.dismissProgressDialog();
startActivity(new Intent(SignUpActivity.this,
HomeActivity.class));
}
}
});
}

@Override
protected int getLayoutResourceId() {
return R.layout.activity_sign_up;
}
}

Sign In Firebase user with email and password

public class LoginActivity extends BaseAppCompatActivity {

@BindView(R.id.tIETLoginEmail)
EditText mEditEmail;
@BindView(R.id.tIETLoginPassword)
EditText mEditPassword;

@Override
protected void onResume() {

https://riptutorial.com/ 489
super.onResume();
FirebaseUser firebaseUser = mFirebaseAuth.getCurrentUser();
if (firebaseUser != null)
startActivity(new Intent(this, HomeActivity.class));
}

@Override
protected int getLayoutResourceId() {
return R.layout.activity_login;
}

@OnClick(R.id.btnLoginLogin)
void onSignInClick() {

FormValidationUtils.clearErrors(mEditEmail, mEditPassword);

if (FormValidationUtils.isBlank(mEditEmail)) {
FormValidationUtils.setError(null, mEditEmail, "Please enter email");
return;
}

if (!FormValidationUtils.isEmailValid(mEditEmail)) {
FormValidationUtils.setError(null, mEditEmail, "Please enter valid email");
return;
}

if (TextUtils.isEmpty(mEditPassword.getText())) {
FormValidationUtils.setError(null, mEditPassword, "Please enter password");
return;
}

signInWithEmailAndPassword(mEditEmail.getText().toString(),
mEditPassword.getText().toString());
}

private void signInWithEmailAndPassword(String email, String password) {


DialogUtils.showProgressDialog(this, "", getString(R.string.sign_in), false);
mFirebaseAuth
.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {

DialogUtils.dismissProgressDialog();

if (task.isSuccessful()) {
Toast.makeText(LoginActivity.this, "Login Successful",
Toast.LENGTH_SHORT).show();
startActivity(new Intent(LoginActivity.this, HomeActivity.class));
finish();
} else {
Toast.makeText(LoginActivity.this,
task.getException().getMessage(),
Toast.LENGTH_SHORT).show();
}
}
});
}

@OnClick(R.id.btnLoginSignUp)
void onSignUpClick() {

https://riptutorial.com/ 490
startActivity(new Intent(this, SignUpActivity.class));
}

@OnClick(R.id.btnLoginForgotPassword)
void forgotPassword() {
startActivity(new Intent(this, ForgotPasswordActivity.class));
}
}

Send Firebase password reset email

public class ForgotPasswordActivity extends AppCompatActivity {

@BindView(R.id.tIETForgotPasswordEmail)
EditText mEditEmail;
private FirebaseAuth mFirebaseAuth;
private FirebaseAuth.AuthStateListener mAuthStateListener;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_forgot_password);
ButterKnife.bind(this);

mFirebaseAuth = FirebaseAuth.getInstance();

mAuthStateListener = new FirebaseAuth.AuthStateListener() {


@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
if (firebaseUser != null) {
// Do whatever you want with the UserId by firebaseUser.getUid()
} else {

}
}
};
}

@Override
protected void onStart() {
super.onStart();
mFirebaseAuth.addAuthStateListener(mAuthStateListener);
}

@Override
protected void onStop() {
super.onStop();
if (mAuthStateListener != null) {
mFirebaseAuth.removeAuthStateListener(mAuthStateListener);
}
}

@OnClick(R.id.btnForgotPasswordSubmit)
void onSubmitClick() {

if (FormValidationUtils.isBlank(mEditEmail)) {
FormValidationUtils.setError(null, mEditEmail, "Please enter email");

https://riptutorial.com/ 491
return;
}

if (!FormValidationUtils.isEmailValid(mEditEmail)) {
FormValidationUtils.setError(null, mEditEmail, "Please enter valid email");
return;
}

DialogUtils.showProgressDialog(this, "", "Please wait...", false);


mFirebaseAuth.sendPasswordResetEmail(mEditEmail.getText().toString())
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
DialogUtils.dismissProgressDialog();
if (task.isSuccessful()) {
Toast.makeText(ForgotPasswordActivity.this, "An email has been
sent to you.", Toast.LENGTH_SHORT).show();
finish();
} else {
Toast.makeText(ForgotPasswordActivity.this,
task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
}
}

Updating a Firebase users's email

public class ChangeEmailActivity extends BaseAppCompatActivity implements


ReAuthenticateDialogFragment.OnReauthenticateSuccessListener {

@BindView(R.id.et_change_email)
EditText mEditText;
private FirebaseUser mFirebaseUser;

@OnClick(R.id.btn_change_email)
void onChangeEmailClick() {

FormValidationUtils.clearErrors(mEditText);

if (FormValidationUtils.isBlank(mEditText)) {
FormValidationUtils.setError(null, mEditText, "Please enter email");
return;
}

if (!FormValidationUtils.isEmailValid(mEditText)) {
FormValidationUtils.setError(null, mEditText, "Please enter valid email");
return;
}

changeEmail(mEditText.getText().toString());
}

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mFirebaseUser = mFirebaseAuth.getCurrentUser();

https://riptutorial.com/ 492
}

private void changeEmail(String email) {


DialogUtils.showProgressDialog(this, "Changing Email", "Please wait...", false);
mFirebaseUser.updateEmail(email)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
DialogUtils.dismissProgressDialog();
if (task.isSuccessful()) {
showToast("Email updated successfully.");
return;
}

if (task.getException() instanceof
FirebaseAuthRecentLoginRequiredException) {
FragmentManager fm = getSupportFragmentManager();
ReAuthenticateDialogFragment reAuthenticateDialogFragment = new
ReAuthenticateDialogFragment();
reAuthenticateDialogFragment.show(fm,
reAuthenticateDialogFragment.getClass().getSimpleName());
}
}
});
}

@Override
protected int getLayoutResourceId() {
return R.layout.activity_change_email;
}

@Override
public void onReauthenticateSuccess() {
changeEmail(mEditText.getText().toString());
}
}

Change Password

public class ChangePasswordActivity extends BaseAppCompatActivity implements


ReAuthenticateDialogFragment.OnReauthenticateSuccessListener {
@BindView(R.id.et_change_password)
EditText mEditText;
private FirebaseUser mFirebaseUser;

@OnClick(R.id.btn_change_password)
void onChangePasswordClick() {

FormValidationUtils.clearErrors(mEditText);

if (FormValidationUtils.isBlank(mEditText)) {
FormValidationUtils.setError(null, mEditText, "Please enter password");
return;
}

changePassword(mEditText.getText().toString());
}

private void changePassword(String password) {

https://riptutorial.com/ 493
DialogUtils.showProgressDialog(this, "Changing Password", "Please wait...", false);
mFirebaseUser.updatePassword(password)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
DialogUtils.dismissProgressDialog();
if (task.isSuccessful()) {
showToast("Password updated successfully.");
return;
}

if (task.getException() instanceof
FirebaseAuthRecentLoginRequiredException) {
FragmentManager fm = getSupportFragmentManager();
ReAuthenticateDialogFragment reAuthenticateDialogFragment = new
ReAuthenticateDialogFragment();
reAuthenticateDialogFragment.show(fm,
reAuthenticateDialogFragment.getClass().getSimpleName());
}
}
});
}

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mFirebaseUser = mFirebaseAuth.getCurrentUser();
}

@Override
protected int getLayoutResourceId() {
return R.layout.activity_change_password;
}

@Override
public void onReauthenticateSuccess() {
changePassword(mEditText.getText().toString());
}
}

Re-Authenticate Firebase user

public class ReAuthenticateDialogFragment extends DialogFragment {

@BindView(R.id.et_dialog_reauthenticate_email)
EditText mEditTextEmail;
@BindView(R.id.et_dialog_reauthenticate_password)
EditText mEditTextPassword;
private OnReauthenticateSuccessListener mOnReauthenticateSuccessListener;

@OnClick(R.id.btn_dialog_reauthenticate)
void onReauthenticateClick() {

FormValidationUtils.clearErrors(mEditTextEmail, mEditTextPassword);

if (FormValidationUtils.isBlank(mEditTextEmail)) {
FormValidationUtils.setError(null, mEditTextEmail, "Please enter email");
return;

https://riptutorial.com/ 494
}

if (!FormValidationUtils.isEmailValid(mEditTextEmail)) {
FormValidationUtils.setError(null, mEditTextEmail, "Please enter valid email");
return;
}

if (TextUtils.isEmpty(mEditTextPassword.getText())) {
FormValidationUtils.setError(null, mEditTextPassword, "Please enter password");
return;
}

reauthenticateUser(mEditTextEmail.getText().toString(),
mEditTextPassword.getText().toString());
}

private void reauthenticateUser(String email, String password) {


DialogUtils.showProgressDialog(getActivity(), "Re-Authenticating", "Please wait...",
false);
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
AuthCredential authCredential = EmailAuthProvider.getCredential(email, password);
firebaseUser.reauthenticate(authCredential)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
DialogUtils.dismissProgressDialog();
if (task.isSuccessful()) {
mOnReauthenticateSuccessListener.onReauthenticateSuccess();
dismiss();
} else {
((BaseAppCompatActivity)
getActivity()).showToast(task.getException().getMessage());
}
}
});
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
mOnReauthenticateSuccessListener = (OnReauthenticateSuccessListener) context;
}

@OnClick(R.id.btn_dialog_reauthenticate_cancel)
void onCancelClick() {
dismiss();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_reauthenticate, container);
ButterKnife.bind(this, view);
return view;
}

@Override
public void onResume() {
super.onResume();
Window window = getDialog().getWindow();
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,

https://riptutorial.com/ 495
WindowManager.LayoutParams.WRAP_CONTENT);
}

interface OnReauthenticateSuccessListener {
void onReauthenticateSuccess();
}
}

Firebase Storage Operations

With this example, you will be able to perform following operations:

1. Connect to Firebase Storage


2. Create a directory named “images”
3. Upload a file in images directory
4. Download a file from images directory
5. Delete a file from images directory

public class MainActivity extends AppCompatActivity {

private static final int REQUEST_CODE_PICK_IMAGE = 1;


private static final int PERMISSION_READ_WRITE_EXTERNAL_STORAGE = 2;

private FirebaseStorage mFirebaseStorage;


private StorageReference mStorageReference;
private StorageReference mStorageReferenceImages;
private Uri mUri;
private ImageView mImageView;
private ProgressDialog mProgressDialog;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);


mImageView = (ImageView) findViewById(R.id.imageView);
setSupportActionBar(toolbar);

// Create an instance of Firebase Storage


mFirebaseStorage = FirebaseStorage.getInstance();
}

private void pickImage() {


Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_CODE_PICK_IMAGE) {
String filePath = FileUtil.getPath(this, data.getData());
mUri = Uri.fromFile(new File(filePath));

https://riptutorial.com/ 496
uploadFile(mUri);
}
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_READ_WRITE_EXTERNAL_STORAGE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
pickImage();
}
}
}

private void showProgressDialog(String title, String message) {


if (mProgressDialog != null && mProgressDialog.isShowing())
mProgressDialog.setMessage(message);
else
mProgressDialog = ProgressDialog.show(this, title, message, true, false);
}

private void hideProgressDialog() {


if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
}

private void showToast(String message) {


Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}

public void showHorizontalProgressDialog(String title, String body) {

if (mProgressDialog != null && mProgressDialog.isShowing()) {


mProgressDialog.setTitle(title);
mProgressDialog.setMessage(body);
} else {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setTitle(title);
mProgressDialog.setMessage(body);
mProgressDialog.setIndeterminate(false);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setProgress(0);
mProgressDialog.setMax(100);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
}
}

public void updateProgress(int progress) {


if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.setProgress(progress);
}
}

/**
* Step 1: Create a Storage
*
* @param view

https://riptutorial.com/ 497
*/
public void onCreateReferenceClick(View view) {
mStorageReference =
mFirebaseStorage.getReferenceFromUrl("gs://**something**.appspot.com");
showToast("Reference Created Successfully.");
findViewById(R.id.button_step_2).setEnabled(true);
}

/**
* Step 2: Create a directory named "Images"
*
* @param view
*/
public void onCreateDirectoryClick(View view) {
mStorageReferenceImages = mStorageReference.child("images");
showToast("Directory 'images' created Successfully.");
findViewById(R.id.button_step_3).setEnabled(true);
}

/**
* Step 3: Upload an Image File and display it on ImageView
*
* @param view
*/
public void onUploadFileClick(View view) {
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(MainActivity.this, new
String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.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);
}

private void showAlertDialog(Context ctx, String title, String body,


DialogInterface.OnClickListener okListener) {

if (okListener == null) {
okListener = new DialogInterface.OnClickListener() {

https://riptutorial.com/ 498
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
};
}

AlertDialog.Builder builder = new


AlertDialog.Builder(ctx).setMessage(body).setPositiveButton("OK",
okListener).setCancelable(false);

if (!TextUtils.isEmpty(title)) {
builder.setTitle(title);
}

builder.show();
}

private void uploadFile(Uri uri) {


mImageView.setImageResource(R.drawable.placeholder_image);

StorageReference uploadStorageReference =
mStorageReferenceImages.child(uri.getLastPathSegment());
final UploadTask uploadTask = uploadStorageReference.putFile(uri);
showHorizontalProgressDialog("Uploading", "Please wait...");
uploadTask
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
hideProgressDialog();
Uri downloadUrl = taskSnapshot.getDownloadUrl();
Log.d("MainActivity", downloadUrl.toString());
showAlertDialog(MainActivity.this, "Upload Complete",
downloadUrl.toString(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
findViewById(R.id.button_step_3).setEnabled(false);
findViewById(R.id.button_step_4).setEnabled(true);
}
});

Glide.with(MainActivity.this)
.load(downloadUrl)
.into(mImageView);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
exception.printStackTrace();
// Handle unsuccessful uploads
hideProgressDialog();
}
})
.addOnProgressListener(MainActivity.this, new
OnProgressListener<UploadTask.TaskSnapshot>() {
@Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
int progress = (int) (100 * (float) taskSnapshot.getBytesTransferred()
/ taskSnapshot.getTotalByteCount());
Log.i("Progress", progress + "");
updateProgress(progress);

https://riptutorial.com/ 499
}
});
}

private void downloadFile(Uri uri) {


mImageView.setImageResource(R.drawable.placeholder_image);
final StorageReference storageReferenceImage =
mStorageReferenceImages.child(uri.getLastPathSegment());
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "Firebase Storage");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MainActivity", "failed to create Firebase Storage directory");
}
}

final File localFile = new File(mediaStorageDir, uri.getLastPathSegment());


try {
localFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}

showHorizontalProgressDialog("Downloading", "Please wait...");


storageReferenceImage.getFile(localFile).addOnSuccessListener(new
OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
@Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
hideProgressDialog();
showAlertDialog(MainActivity.this, "Download Complete",
localFile.getAbsolutePath(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
findViewById(R.id.button_step_4).setEnabled(false);
findViewById(R.id.button_step_5).setEnabled(true);
}
});

Glide.with(MainActivity.this)
.load(localFile)
.into(mImageView);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
// Handle any errors
hideProgressDialog();
exception.printStackTrace();
}
}).addOnProgressListener(new OnProgressListener<FileDownloadTask.TaskSnapshot>() {
@Override
public void onProgress(FileDownloadTask.TaskSnapshot taskSnapshot) {
int progress = (int) (100 * (float) taskSnapshot.getBytesTransferred() /
taskSnapshot.getTotalByteCount());
Log.i("Progress", progress + "");
updateProgress(progress);
}
});
}

private void deleteFile(Uri uri) {

https://riptutorial.com/ 500
showProgressDialog("Deleting", "Please wait...");
StorageReference storageReferenceImage =
mStorageReferenceImages.child(uri.getLastPathSegment());
storageReferenceImage.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
hideProgressDialog();
showAlertDialog(MainActivity.this, "Success", "File deleted successfully.",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
mImageView.setImageResource(R.drawable.placeholder_image);
findViewById(R.id.button_step_3).setEnabled(true);
findViewById(R.id.button_step_4).setEnabled(false);
findViewById(R.id.button_step_5).setEnabled(false);
}
});
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "Firebase Storage");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MainActivity", "failed to create Firebase Storage directory");
}
}
deleteFiles(mediaStorageDir);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
hideProgressDialog();
exception.printStackTrace();
}
});
}

private void deleteFiles(File directory) {


if (directory.isDirectory())
for (File child : directory.listFiles())
child.delete();
}
}

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 firebase.storage {
match /b/**something**.appspot.com/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}

But I changed to skip the authentication:

service firebase.storage {
match /b/**something**.appspot.com/o {

https://riptutorial.com/ 501
match /{allPaths=**} {
allow read, write;
}
}
}

Firebase Cloud Messaging

First of all you need to setup your project adding Firebase to your Android project following the
steps described in this topic.

Set up Firebase and the FCM SDK


Add the FCM dependency to your app-level build.gradle file

dependencies {
compile 'com.google.firebase:firebase-messaging:11.0.4'
}

And at the very bottom (this is important) add:

// ADD THIS AT THE BOTTOM


apply plugin: 'com.google.gms.google-services'

Edit your app manifest


Add the following to your app's manifest:

• A service that extends FirebaseMessagingService. This is required if you want to do any


message handling beyond receiving notifications on apps in the background.

• A service that extends FirebaseInstanceIdService to handle the creation, rotation, and


updating of registration tokens.

For example:

<service
android:name=".MyInstanceIdListenerService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<service
android:name=".MyFcmListenerService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>

https://riptutorial.com/ 502
Here are simple implementations of the 2 services.

To retrieve the current registration token extend the FirebaseInstanceIdService class and override
the onTokenRefresh() method:

public class MyInstanceIdListenerService extends FirebaseInstanceIdService {

// 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 = FirebaseInstanceId.getInstance().getToken();

// Send this token to your server or store it locally


}
}

To receive messages, use a service that extends FirebaseMessagingService and override the
onMessageReceived method.

public class MyFcmListenerService extends FirebaseMessagingService {

/**
* Called when message is received.
*
* @param remoteMessage Object representing the message received from Firebase Cloud
Messaging.
*/
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
String from = remoteMessage.getFrom();

// Check if message contains a data payload.


if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
Map<String, String> data = remoteMessage.getData();
}

// Check if message contains a notification payload.


if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " +
remoteMessage.getNotification().getBody());
}

// 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

FirebaseMessaging.getInstance().subscribeToTopic("Free");

then in fireBase console, send notification by topic name

https://riptutorial.com/ 503
More info in the dedicated topic Firebase Cloud Messaging.

Add Firebase to Your Android Project

Here are simplified steps (based on the official documentation) required to create a Firebase
project and connect it with an Android app.

Add Firebase to your app


1. Create a Firebase project in the Firebase console and click Create New Project.

2. Click Add Firebase to your Android app and follow the setup steps.

3. When prompted, enter your app's package name.


It's important to enter the fully qualified package name your app is using; this can only be set
when you add an app to your Firebase project.

4. At the end, you'll download a google-services.json file. You can download this file again at
any time.

5. If you haven't done so already, copy the google-services.json 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.

Add the SDK


To integrate the Firebase libraries into one of your own projects, you need to perform a few basic
tasks to prepare your Android Studio project. You may have already done this as part of adding
Firebase to your app.

1. Add rules to your root-level build.gradle file, to include the google-services plugin:

buildscript {
// ...
dependencies {
// ...
classpath 'com.google.gms:google-services:3.1.0'
}
}

Then, in your module Gradle file (usually the app/build.gradle), add the apply plugin line at the
bottom of the file to enable the Gradle plugin:

apply plugin: 'com.android.application'

android {
// ...

https://riptutorial.com/ 504
}

dependencies {
// ...
compile 'com.google.firebase:firebase-core:11.0.4'
}

// ADD THIS AT THE BOTTOM


apply plugin: 'com.google.gms.google-services'

The final step is to add the dependencies for the Firebase SDK using one or more libraries
available for the different Firebase features.

Gradle Dependency Line Service

com.google.firebase:firebase-core:11.0.4 Analytics

com.google.firebase:firebase-database:11.0.4 Realtime Database

com.google.firebase:firebase-storage:11.0.4 Storage

com.google.firebase:firebase-crash:11.0.4 Crash Reporting

com.google.firebase:firebase-auth:11.0.4 Authentication

com.google.firebase:firebase-messaging:11.0.4 Cloud Messaging / Notifications

com.google.firebase:firebase-config:11.0.4 Remote Config

com.google.firebase:firebase-invites:11.0.4 Invites / Dynamic Links

com.google.firebase:firebase-ads:11.0.4 AdMob

com.google.android.gms:play-services-appindexing:11.0.4 App Indexing

Firebase Realtime Database: how to set/get data

Note: Let's setup some anonymous authentication for the example

{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}

Once it is done, create a child by editing your database address. For example:

https://your-project.firebaseio.com/ to https://your-project.firebaseio.com/chat

We will put data to this location from our Android device. You don't have to create the database

https://riptutorial.com/ 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:

public class ChatMessage {


private String username;
private String message;

public ChatMessage(String username, String message) {


this.username = username;
this.message = message;
}

public ChatMessage() {} // you MUST have an empty constructor

public String getUsername() {


return username;
}

public String getMessage() {


return message;
}
}

Then in your activity:

if (FirebaseAuth.getInstance().getCurrentUser() == null) {
FirebaseAuth.getInstance().signInAnonymously().addOnCompleteListener(new
OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isComplete() && task.isSuccessful()){
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference reference = database.getReference("chat"); // reference
is 'chat' because we created the database at /chat
}
}
});
}

To send a value:

ChatMessage msg = new ChatMessage("user1", "Hello World!");


reference.push().setValue(msg);

To receive changes that occurs in the database:

reference.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
ChatMessage msg = dataSnapshot.getValue(ChatMessage.class);
Log.d(TAG, msg.getUsername()+" "+msg.getMessage());
}

public void onChildChanged(DataSnapshot dataSnapshot, String s) {}

https://riptutorial.com/ 506
public void onChildRemoved(DataSnapshot dataSnapshot) {}
public void onChildMoved(DataSnapshot dataSnapshot, String s) {}
public void onCancelled(DatabaseError databaseError) {}
});

Demo of FCM based notifications

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.

Steps to integrate FCM are as follows.

1. Create sample hello world project in Android Studio Your Android studio screen would look
like the following picture.

https://riptutorial.com/ 507
https://riptutorial.com/ 508
2. Next step is to set up firebase project. Visit https://console.firebase.google.com 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.

https://riptutorial.com/ 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.

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -

https://riptutorial.com/ 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-
services.json".

4. Now copy the google-services.json file you have just downloaded into your Android app
module root directory.

https://riptutorial.com/ 511
https://riptutorial.com/ 512
5. Follow the instructions given on the firebase console as you proceed ahead. a. Add following
code line to your project level build.gradle

dependencies{ classpath 'com.google.gms:google-services:3.1.0' .....

b. Add following code line at the end of your app level build.gradle.

//following are the dependencies to be added


compile 'com.google.firebase:firebase-messaging:11.0.4'
compile 'com.android.support:multidex:1.0.1'
}
// this line goes to the end of the file
apply plugin: 'com.google.gms.google-services'

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="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>

b. One extending FirebaseInstanceIDService.

<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>

7. FirebaseMessagingService code should look like this.

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

import com.google.firebase.messaging.FirebaseMessagingService;

public class MyFirebaseMessagingService extends FirebaseMessagingService {


public MyFirebaseMessagingService() {
}
}

8. FirebaseInstanceIdService should look like this.

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

import com.google.firebase.iid.FirebaseInstanceIdService;

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {


public MyFirebaseInstanceIDService() {
}
}

https://riptutorial.com/ 513
9. Now it is time to capture the device registration token. Add following line of code to
MainActivity's onCreate method.

String token = FirebaseInstanceId.getInstance().getToken();


Log.d("FCMAPP", "Token is "+token);

10. Once we have the access token, we can use firebase console to send out the notification.
Run the app on your android handset.

https://riptutorial.com/ 514
https://riptutorial.com/ 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.

https://riptutorial.com/ 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().

https://riptutorial.com/ 517
https://riptutorial.com/ 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.

Step 4:- Handle incoming URLS

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_schedule);
onNewIntent(getIntent());
}

protected void onNewIntent(Intent intent) {


String action = intent.getAction();
Uri data = intent.getData();
if (Intent.ACTION_VIEW.equals(action) && data != null) {
articleId = data.getLastPathSegment();
TextView linkText = (TextView)findViewById(R.id.link);
linkText.setText(data.toString());
}

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:-

adb shell am start -a android.intent.action.VIEW -d "{URL}" < package name >

Android Studio Configurations:- Android studio > Build > Edit Configuration >Launch
options>select URL>then type in your Url here >Apply and test.Run 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.

Add AppIndexing API

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.

Step 1 :- Add google service

https://riptutorial.com/ 519
dependencies {
...
compile 'com.google.android.gms:play-services-appindexing:9.4.0'
...
}

Step 2 :- Import classes

import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.api.GoogleApiClient;

Step 3 :- Add App Indexing API calls

private GoogleApiClient mClient;


private Uri mUrl;
private String mTitle;
private String mDescription;

//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 GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
mUrl = "http://examplepetstore.com/dogs/standard-poodle";
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.

//setting title and description for App Indexing


mUrl = Uri.parse(“android-app://com.famelive/https/m.fame.live/vod/” +model.getId());
mTitle = model.getTitle();
mDescription = model.getDescription();

mClient.connect();
AppIndex.AppIndexApi.start(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) {
AppIndex.AppIndexApi.end(mClient, getAction());
mClient.disconnect();
}
super.onStop();
}

public Action getAction() {


Thing object = new Thing.Builder()
.setName(mTitle)
.setDescription(mDescription)
.setUrl(mUrl)
.build();

return new Action.Builder(Action.TYPE_WATCH)

https://riptutorial.com/ 520
.setObject(object)
.setActionStatus(Action.STATUS_TYPE_COMPLETED)
.build();
}

To test this just follow the step 4 in Remarks given below.

Read Firebase App Indexing online: https://riptutorial.com/android/topic/5957/firebase-app-


indexing

https://riptutorial.com/ 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 build.gradle file:

dependencies {
compile 'com.google.firebase:firebase-messaging:10.2.1'
}

Now you are ready to work with the FCM in Android.

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.

Edit your AndroidManifest.xml file

<service
android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>

<service
android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.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

https://riptutorial.com/ 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
FirebaseInstanceID.getToken() to retrieve the current token.

Example:

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

/**
* 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 = FirebaseInstanceId.getInstance().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

public class MyFirebaseMessagingService extends FirebaseMessagingService {


Bitmap bitmap;
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
String message = remoteMessage.getData().get("message");
//imageUri will contain URL of the image to be displayed with Notification
String imageUri = remoteMessage.getData().get("image");
String link=remoteMessage.getData().get("link");

//To get a Bitmap image from the URL received


bitmap = getBitmapfromUrl(imageUri);
sendNotification(message, bitmap,link);

/**
* Create and show a simple notification containing the received FCM message.
*/

private void sendNotification(String messageBody, Bitmap image, String link) {


Intent intent = new Intent(this, NewsListActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

https://riptutorial.com/ 523
intent.putExtra("LINK",link);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */,
intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setLargeIcon(image)/*Notification icon image*/
.setSmallIcon(R.drawable.hindi)
.setContentTitle(messageBody)
.setStyle(new NotificationCompat.BigPictureStyle()
.bigPicture(image))/*Notification with Image*/
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());


}
public Bitmap getBitmapfromUrl(String imageUrl) {
try {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(input);
return bitmap;

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
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,BrowserActivity.class);
i.putExtra("link",getIntent().getStringExtra("LINK"));
i.putExtra("PUSH","yes");
NewsListActivity.this.startActivity(i);
finish();
}}

Receive Messages

To receive messages, use a service that extends FirebaseMessagingService and override the
onMessageReceived method.

public class MyFcmListenerService extends FirebaseMessagingService {

/**

https://riptutorial.com/ 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 = message.getFrom();

// Check if message contains a data payload.


if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
Map<String, String> data = message.getData();
}

// Check if message contains a notification payload.


if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " +
remoteMessage.getNotification().getBody());
}

//.....
}

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.

Here a short recap:

App state Notification Data Both

Foreground onMessageReceived onMessageReceived onMessageReceived

Background System tray onMessageReceived Notification: system tray

Data: in extras of the intent.

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:

FirebaseMessaging.getInstance().subscribeToTopic("myTopic");

Read Firebase Cloud Messaging online: https://riptutorial.com/android/topic/8826/firebase-cloud-


messaging

https://riptutorial.com/ 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:

• Create an app on the Firebase Console here.

• Copy the google-services.json file from your project into your in app/ directory.

• Add the following rules to your root-level build.gradle file in order to include the google-
services plugin:

buildscript {
// ...
dependencies {
// ...
classpath 'com.google.gms: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:

apply plugin: 'com.google.gms.google-services'

• Add the dependency for Crash Reporting to your app-level build.gradle file:

compile 'com.google.firebase:firebase-crash:10.2.1'

• You can then fire a custom exception from your application by using the following line:

FirebaseCrash.report(new Exception("Non Fatal Error logging"));

All your fatal exceptions will be reported to your Firebase Console.

• If you want to add custom logs to a console, you can use the following code:

FirebaseCrash.log("Level 2 completed.");

For more information, please visit:

• Official documentation
• Stack Overflow dedicated topic

https://riptutorial.com/ 526
How to report an error

Firebase Crash Reporting automatically generates reports for fatal errors (or uncaught
exceptions).

You can create your custom report using:

FirebaseCrash.report(new Exception("My first Android non-fatal error"));

You can check in the log when FirebaseCrash initialized the module:

07–20 08:57:24.442 D/FirebaseCrashApiImpl: FirebaseCrash reporting API


initialized 07–20 08:57:24.442 I/FirebaseCrash: FirebaseCrash reporting initialized
com.google.firebase.crash.internal.zzg@3333d325 07–20 08:57:24.442
D/FirebaseApp: Initialized class com.google.firebase.crash.FirebaseCrash.

And then when it sent the exception:

07–20 08:57:47.052 D/FirebaseCrashApiImpl: throwable java.lang.Exception: My


first Android non-fatal error 07–20 08:58:18.822
D/FirebaseCrashSenderServiceImpl: Response code: 200 07–20 08:58:18.822
D/FirebaseCrashSenderServiceImpl: Report sent

You can add custom logs to your report with

FirebaseCrash.log("Activity created");

Read Firebase Crash Reporting online: https://riptutorial.com/android/topic/5965/firebase-crash-


reporting

https://riptutorial.com/ 527
Chapter 104: Firebase Realtime DataBase
Remarks

Other related topics:


• Firebase

Examples
Firebase Realtime DataBase event handler

First Initialize FirebaseDatabase:

FirebaseDatabase database = FirebaseDatabase.getInstance();

Write to your database:

// Write a message to the database


FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("message");

myRef.setValue("Hello, World!");

Read from your database:

// Read from the database


myRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
String value = dataSnapshot.getValue(String.class);
Log.d(TAG, "Value is: " + value);
}

@Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});

Retrieve Data on Android events:

ChildEventListener childEventListener = new ChildEventListener() {


@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());

https://riptutorial.com/ 528
}

@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
}

@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());

@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());

@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "postComments:onCancelled", databaseError.toException());
Toast.makeText(mContext, "Failed to load comments.",
Toast.LENGTH_SHORT).show();
}
};
ref.addChildEventListener(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 build.gradle file:

compile 'com.google.firebase:firebase-database:10.2.1'

3. Configure Firebase Database Rules

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.

// Write a message to the database


FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("message");

myRef.setValue("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.

https://riptutorial.com/ 529
First, add the dependency of the Firebase Database to the app level build.gradle file:

compile 'com.google.firebase:firebase-database:9.4.0'

Now, let us create a chat app which stores data into the Firebase Database.

Step 1: Create a class named Chat


Just create a class with some basic variables required for the chat:

public class Chat{


public String name, message;
}

Step 2: Create some JSON data


For sending/retrieving data to/from the Firebase Database, you need to use JSON. Let us assume
that some chats are already stored at the root level in the database. The data of these chats could
look like as follows:

[
{
"name":"John Doe",
"message":"My first Message"
},
{
"name":"John Doe",
"message":"Second Message"
},
{
"name":"John Doe",
"message":"Third Message"
}
]

Step 3: Adding the listeners


There are three types of listeners. In the following example we are going to use the
childEventListener:

DatabaseReference chatDb = FirebaseDatabase.getInstance().getReference() // Referencing the


root of the database.
.child("chats"); // Referencing the "chats" node under the root.

chatDb.addChildEventListener(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

https://riptutorial.com/ 530
// example, this function is going to be called 3 times.

// Retrieving the Chat object from this function is simple.


Chat chat; // Create a null chat object.

// 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 Chat.class.
chat = dataSnapshot.getValue(Chat.class);

// 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.

// To get the key, use the .getKey() function.


// To get the value, use code similar to the above one.
}

@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.

// To get the key, use the s String parameter .


}

@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
// This function is called when any of the child nodes is moved to a different
position.

// To get the key, use the s String parameter.


}

@Override
public void onCancelled(DatabaseError databaseError) {
// If anything goes wrong, this function is going to be called.

// You can get the exception by using databaseError.toException();


}
});

Step 4: Add data to the database


Just create a Chat class object and add the values as follows:

Chat chat=new Chat();


chat.name="John Doe";
chat.message="First message from android";

Now get a reference to the chats node as done in the retrieving session:

https://riptutorial.com/ 531
DatabaseReference chatDb = FirebaseDatabase.getInstance().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.
chatDb.push().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: Flat Database Structure

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).

Desired flat database structure:

|--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"

The used memo class

public class Memo {


private String title, content;
//getters and setters ...

https://riptutorial.com/ 532
//toMap() is necessary for the push process
private Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("title", title);
result.put("content", content);
return result;
}
}

Retrieving the memos of a user

//We need to store the keys and the memos seperately


private ArrayList<String> mKeys = new ArrayList<>();
private ArrayList<Memo> mMemos = new ArrayList<>();

//The user needs to be logged in to retrieve the uid


String currentUserId = FirebaseAuth.getInstance().getCurrentUser().getUid();

//This is the reference to the list of memos a user has


DatabaseReference currentUserMemoReference = FirebaseDatabase.getInstance().getReference()
.child("users").child(currentUserId).child("memos");

//This is a reference to the list of all memos


DatabaseReference memoReference = FirebaseDatabase.getInstance().getReference()
.child("memos");

//We start to listen to the users memos,


//this will also retrieve the memos initially
currentUserMemoReference.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
//Here we retrieve the key of the memo the user has.
String key = dataSnapshot.getKey(); //for example memokey1
//For later manipulations of the lists, we need to store the key in a list
mKeys.add(key);
//Now that we know which message belongs to the user,
//we request it from our memos:
memoReference.child(key).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Here we retrieve our memo:
Memo memo = dataSnapshot.getValue(Memo.class);
mMemos.add(memo);
}

@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

https://riptutorial.com/ 533
public void onCancelled(DatabaseError databaseError) { }
}

Creating a memo

//The user needs to be logged in to retrieve the uid


String currentUserUid = FirebaseAuth.getInstance().getCurrentUser().getUid();

//This is the path to the list of memos a user has


String userMemoPath = "users/" + currentUserUid + "/memos/";

//This is the path to the list of all memos


String memoPath = "memos/";

//We need to retrieve an unused key from the memos reference


DatabaseReference memoReference =
FirebaseDatabase.getInstance().getReference().child("memos");
String key = memoReference.push().getKey();
Memo newMemo = new Memo("Important numbers", "1337, 42, 3.14159265359");

Map<String, Object> childUpdates = new HashMap<>();


//The second parameter **here** (the value) does not matter, it's just that the key exists
childUpdates.put(userMemoPath + key, true);
childUpdates.put(memoPath + key, newMemo.toMap());

FirebaseDatabase.getInstance().getReference().updateChildren(childUpdates);

After the push, or database looks like this:

|--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"

Understanding firebase JSON database

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

https://riptutorial.com/ 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.

here is a sample JSON to show how data is stored in firebase:

{
"user_base" : {
"342343" : {
"email" : "[email protected]",
"authToken" : "some string",
"name" : "Kaushal",
"phone" : "+919916xxxxxx",
"serviceProviderId" : "firebase",
"signInServiceType" : "google",
},
"354895" : {
"email" : "[email protected]",
"authToken" : "some string",
"name" : "devil",
"phone" : "+919685xxxxxx",
"serviceProviderId" : "firebase",
"signInServiceType" : "github"
},
"371298" : {
"email" : "[email protected]",
"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.

Retrieving data from firebase

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

https://riptutorial.com/ 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.

create a firebase database reference

DatabaseReference userDBRef = FirebaseDatabase.getInstance().getReference();


// above statement point to base tree
userDBRef = DatabaseReference.getInstance().getReference().child("user_base")
// points to user_base table JSON (see previous section)

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:

DatabaseReference bruceWayneRef = userDBRef.child("371298");


// 371298 is key of bruce wayne user in JSON structure (previous section)

Or simply pass the whole reference to the JSON object:

DatabaseReference bruceWayneRef = DatabaseReference.getInstance().getReference()


.child("user_base/371298");
// deeply nested data can also be referenced this way, just put the fully
// qualified path in pattern shown in above code "blah/blah1/blah1-2/blah1-2-3..."

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).

Here is some sample code (code explanation after code):

userDBRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
User bruceWayne = dataSnapshot.child("371298").getValue(User.class);
// 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
});

https://riptutorial.com/ 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.

userDBRef.addListenerForSingleValueEvent(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:

String myKey = dataSnapshot.getKey();

Listening for child updates

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):

userDBRef.addChildEventListener(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
}

https://riptutorial.com/ 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).

onChiledRemoved() returns the removed child node.

Retrieving data with pagination

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 = userDBRef.orderByChild("email").limitToFirst(limit)
.startAt(start)
userListQuery.addValueEventListener(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.

Read Firebase Realtime DataBase online: https://riptutorial.com/android/topic/5511/firebase-


realtime-database

https://riptutorial.com/ 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

Elevation value for the FAB. May be a reference to


another resource, in the form
android.support.design:elevation
"@[+][package:]type/name" or a theme attribute in
the form "?[package:]type/name".

android.support.design:fabSize Size for the FAB.

android.support.design:rippleColor Ripple color for the FAB.

android.support.design:useCompatPadding Enable compat padding.

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
build.gradle file:

dependencies {
compile 'com.android.support:design:25.1.0'
}

Official Documentation:
https://developer.android.com/reference/android/support/design/widget/FloatingActionButton.html

https://riptutorial.com/ 539
Material Design Specifications:
https://material.google.com/components/buttons-floating-action-button.html

Examples
How to add the FAB to the layout

To use a FloatingActionButton just add the dependency in the build.gradle file as described in the
remarks section.

Then add to the layout:

<android.support.design.widget.FloatingActionButton
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"

If you wish to change the color in code you can use,

myFab.setBackgroundTintList(ColorStateList.valueOf(your color in int));

If you want to change FAB's color in pressed state use

https://riptutorial.com/ 540
mFab.setRippleColor(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.

Default circle size is 56 x 56dp

Mini circle size : 40 x 40dp

If you only want to change only the Interior icon use a 24 x 24dp icon for default size

Show and Hide FloatingActionButton on Swipe

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.

Here is an example with a ViewPager:

• Three Tabs
• Show FloatingActionButton for the first and third Tab
• Hide the FloatingActionButton on the middle Tab

public class MainActivity extends AppCompatActivity {

FloatingActionButton fab;
ViewPager viewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

fab = (FloatingActionButton) findViewById(R.id.fab);


viewPager = (ViewPager) findViewById(R.id.viewpager);

// ...... set up ViewPager ............

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

@Override
public void onPageSelected(int position) {
if (position == 0) {
fab.setImageResource(android.R.drawable.ic_dialog_email);
fab.show();

https://riptutorial.com/ 541
} else if (position == 2) {
fab.setImageResource(android.R.drawable.ic_dialog_map);
fab.show();
} else {
fab.hide();
}
}

@Override
public void onPageScrolled(int position, float positionOffset, int
positionOffsetPixels) {}

@Override
public void onPageScrollStateChanged(int state) {}
});

// Handle the FloatingActionButton click event:


fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = viewPager.getCurrentItem();
if (position == 0) {
openSend();
} else if (position == 2) {
openMap();
}
}
});

}
}

Result:

https://riptutorial.com/ 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 FloatingActionButton.Behavior 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)

public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {


public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
super();
}

@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
|| super.onStartNestedScroll(coordinatorLayout, child, directTargetChild,
target, nestedScrollAxes);
}

https://riptutorial.com/ 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) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed);
if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
// User scrolled down and the FAB is currently visible -> hide the FAB
child.hide();
} else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
// User scrolled up and the FAB is currently not visible -> show the FAB
child.show();
}
}
}

In the FloatingActionButton layout xml, specify the app:layout_behavior with the fully-qualified-
class-name of ScrollAwareFABBehavior:

app:layout_behavior="com.example.app.ScrollAwareFABBehavior"

For example with this layout:

<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<android.support.design.widget.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="6dp">
<android.support.v7.widget.Toolbar
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/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:elevation="0dp"
app:layout_scrollFlags="scroll|enterAlways"
/>

<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
app:tabMode="fixed"
android:layout_below="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"

https://riptutorial.com/ 544
android:background="?attr/colorPrimary"
app:elevation="0dp"
app:tabTextColor="#d3d3d3"
android:minHeight="?attr/actionBarSize"
/>

</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager
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"
/>

<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
app:layout_behavior="com.example.app.ScrollAwareFABBehavior"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>

Here is the result:

https://riptutorial.com/ 545
Setting behaviour of FloatingActionButton

You can set the behavior of the FAB in XML.

For example:

<android.support.design.widget.FloatingActionButton
app:layout_behavior=".MyBehavior" />

Or you can set programmatically using:

CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();


p.setBehavior(xxxx);
fab.setLayoutParams(p);

Read FloatingActionButton online: https://riptutorial.com/android/topic/2979/floatingactionbutton

https://riptutorial.com/ 546
Chapter 106: Formatting phone numbers with
pattern.
Introduction
This example show you how to format phone numbers with a patter

You will need the following library in your gradle.

compile 'com.googlecode.libphonenumber: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.

private String getFormattedNumber(String phoneNumber) {

PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();

Phonemetadata.NumberFormat numberFormat = new Phonemetadata.NumberFormat();

numberFormat.pattern = "(\\d{3})(\\d{3})(\\d{4})";

numberFormat.format = "($1) $2-$3";

List<Phonemetadata.NumberFormat> newNumberFormats = new ArrayList<>();

newNumberFormats.add(numberFormat);

Phonenumber.PhoneNumber phoneNumberPN = null;

try {
phoneNumberPN = phoneNumberUtil.parse(phoneNumber, Locale.US.getCountry());
phoneNumber = phoneNumberUtil.formatByPattern(phoneNumberPN,
PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL, newNumberFormats);

} catch (NumberParseException e) {
e.printStackTrace();
}

return phoneNumber;
}

Read Formatting phone numbers with pattern. online:


https://riptutorial.com/android/topic/9083/formatting-phone-numbers-with-pattern-

https://riptutorial.com/ 547
Chapter 107: Formatting Strings
Examples
Format a string resource

You can add wildcards in string resources and populate them at runtime:

1. Edit strings.xml

<string name="my_string">This is %1$s</string>

2. Format string as needed

String fun = "fun";


context.getString(R.string.my_string, fun);

Format a timestamp to string

For full description of patterns, see SimpleDateFormat reference

Date now = new Date();


long timestamp = now.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.US);
String dateStr = sdf.format(timestamp);

Formatting data types to String and vise versa

Data types to string formatting

Data types like int, float, double, long, boolean can be formatted to string using String.valueOf().

String.valueOf(1); //Output -> "1"


String.valueOf(1.0); //Output -> "1.0"
String.valueOf(1.2345); //Output -> "1.2345"
String.valueOf(true); //Output -> "true"

Vise versa of this, formatting string to other data type

Integer.parseInt("1"); //Output -> 1


Float.parseFloat("1.2"); //Output -> 1.2
Boolean.parseBoolean("true"); //Output -> true

Read Formatting Strings online: https://riptutorial.com/android/topic/1346/formatting-strings

https://riptutorial.com/ 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 onAttachFragment(Fragment childFragment) // Called when a fragment is attached as a


child of this fragment.

• void onConfigurationChanged(Configuration newConfig) // Called by the system when the


device configuration changes while your component is running.

• void onCreate(Bundle savedInstanceState) // Called to do initial creation of a fragment.

• View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle


savedInstanceState) // Called to have the fragment instantiate its user interface view.

• void onDestroy() // Called when the fragment is no longer in use.

• void onDestroyView() // Called when the view previously created by


onCreateView(LayoutInflater, ViewGroup, Bundle) has been detached from the fragment.

• void onDetach() // Called when the fragment is no longer attached to its activity.

• void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) // This method


was deprecated in API level 23. Use onInflate(Context, AttributeSet, Bundle) instead.

• void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) // Called when


a fragment is being created as part of a view layout inflation, typically from setting the
content view of an activity.

• void onPause() // Called when the Fragment is no longer resumed.

• void onResume() // Called when the fragment is visible to the user and actively running.

https://riptutorial.com/ 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.

• void onStart() // Called when the Fragment is visible to the user.

• void onStop() // Called when the Fragment is no longer started.

• void onViewStateRestored(Bundle savedInstanceState) // Called when all saved state has


been restored into the view hierarchy of the fragment.

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 android.os.Bundle;
import android.support.v4.app.Fragment;

public class MyFragment extends Fragment


{
// Our identifier for obtaining the name from arguments
private static final String NAME_ARG = "name";

https://riptutorial.com/ 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
args.putString(NAME_ARG, name);

myFragment.setArguments(args);
return myFragment;
}

@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Bundle arguments = getArguments();
if (arguments == null || !arguments.containsKey(NAME_ARG)) {
// Set a default or error as you see fit
} else {
mName = arguments.getString(NAME_ARG);
}
}
}

Now, in the Activity:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
MyFragment mFragment = MyFragment.newInstance("my name");
ft.replace(R.id.placeholder, mFragment);
//R.id.placeholder is where we want to load our fragment
ft.commit();

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.

Navigation between fragments using backstack and static fabric pattern

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) {

https://riptutorial.com/ 551
getSupportFragmentManager().beginTransaction()
.addToBackStack("fragmentA")
.replace(R.id.container, FragmentA.newInstance(), "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.

public void replaceFragment(Fragment fragment, String tag) {


//Get current fragment placed in container
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);

//Prevent adding same fragment on top


if (currentFragment.getClass() == fragment.getClass()) {
return;
}

//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);
}

//Otherwise, just replace fragment


getSupportFragmentManager()
.beginTransaction()
.addToBackStack(tag)
.replace(R.id.container, fragment, tag)
.commit();
}

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 {
super.onBackPressed();
}
}

Execution in activity:

replaceFragment(FragmentB.newInstance(), "fragmentB");

Execution outside activity (assuming MainActivity is our activity):

((MainActivity) getActivity()).replaceFragment(FragmentB.newInstance(), "fragmentB");

https://riptutorial.com/ 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:

Bundle bundle = new Bundle();


String myMessage = "Stack Overflow is cool!";
bundle.putString("message", myMessage );
FragmentClass fragInfo = new FragmentClass();
fragInfo.setArguments(bundle);
transaction.replace(R.id.fragment_single, fragInfo);
transaction.commit();

Fragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
String myValue = this.getArguments().getString("message");
...
}

Sending events back to an activity with callback interface

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:

public interface SampleCallback {


void onButtonClicked();
}

Next step is to assign this callback in fragment:

public final class SampleFragment extends Fragment {

private SampleCallback callback;

@Override

https://riptutorial.com/ 553
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof SampleCallback) {
callback = (SampleCallback) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement SampleCallback");
}
}

@Override
public void onDetach() {
super.onDetach();
callback = null;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
final View view = inflater.inflate(R.layout.sample, container, false);
// Add button's click listener
view.findViewById(R.id.actionButton).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
callback.onButtonClicked(); // Invoke callback here
}
});
return view;
}
}

And finally, implement callback in activity:

public final class SampleActivity extends Activity implements SampleCallback {

// ... Skipped code with settings content view and presenting the fragment

@Override
public void onButtonClicked() {
// Invoked when fragment's button has been clicked
}
}

Animate the transition between fragments

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.

Standard animations are specified by calling FragmentTransaction.setTransition(int transit), and


using one of the pre-defined constants available in the FragmentTransaction class. At the time of
writing, these constants are:

FragmentTransaction.TRANSIT_NONE
FragmentTransaction.TRANSIT_FRAGMENT_OPEN

https://riptutorial.com/ 554
FragmentTransaction.TRANSIT_FRAGMENT_CLOSE
FragmentTransaction.TRANSIT_FRAGMENT_FADE

The complete transaction might look something like this:

getSupportFragmentManager()
.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(R.id.contents, new MyFragment(), "MyFragmentTag")
.commit();

Custom animations are specified by calling either FragmentTransaction.setCustomAnimations(int


enter, int exit) or FragmentTransaction.setCustomAnimations(int enter, int exit, int popEnter,
int popExit).

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(R.anim.slide_in_left, R.anim.slide_out_right)
.replace(R.id.contents, 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:

<?xml version="1.0" encoding="utf-8"?>


<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="x"
android:valueType="floatType"
android:valueFrom="-1280"
android:valueTo="0"
android:duration="500"/>
</set>

Communication between Fragments

All communications between Fragments must go via an Activity. Fragments CANNOT


communicate with each other without an Activity.

Additional Resources

• How to implement OnFragmentInteractionListener


• Android | Communicating With Other Fragments

https://riptutorial.com/ 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
SenderFragment.SendMessageListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.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(R.id.fragment_receiver);

// Make sure that such a fragment exists


if (receiverFragment != null) {
// Send this message to the ReceiverFragment by calling its public method
receiverFragment.showMessage(message);
}
}
}

The layout file for the MainActivity hosts two fragments inside a LinearLayout :

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
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="com.naru.fragmentcommunication.MainActivity">

<fragment
android:id="@+id/fragment_sender"
android:name="com.naru.fragmentcommunication.SenderFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"

https://riptutorial.com/ 556
tools:layout="@layout/fragment_sender" />

<fragment
android:id="@+id/fragment_receiver"
android:name="com.naru.fragmentcommunication.ReceiverFragment"
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:

public class SenderFragment extends Fragment {

private SendMessageListener commander;

/**
* 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) {
super.onAttach(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(context.toString()
+ "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'
*

https://riptutorial.com/ 557
* @param activity
*/
@Override
public void onAttach(Activity activity) {
super.onAttach(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(activity.toString()
+ "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 = inflater.inflate(R.layout.fragment_receiver, container, false);

// Initialize button and a click listener on it


Button send = (Button) view.findViewById(R.id.bSend);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

// Sanity check whether we were able to properly initialize our interface


reference
if (commander != null) {

// 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.
commander.onSendMessage("HELLO FROM SENDER FRAGMENT!");
}
}
});

return view;
}
}

The layout file for the SenderFragment:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">

<Button
android:id="@+id/bSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SEND"
android:layout_gravity="center_horizontal" />
</LinearLayout>

https://riptutorial.com/ 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 :

public class ReceiverFragment extends Fragment {


TextView tvMessage;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// Inflate view for the sender fragment.
View view = inflater.inflate(R.layout.fragment_receiver, container, false);

// Initialize the TextView


tvMessage = (TextView) view.findViewById(R.id.tvReceivedMessage);

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) {
tvMessage.setText(message);
}
}

The layout file for the ReceiverFragment :

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tvReceivedMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Waiting for message!" />
</LinearLayout>

Read Fragments online: https://riptutorial.com/android/topic/1396/fragments

https://riptutorial.com/ 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.

Fresco also supports streaming of JPEGs.

Remarks
How to set up dependencies in the app level build.gradle file:

dependencies {
// Your app's other dependencies.
compile 'com.facebook.fresco:fresco:0.14.1' // Or a newer version if available.
}

More information can be found here.

Examples
Getting Started with Fresco

First, add Fresco to your build.gradle as shown in the Remarks section:

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:

public class MyApplication extends Application {


@Override
public void onCreate() {
super.onCreate();
Fresco.initialize(this);
}
}

If you want to load remote images from a server, your app needs the internt permission. Simply
add it to your AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

https://riptutorial.com/ 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):

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="120dp"
android:layout_height="120dp"
fresco:placeholderImage="@drawable/placeholder" />

Or supply an aspect ratio for your image:

<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="120dp"
android:layout_height="wrap_content"
fresco:viewAspectRatio="1.33"
fresco:placeholderImage="@drawable/placeholder" />

Finally, you can set your image URI in Java:

SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);


draweeView.setImageURI("http://yourdomain.com/yourimage.jpg");

That's it! You should see your placeholder drawable until the network image has been fetched.

Using OkHttp 3 with Fresco

First, in addition to the normal Fresco Gradle dependency, you have to add the OkHttp 3
dependency to your build.gradle:

compile "com.facebook.fresco:imagepipeline-okhttp3:1.2.0" // Or a newer version.

When you initialize Fresco (usually in your custom Application implementation), you can now
specify your OkHttp client:

OkHttpClient okHttpClient = new OkHttpClient(); // Build on your own OkHttpClient.

Context context = ... // Your Application context.


ImagePipelineConfig config = OkHttpImagePipelineConfigFactory
.newBuilder(context, okHttpClient)
.build();
Fresco.initialize(context, config);

JPEG Streaming with Fresco using DraweeController

This example assumes that you have already added Fresco to your app (see this example):

https://riptutorial.com/ 561
SimpleDraweeView img = new SimpleDraweeView(context);
ImageRequest request = ImageRequestBuilder
.newBuilderWithSource(Uri.parse("http://example.com/image.png"))
.setProgressiveRenderingEnabled(true) // This is where the magic happens.
.build();

DraweeController controller = Fresco.newDraweeControllerBuilder()


.setImageRequest(request)
.setOldController(img.getController()) // Get the current controller from our
SimpleDraweeView.
.build();

img.setController(controller); // Set the new controller to the SimpleDraweeView to enable


progressive JPEGs.

Read Fresco online: https://riptutorial.com/android/topic/5217/fresco

https://riptutorial.com/ 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

Step 1 - installing VirtualBox


Download and install VirtualBox according to your operating system. , it is required to run
Genymotion.

Step 2 - downloading Genymotion


Go to the Genymotion download page and download Genymotion according to your operating
system.

Note: you will need to create a new account OR log-in with your account.

Step 3 - Installing Genymotion


if on Linux then refer to this answer, to install and run a .bin file.

Step 4 - Installing Genymotion's emulators


• run Genymotion
• Press on the Add button (in top bar).
• Log-In with your account and you will be able to browse the available emulators.
• select and Install what you need.

Step 5 - Integrating genymotion with Android Studio

Genymotion, can be integrated with Android Studio via a plugin, here the steps to install it in Android
Studio

• go to File/Settings (for Windows and Linux) or to Android Studio/Preferences (for Mac OS X)

https://riptutorial.com/ 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.

Step 6 - Running Genymotion from Android Studio

• go to File/Settings (for Windows and Linux) or to Android Studio/Preferences (for Mac OS X)


• go to Other Settings/Genymotion and add the path of Genymotion's folder and apply your
changes.

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!

Google framework on Genymotion

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)

1. Download from above link


2. Just drag & drop downloaded zip file to genymotion and restart
3. Add google account and download "Google Play Music" and Run.

Reference:-
Stack overflow question on this topic

Read Genymotion for android online: https://riptutorial.com/android/topic/9245/genymotion-for-


android

https://riptutorial.com/ 564
Chapter 111: Gesture Detection
Remarks
Official Documentation: Detecting Common Gestures

Examples
Swipe Detection

public class OnSwipeListener implements View.OnTouchListener {

private final GestureDetector gestureDetector;

public OnSwipeListener(Context context) {


gestureDetector = new GestureDetector(context, new GestureListener());
}

@Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}

private final class GestureListener extends GestureDetector.SimpleOnGestureListener {

private static final int SWIPE_VELOCITY_THRESHOLD = 100;


private static final int SWIPE_THRESHOLD = 100;

@Override
public boolean onDown(MotionEvent e) {
return true;
}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float
velocityY) {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) >
SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
}
} else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) >
SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom();
} else {
onSwipeTop();
}
}

https://riptutorial.com/ 565
return true;
}
}

public void onSwipeRight() {


}

public void onSwipeLeft() {


}

public void onSwipeTop() {


}

public void onSwipeBottom() {


}

Applied to a view...

view.setOnTouchListener(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");
}

});

Basic Gesture Detection

public class GestureActivity extends Activity implements


GestureDetector.OnDoubleTapListener,
GestureDetector.OnGestureListener {

private GestureDetector mGestureDetector;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGestureDetector = new GestureDetector(this, this);
mGestureDetector.setOnDoubleTapListener(this);
}

@Override
public boolean onTouchEvent(MotionEvent event){
mGestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}

https://riptutorial.com/ 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;
}

Read Gesture Detection online: https://riptutorial.com/android/topic/4711/gesture-detection

https://riptutorial.com/ 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 View.getViewTreeObserver javadocs:

// The returned ViewTreeObserver observer is not guaranteed to remain


// valid for the lifetime of this View. If the caller of this method keeps
// a long-lived reference to ViewTreeObserver, it should always check for
// the return value of {@link ViewTreeObserver#isAlive()}.

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 com.example;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;

public class ExampleActivity extends Activity {

@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);

final View viewToMeasure = findViewById(R.id.view_to_measure);

// viewToMeasure dimensions are not known at this point.


// viewToMeasure.getWidth() and viewToMeasure.getHeight() both return 0,
// regardless of on-screen size.

viewToMeasure.getViewTreeObserver().addOnPreDrawListener(new
ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
// viewToMeasure is now measured and laid out, and displayed dimensions are
known.

https://riptutorial.com/ 568
logComputedViewDimensions(viewToMeasure.getWidth(),
viewToMeasure.getHeight());

// Remove this listener, as we have now successfully calculated the desired


dimensions.
viewToMeasure.getViewTreeObserver().removeOnPreDrawListener(this);

// Always return true to continue drawing.


return true;
}
});
}

private void logComputedViewDimensions(final int width, final int height) {


Log.d("example", "viewToMeasure has width " + width);
Log.d("example", "viewToMeasure has height " + height);
}

Read Getting Calculated View Dimensions online: https://riptutorial.com/android/topic/115/getting-


calculated-view-dimensions

https://riptutorial.com/ 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:

<uses-feature android:glEsVersion="0x00020000" android:required="true"/>

Create your extended GLSurfaceView:

import static android.opengl.GLES20.*; // To use all OpenGL ES 2.0 methods and constants
statically

public class MyGLSurfaceView extends GLSurfaceView {

public MyGLSurfaceView(Context context, AttributeSet attrs) {


super(context, attrs);

setEGLContextClientVersion(2); // OpenGL ES version 2.0


setRenderer(new MyRenderer());
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}

public final class MyRenderer implements GLSurfaceView.Renderer{


public final void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Your OpenGL ES init methods
glClearColor(1f, 0f, 0f, 1f);
}
public final void onSurfaceChanged(GL10 unused, int width, int height) {
glViewport(0, 0, width, height);
}

public final void onDrawFrame(GL10 unused) {


// Your OpenGL ES draw methods
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
}
}

Add MyGLSurfaceView to your layout:

https://riptutorial.com/ 570
<com.example.app.MyGLSurfaceView
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.

Compiling and Linking GLSL-ES Shaders from asset file

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:

private String loadStringFromAssetFile(Context myContext, String filePath){


StringBuilder shaderSource = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new
InputStreamReader(myContext.getAssets().open(filePath)));
String line;
while((line = reader.readLine()) != null){
shaderSource.append(line).append("\n");
}
reader.close();
return shaderSource.toString();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Could not load shader file");
return null;
}
}

Now you need to create a function that compiles a shader stored in a sting:

private int compileShader(int shader_type, String shaderString){

// This compiles the shader from the string


int shader = glCreateShader(shader_type);
glShaderSource(shader, shaderString);
glCompileShader(shader);

// This checks for for compilation errors


int[] compiled = new int[1];
glGetShaderiv(shader, GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
String log = glGetShaderInfoLog(shader);

Log.e(TAG, "Shader compilation error: ");


Log.e(TAG, log);
}
return shader;
}

Now you can load, compile and link your shaders:

https://riptutorial.com/ 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);

// Link shaders and create shader program


int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram , vertexShader);
glAttachShader(shaderProgram , fragmentShader);
glLinkProgram(shaderProgram);

// Check for linking errors:


int linkStatus[] = new int[1];
glGetProgramiv(shaderProgram, GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GL_TRUE) {
String log = glGetProgramInfoLog(shaderProgram);

Log.e(TAG,"Could not link shader program: ");


Log.e(TAG, log);
}

If there are no errors, your shader program is ready to use:

glUseProgram(shaderProgram);

Read Getting started with OpenGL ES 2.0+ online:


https://riptutorial.com/android/topic/8662/getting-started-with-opengl-es-2-0plus

https://riptutorial.com/ 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

ArrayList<String> fontNames = new ArrayList<String>();


File temp = new File("/system/fonts/");
String fontSuffix = ".ttf";

for(File font : temp.listFiles()) {


String fontName = font.getName();
if(fontName.endsWith(fontSuffix)) {
fontNames.add(fontName.subSequence(0,fontName.lastIndexOf(fontSuffix)).toString());
}
}

Applying a system font to a TextView

In the following code you need to replace fontsname by the name of the font you would like to use:

TextView lblexample = (TextView) findViewById(R.id.lblexample);


lblexample.setTypeface(Typeface.createFromFile("/system/fonts/" + "fontsname" + ".ttf"));

Read Getting system font names and using the fonts online:
https://riptutorial.com/android/topic/10930/getting-system-font-names-and-using-the-fonts

https://riptutorial.com/ 573
Chapter 115: Glide
Introduction
**** WARNING This documentation is unmaintained and frequently inaccurate ****

Glide's official documentation is a much better source:

For Glide v4, see http://bumptech.github.io/glide/. For Glide v3, see


https://github.com/bumptech/glide/wiki.

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.

Source code and further documentation is available on GitHub: https://github.com/bumptech/glide

Examples
Add Glide to your project

From the official documentation:

With Gradle:

repositories {
mavenCentral() // jcenter() works as well because it pulls from Maven Central
}

dependencies {
compile 'com.github.bumptech.glide:glide:4.0.0'
compile 'com.android.support:support-v4:25.3.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0'
}

With Maven:

https://riptutorial.com/ 574
<dependency>
<groupId>com.github.bumptech.glide</groupId>
<artifactId>glide</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>support-v4</artifactId>
<version>r7</version>
</dependency>
<dependency>
<groupId>com.github.bumptech.glide</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 proguard.cfg (See Glide's wiki for more info):

-keep public class * implements com.bumptech.glide.module.GlideModule


-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}

# for DexGuard only


-keepresourcexmlelements manifest/application/meta-data@value=GlideModule

Loading an image

ImageView
To load an image from a specified URL, Uri, resource id, or any other model into an ImageView:

ImageView imageView = (ImageView) findViewById(R.id.imageView);


String yourUrl = "http://www.yoururl.com/image.png";

Glide.with(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 (R.drawable.image).

RecyclerView and ListView


In ListView or RecyclerView, you can use exactly the same lines:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
MyViewHolder myViewHolder = (MyViewHolder) viewHolder;

https://riptutorial.com/ 575
String currentUrl = myUrls.get(position);

Glide.with(context)
.load(currentUrl)
.into(myViewHolder.imageView);
}

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(RecyclerView.ViewHolder viewHolder, int position) {
MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
String currentUrl = myUrls.get(position);

if (TextUtils.isEmpty(currentUrl)) {
Glide.clear(viewHolder.imageView);
// Now that the view has been cleared, you can safely set your own resource
viewHolder.imageView.setImageResource(R.drawable.missing_image);
} else {
Glide.with(context)
.load(currentUrl)
.into(myViewHolder.imageView);
}
}

Glide circle transformation (Load image in a circular ImageView)

Create a circle image with glide.

public class CircleTransform extends BitmapTransformation {

public CircleTransform(Context context) {


super(context);
}

@Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth,


int outHeight) {
return circleCrop(pool, toTransform);
}

private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {


if (source == null) return null;

int size = Math.min(source.getWidth(), source.getHeight());


int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;

Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);

Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);


if (result == null) {
result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
}

Canvas canvas = new Canvas(result);


Paint paint = new Paint();

https://riptutorial.com/ 576
paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP,
BitmapShader.TileMode.CLAMP));
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
return result;
}

@Override public String getId() {


return getClass().getName();
}
}

Usage:

Glide.with(context)
.load(yourimageurl)
.transform(new CircleTransform(context))
.into(userImageView);

Default transformations

Glide includes two default transformations, fit center and center crop.

Fit center:

Glide.with(context)
.load(yourUrl)
.fitCenter()
.into(yourView);

Fit center performs the same transformation as Android's ScaleType.FIT_CENTER.

Center crop:

Glide.with(context)
.load(yourUrl)
.centerCrop()
.into(yourView);

Center crop performs the same transformation as Android's ScaleType.CENTER_CROP.

For more information, see Glide's wiki.

Glide rounded corners image with custom Glide target

First make utility class or use this method in class needed

public class UIUtils {


public static BitmapImageViewTarget getRoundedImageTarget(@NonNull final Context context,
@NonNull final ImageView imageView,
final float radius) {
return new BitmapImageViewTarget(imageView) {

https://riptutorial.com/ 577
@Override
protected void setResource(final Bitmap resource) {
RoundedBitmapDrawable circularBitmapDrawable =
RoundedBitmapDrawableFactory.create(context.getResources(), resource);
circularBitmapDrawable.setCornerRadius(radius);
imageView.setImageDrawable(circularBitmapDrawable);
}
};
}

Loading image:

Glide.with(context)
.load(imageUrl)
.asBitmap()
.into(UIUtils.getRoundedImageTarget(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.

Example with similar fade in to default Glide animation.

Glide.with(context)
.load(imageUrl)
.asBitmap()
.animate(R.anim.abc_fade_in)
.into(UIUtils.getRoundedImageTarget(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.

Note you also need to have support library to use RoundedBitmapDrawableFactory

Preloading images

To preload remote images and ensure that the image is only downloaded once:

Glide.with(context)
.load(yourUrl)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.preload();

Then:

Glide.with(context)
.load(yourUrl)
.diskCacheStrategy(DiskCacheStrategy.SOURCE) // 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):

https://riptutorial.com/ 578
Glide.with(context)
.load(yourFilePathOrUri)
.fitCenter() // Or whatever transformation you want
.preload(200, 200); // Or whatever width and height you want

Then:

Glide.with(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);

Placeholder and Error handling

If you want to add a Drawable be shown during the load, you can add a placeholder:

Glide.with(context)
.load(yourUrl)
.placeholder(R.drawable.placeholder)
.into(imageView);

If you want a Drawable to be shown if the load fails for any reason:

Glide.with(context)
.load(yourUrl)
.error(R.drawable.error)
.into(imageView);

If you want a Drawable to be shown if you provide a null model (URL, Uri, file path etc):

Glide.with(context)
.load(maybeNullUrl)
.fallback(R.drawable.fallback)
.into(imageView);

Load image in a circular ImageView without custom transformations

Create a custom BitmapImageViewTarget to load the image into:

public class CircularBitmapImageViewTarget extends BitmapImageViewTarget


{
private Context context;
private ImageView imageView;

public CircularBitmapImageViewTarget(Context context, ImageView imageView)


{
super(imageView);
this.context = context;
this.imageView = imageView;
}

@Override

https://riptutorial.com/ 579
protected void setResource(Bitmap resource)
{
RoundedBitmapDrawable bitmapDrawable =
RoundedBitmapDrawableFactory.create(context.getResources(), resource);
bitmapDrawable.setCircular(true);
imageView.setImageDrawable(bitmapDrawable);
}
}

Usage:

Glide
.with(context)
.load(yourimageidentifier)
.asBitmap()
.into(new CircularBitmapImageViewTarget(context, imageView));

Handling Glide image load failed

Glide
.with(context)
.load(currentUrl)
.into(new BitmapImageViewTarget(profilePicture) {
@Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable circularBitmapDrawable =
RoundedBitmapDrawableFactory.create(context.getResources(), resource);
circularBitmapDrawable.setCornerRadius(radius);
imageView.setImageDrawable(circularBitmapDrawable);
}

@Override
public void onLoadFailed(@NonNull Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, SET_YOUR_DEFAULT_IMAGE);
Log.e(TAG, e.getMessage(), e);
}
});

Here at SET_YOUR_DEFAULT_IMAGE place you can set any default Drawable. This image will be shown if
Image loading is failed.

Read Glide online: https://riptutorial.com/android/topic/1091/glide

https://riptutorial.com/ 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:

• Get an API key from the Google Developers Console

• Add necessary permissions and API key to the manifest:

<!-- Not required for getting current headphone state -->


<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- Only required for actvity recognition -->
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>

<!-- Replace with your actual API key from console -->
<meta-data android:name="com.google.android.awareness.API_KEY"
android:value="YOUR_API_KEY"/>

<!-- Required for Snapshot API only -->


<meta-data android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY"/>

• Initalize the GoogleApiClient somewhere, preferably in your activity's onCreate() method.

GoogleApiClient client = new GoogleApiClient.Builder(context)


.addApi(Awareness.API)
.build();
client.connect();

• Call the API of your choice

• Parse result

An easy way to check for the needed user permission is a method such as this:

private boolean isFineLocationGranted() {


if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Log.e(getClass().getSimpleName(), "Fine location permission not granted!");
}
}

Examples
Get current user activity using Snapshot API

https://riptutorial.com/ 581
For one-time, non-constant requests for a user's physical activity, use the Snapshot API:

// Remember to initialize your client as described in the Remarks section


Awareness.SnapshotApi.getDetectedActivity(client)
.setResultCallback(new ResultCallback<DetectedActivityResult>() {
@Override
public void onResult(@NonNull DetectedActivityResult detectedActivityResult) {
if (!detectedActivityResult.getStatus().isSuccess()) {
Log.e(getClass().getSimpleName(), "Could not get the current activity.");
return;
}
ActivityRecognitionResult result = detectedActivityResult
.getActivityRecognitionResult();
DetectedActivity probableActivity = result.getMostProbableActivity();
Log.i(getClass().getSimpleName(), "Activity received : " +
probableActivity.toString());
}
});

Get headphone state with Snapshot API

// Remember to initialize your client as described in the Remarks section


Awareness.SnapshotApi.getHeadphoneState(client)
.setResultCallback(new ResultCallback<HeadphoneStateResult>() {
@Override
public void onResult(@NonNull HeadphoneStateResult headphoneStateResult) {
Log.i(TAG, "Headphone state connection state: " +
headphoneStateResult.getHeadphoneState()
.getState() == HeadphoneState.PLUGGED_IN));
}
});

Get current location using Snapshot API

// Remember to intialize your client as described in the Remarks section


Awareness.SnapshotApi.getLocation(client)
.setResultCallback(new ResultCallback<LocationResult>() {
@Override
public void onResult(@NonNull LocationResult locationResult) {
Location location = locationResult.getLocation();
Log.i(getClass().getSimpleName(), "Coordinates: "location.getLatitude() + "," +
location.getLongitude() + ", radius : " + location.getAccuracy());
}
});

Get nearby places using Snapshot API

// Remember to initialize your client as described in the Remarks section


Awareness.SnapshotApi.getPlaces(client)
.setResultCallback(new ResultCallback<PlacesResult>() {
@Override
public void onResult(@NonNull PlacesResult placesResult) {
List<PlaceLikelihood> likelihoodList = placesResult.getPlaceLikelihoods();
if (likelihoodList == null || likelihoodList.isEmpty()) {
Log.e(getClass().getSimpleName(), "No likely places");

https://riptutorial.com/ 582
}
}
});

As for getting the data in those places, here are some options:

Place place = placeLikelihood.getPlace();


String likelihood = placeLikelihood.getLikelihood();
Place place = likelihood.getPlace();
String placeName = place.getName();
String placeAddress = place.getAddress();
String placeCoords = place.getLatLng();
String locale = extractFromLocale(place.getLocale()));

Get current weather using Snapshot API

// Remember to initialize your client as described in the Remarks section


Awareness.SnapshotApi.getWeather(client)
.setResultCallback(new ResultCallback<WeatherResult>() {
@Override
public void onResult(@NonNull WeatherResult weatherResult) {
Weather weather = weatherResult.getWeather();
if (weather == null) {
Log.e(getClass().getSimpleName(), "No weather received");
} else {
Log.i(getClass().getSimpleName(), "Temperature is " +
weather.getTemperature(Weather.CELSIUS) + ", feels like " +
weather.getFeelsLikeTemperature(Weather.CELSIUS) +
", humidity is " + weather.getHumidity());
}
}
});

Get changes in user activity with Fence API

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;

// Make sure to initialize your client as described in the Remarks section.


protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// etc.

// The 0 is a standard Activity request code that can be changed to your needs.
mPendingIntent = PendingIntent.getBroadcast(this, 0,
new Intent(FENCE_RECEIVER_ACTION), 0);

https://riptutorial.com/ 583
registerReceiver(mFenceReceiver, new IntentFilter(FENCE_RECEIVER_ACTION));

// Create the fence.


AwarenessFence fence = DetectedActivityFence.during(DetectedActivityFence.WALKING);
// Register the fence to receive callbacks.
Awareness.FenceApi.updateFences(client, new FenceUpdateRequest.Builder()
.addFence(FENCE_KEY, fence, mPendingIntent)
.build())
.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
if (status.isSuccess()) {
Log.i(FENCE_KEY, "Successfully registered.");
} else {
Log.e(FENCE_KEY, "Could not be registered: " + status);
}
}
});
}
}

Now you can receive the intent with a BroadcastReceiver to get callbacks when the user changes
the activity:

public class FenceReceiver extends BroadcastReceiver {

private static final String TAG = "FenceReceiver";

@Override
public void onReceive(Context context, Intent intent) {
// Get the fence state
FenceState fenceState = FenceState.extract(intent);

switch (fenceState.getCurrentState()) {
case FenceState.TRUE:
Log.i(TAG, "User is walking");
break;
case FenceState.FALSE:
Log.i(TAG, "User is not walking");
break;
case FenceState.UNKNOWN:
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";

https://riptutorial.com/ 584
private FenceReceiver mFenceReceiver;
private PendingIntent mPendingIntent;

// Make sure to initialize your client as described in the Remarks section


protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// etc

// The 0 is a standard Activity request code that can be changed for your needs
mPendingIntent = PendingIntent.getBroadcast(this, 0,
new Intent(FENCE_RECEIVER_ACTION), 0);
registerReceiver(mFenceReceiver, new IntentFilter(FENCE_RECEIVER_ACTION));

// Create the fence


AwarenessFence fence = LocationFence.entering(48.136334, 11.581660, 25);
// Register the fence to receive callbacks.
Awareness.FenceApi.updateFences(client, new FenceUpdateRequest.Builder()
.addFence(FENCE_KEY, fence, mPendingIntent)
.build())
.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
if (status.isSuccess()) {
Log.i(FENCE_KEY, "Successfully registered.");
} else {
Log.e(FENCE_KEY, "Could not be registered: " + status);
}
}
});
}
}

Now create a BroadcastReciver to recive updates in user state:

public class FenceReceiver extends BroadcastReceiver {

private static final String TAG = "FenceReceiver";

@Override
public void onReceive(Context context, Intent intent) {
// Get the fence state
FenceState fenceState = FenceState.extract(intent);

switch (fenceState.getCurrentState()) {
case FenceState.TRUE:
Log.i(TAG, "User is in location");
break;
case FenceState.FALSE:
Log.i(TAG, "User is not in location");
break;
case FenceState.UNKNOWN:
Log.i(TAG, "User is doing something unknown");
break;
}
}
}

Read Google Awareness APIs online: https://riptutorial.com/android/topic/3361/google-awareness-


apis

https://riptutorial.com/ 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.

You can make a call to GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo() to get the


attribution text at runtime.

Examples
Integrate Google Drive in Android

Create a New Project on Google Developer Console

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.

To create a project on Google Developer Console, follow these steps:

• 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.

https://riptutorial.com/ 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.

https://riptutorial.com/ 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.

https://riptutorial.com/ 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/debug.keystore -list -v

https://riptutorial.com/ 589
• Now, add Package name and SHA-1 fingerprint in input fields on credentials page. Finally,
click on create button to create API key.

https://riptutorial.com/ 590
• This will create API key for Android. We will use the this API key to integrate Android
application with Google Drive.

https://riptutorial.com/ 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.

https://riptutorial.com/ 592
• Click on Drive API link to open overview page of Google Drive API.

https://riptutorial.com/ 593
• Click on the Enable button to enable Google drive API. It allows client access to Google
Drive.

Add Internet Permission

App needs Internet access Google Drive files. Use the following code to set up Internet

https://riptutorial.com/ 594
permissions in AndroidManifest.xml file :

<uses-permission android:name="android.permission.INTERNET" />

Add Google Play Services

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 build.gradle(app
module) file and add Google play services SDK as a dependencies.

dependencies {
....
compile 'com.google.android.gms:play-services:<latest_version>'
....
}

Add API key in Manifest file

To use Google API in Android application, we need to add API key and version of the Google Play
Service in the AndroidManifest.xml file. Add the correct metadata tags inside the tag of the
AndroidManifest.xml file.

Connect and Authorize the Google Drive Android API

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() {
super.onResume();
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 GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}

mGoogleApiClient.connect();
}

https://riptutorial.com/ 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() {
super.onStop();
if (mGoogleApiClient != null) {

// disconnect Google Android Drive API connection.


mGoogleApiClient.disconnect();
}
super.onPause();
}

Implement Connection Callbacks and Connection Failed Listener

We will implement Connection Callbacks and Connection Failed Listener of Google API client in
MainActivity.java 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.

You need to implement ConnectionCallbacks and OnConnectionFailedListener in your activity.


Use the following code in your Java file.

@Override
public void onConnectionFailed(ConnectionResult result) {

// Called whenever the API client fails to connect.


Log.i(TAG, "GoogleApiClient connection failed:" + result.toString());

if (!result.hasResolution()) {

// show the localized error dialog.


GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(),
0).show();
return;
}

/**
* 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 {

result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);

https://riptutorial.com/ 596
} catch (SendIntentException e) {

Log.e(TAG, "Exception while starting resolution activity", e);


}
}

/**
* It invoked when Google API client connected
* @param connectionHint
*/
@Override
public void onConnected(Bundle connectionHint) {

Toast.makeText(getApplicationContext(), "Connected", Toast.LENGTH_LONG).show();


}

/**
* It invoked when connection suspended
* @param cause
*/
@Override
public void onConnectionSuspended(int cause) {

Log.i(TAG, "GoogleApiClient connection suspended");


}

Create a File on Google Drive

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.

public void CreateMyFile(){


fileOperation = true;
// Create new contents resource.
Drive.DriveApi.newDriveContents(mGoogleApiClient)
.setResultCallback(driveContentsCallback);
}

Result Handler of DriveContents


Handling the response requires to check if the call was successful or not. If the call was
successful, we can retrieve the DriveContents resource.

We will create a result handler of DriveContents. Within this method, we call the

https://riptutorial.com/ 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 (result.getStatus().isSuccess()) {
if (fileOperation == true){
CreateFileOnGoogleDrive(result);
}
}
}
};

Create File Programmatically


To create files, we need to use a MetadataChangeSet object. By using this object, we set the title (file
name) and file type. Also, we must use the createFile() method of the DriveFolder class and pass
the Google client API, the MetaDataChangeSet object, and the driveContents to create a file. We call
the result handler callback to handle the result of the created file.

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){

final DriveContents driveContents = result.getDriveContents();

// Perform I/O off the UI thread.


new Thread() {
@Override
public void run() {
// Write content to DriveContents.
OutputStream outputStream = driveContents.getOutputStream();
Writer writer = new OutputStreamWriter(outputStream);
try {
writer.write("Hello Christlin!");
writer.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}

MetadataChangeSet changeSet = new MetadataChangeSet.Builder()


.setTitle("My First Drive File")
.setMimeType("text/plain")
.setStarred(true).build();

// Create a file in the root folder.


Drive.DriveApi.getRootFolder(mGoogleApiClient)

https://riptutorial.com/ 598
.createFile(mGoogleApiClient, changeSet, driveContents)
setResultCallback(fileCallback);
}
}.start();
}

Handle result of Created File


The following code will create a callback method to handle the result of the created file:

/**
* Handle result of Created file
*/
final private ResultCallback<DriveFolder.DriveFileResult> fileCallback = new
ResultCallback<DriveFolder.DriveFileResult>() {
@Override
public void onResult(DriveFolder.DriveFileResult result) {
if (result.getStatus().isSuccess()) {
Toast.makeText(getApplicationContext(), "file created: "+
result.getDriveFile().getDriveId(), Toast.LENGTH_LONG).show();
}
return;
}
};

Read Google Drive API online: https://riptutorial.com/android/topic/10646/google-drive-api

https://riptutorial.com/ 599
Chapter 118: Google Maps API v2 for Android
Parameters

Parameter Details

GoogleMap the GoogleMap is an object that is received on a onMapReady() event

MarkerOptions is the builder class of a Marker, and is used to add one marker
MarkerOptions
to a map.

Remarks
Requirements

1. Google Play Services SDK installed.


2. A Google Console Account.
3. A Google Maps API Key obtained in Google Console.

Examples
Default Google Map Activity

This Activity code will provide basic functionality for including a Google Map using a
SupportMapFragment.

The Google Maps V2 API includes an all-new way to load maps.

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.

MapsActivity.java:

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {

private GoogleMap mMap;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);

https://riptutorial.com/ 600
}

@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;

// Add a marker in Sydney, Australia, and move the camera.


LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}
}

Notice that the code above inflates a layout, which has a SupportMapFragment nested inside the
container Layout, defined with an ID of R.id.map. The layout file is shown below:

activity_maps.xml

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/map"
tools:context="com.example.app.MapsActivity"
android:name="com.google.android.gms.maps.SupportMapFragment"/>

</LinearLayout>

Custom Google Map Styles

Map Style

Google Maps come with a set of different styles to be applied, using this code :

// Sets the map type to be "hybrid"


map.setMapType(GoogleMap.MAP_TYPE_HYBRID);

The different map styles are :

Normal

map.setMapType(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.

https://riptutorial.com/ 601
Hybrid

map.setMapType(GoogleMap.MAP_TYPE_HYBRID);

Satellite photograph data with road maps added. Road and feature labels are also visible.

https://riptutorial.com/ 602
Satellite

map.setMapType(GoogleMap.MAP_TYPE_SATELLITE);

Satellite photograph data. Road and feature labels are not visible.

https://riptutorial.com/ 603
Terrain

map.setMapType(GoogleMap.MAP_TYPE_TERRAIN);

Topographic data. The map includes colors, contour lines and labels, and perspective shading.
Some roads and labels are also visible.

https://riptutorial.com/ 604
None

map.setMapType(GoogleMap.MAP_TYPE_NONE);

No tiles. The map will be rendered as an empty grid with no tiles loaded.

https://riptutorial.com/ 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.

to enable or disable indoor maps, this is how it's done :

GoogleMap.setIndoorEnabled(true).
GoogleMap.setIndoorEnabled(false).

We can add custom styles to maps.

In onMapReady method add the following code snippet

mMap = googleMap;
try {
// Customise the styling of the base map using a JSON object defined
// in a raw resource file.
boolean success = mMap.setMapStyle(
MapStyleOptions.loadRawResourceStyle(
MapsActivity.this, R.raw.style_json));

https://riptutorial.com/ 606
if (!success) {
Log.e(TAG, "Style parsing failed.");
}
} catch (Resources.NotFoundException e) {
Log.e(TAG, "Can't find style.", e);
}

under res folder create a folder name raw and add the styles json file. Sample style.json file

[
{
"featureType": "all",
"elementType": "geometry",
"stylers": [
{
"color": "#242f3e"
}
]
},
{
"featureType": "all",
"elementType": "labels.text.stroke",
"stylers": [
{
"lightness": -80
}
]
},
{
"featureType": "administrative",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#746855"
}
]
},
{
"featureType": "administrative.locality",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#d59563"
}
]
},
{
"featureType": "poi",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#d59563"
}
]
},
{
"featureType": "poi.park",
"elementType": "geometry",
"stylers": [
{

https://riptutorial.com/ 607
"color": "#263c3f"
}
]
},
{
"featureType": "poi.park",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#6b9a76"
}
]
},
{
"featureType": "road",
"elementType": "geometry.fill",
"stylers": [
{
"color": "#2b3544"
}
]
},
{
"featureType": "road",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#9ca5b3"
}
]
},
{
"featureType": "road.arterial",
"elementType": "geometry.fill",
"stylers": [
{
"color": "#38414e"
}
]
},
{
"featureType": "road.arterial",
"elementType": "geometry.stroke",
"stylers": [
{
"color": "#212a37"
}
]
},
{
"featureType": "road.highway",
"elementType": "geometry.fill",
"stylers": [
{
"color": "#746855"
}
]
},
{
"featureType": "road.highway",
"elementType": "geometry.stroke",

https://riptutorial.com/ 608
"stylers": [
{
"color": "#1f2835"
}
]
},
{
"featureType": "road.highway",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#f3d19c"
}
]
},
{
"featureType": "road.local",
"elementType": "geometry.fill",
"stylers": [
{
"color": "#38414e"
}
]
},
{
"featureType": "road.local",
"elementType": "geometry.stroke",
"stylers": [
{
"color": "#212a37"
}
]
},
{
"featureType": "transit",
"elementType": "geometry",
"stylers": [
{
"color": "#2f3948"
}
]
},
{
"featureType": "transit.station",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#d59563"
}
]
},
{
"featureType": "water",
"elementType": "geometry",
"stylers": [
{
"color": "#17263c"
}
]
},
{

https://riptutorial.com/ 609
"featureType": "water",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#515c6d"
}
]
},
{
"featureType": "water",
"elementType": "labels.text.stroke",
"stylers": [
{
"lightness": -20
}
]
}
]

To generate styles json file click this link

https://riptutorial.com/ 610
https://riptutorial.com/ 611
Objects, we can do it this way.

The MyLocation holder class:

public class MyLocation {


LatLng latLng;
String title;
String snippet;
}

Here is a method that would take a list of MyLocation Objects and place a Marker for each one:

private void LocationsLoaded(List<MyLocation> locations){

for (MyLocation myLoc : locations){


mMap.addMarker(new MarkerOptions()
.position(myLoc.latLng)
.title(myLoc.title)
.snippet(myLoc.snippet)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
}
}

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.

MapView: embedding a GoogleMap in an existing layout

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.

In your layout use MapView as follows:

<com.google.android.gms.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
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

https://riptutorial.com/ 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 -->
/>

Your activity needs to implement the OnMapReadyCallback interface in order to work:

/**
* 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 {

private MapView mMapView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.raw_mapview_demo);

mMapView = (MapView) findViewById(R.id.map);


mMapView.onCreate(savedInstanceState);

mMapView.getMapAsync(this);
}

@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}

@Override
public void onMapReady(GoogleMap map) {
map.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}

@Override
protected void onPause() {
mMapView.onPause();
super.onPause();
}

@Override
protected void onDestroy() {
mMapView.onDestroy();
super.onDestroy();
}

@Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}

@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);

https://riptutorial.com/ 613
mMapView.onSaveInstanceState(outState);
}
}

Show Current Location in a Google Map

Here is a full Activity class that places a Marker at the current location, and also moves the
camera to the current position.

There are a few thing going on in sequence here:

• Check Location permission


• Once Location permission is granted, call setMyLocationEnabled(), build the GoogleApiClient,
and connect it
• Once the GoogleApiClient is connected, request location updates

public class MapLocationActivity extends AppCompatActivity


implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {

GoogleMap mGoogleMap;
SupportMapFragment mapFrag;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

getSupportActionBar().setTitle("Map Location Activity");

mapFrag = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);


mapFrag.getMapAsync(this);
}

@Override
public void onPause() {
super.onPause();

//stop location updates when Activity is no longer active


if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}

@Override
public void onMapReady(GoogleMap googleMap)
{
mGoogleMap=googleMap;
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);

https://riptutorial.com/ 614
//Initialize Google Play Services
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Location Permission already granted
buildGoogleApiClient();
mGoogleMap.setMyLocationEnabled(true);
} else {
//Request Location Permission
checkLocationPermission();
}
}
else {
buildGoogleApiClient();
mGoogleMap.setMyLocationEnabled(true);
}
}

protected synchronized void buildGoogleApiClient() {


mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}

@Override
public void onConnected(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(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) {
mCurrLocationMarker.remove();
}

//Place current location marker


LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Current Position");

https://riptutorial.com/ 615
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_M
AGENTA));
mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);

//move map camera


mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(11));

//stop location updates


if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}

public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;


private void checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation?


if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {

// Show an explanation to the user *asynchronously* -- don't block


// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
new AlertDialog.Builder(this)
.setTitle("Location Permission Needed")
.setMessage("This app needs the Location permission, please accept to
use location functionality")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(MapLocationActivity.this,
new
String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION );
}
})
.create()
.show();

} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.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 (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {

https://riptutorial.com/ 616
// permission was granted, yay! Do the
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {

if (mGoogleApiClient == null) {
buildGoogleApiClient();
}
mGoogleMap.setMyLocationEnabled(true);
}

} else {

// permission denied, boo! Disable the


// functionality that depends on this permission.
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
}
return;
}

// other 'case' lines to check for other


// permissions this app might request
}
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/map"
tools:context="com.example.app.MapLocationActivity"
android:name="com.google.android.gms.maps.SupportMapFragment"/>

</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):

https://riptutorial.com/ 617
Prompt the user for Location permission on Marshmallow and Nougat by calling
ActivityCompat.requestPermissions():

https://riptutorial.com/ 618
Move camera to current location and place Marker when the Location permission is granted:

https://riptutorial.com/ 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("com.package.name",
PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
MessageDigest md;
md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
String hash= new String(Base64.encode(md.digest(), 0));
Log.e("hash", hash);
}
} catch (NameNotFoundException e1) {
Log.e("name not found", e1.toString());
} catch (NoSuchAlgorithmException e) {
Log.e("no such an algorithm", e.toString());

https://riptutorial.com/ 620
} catch (Exception e) {
Log.e("exception", e.toString());
}

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.:

final MapView mapView = (MapView)view.findViewById(R.id.map);


mapView.setClickable(false);

UISettings

Using UISettings, the appearance of the Google Map can be modified.

Here is an example of some common settings:

mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mGoogleMap.getUiSettings().setMapToolbarEnabled(true);
mGoogleMap.getUiSettings().setZoomControlsEnabled(true);
mGoogleMap.getUiSettings().setCompassEnabled(true);

Result:

https://riptutorial.com/ 621
Get debug SHA1 fingerprint

1. Open Android Studio


2. Open Your Project
3. Click on Gradle (From Right Side Panel, you will see Gradle Bar)
4. Click on Refresh (Click on Refresh from Gradle Bar, you will see List Gradle scripts of your
Project)
5. Click on Your Project (Your Project Name form List (root))
6. Click on Tasks
7. Click on android
8. Double Click on signingReport (You will get SHA1 and MD5 in Run Bar)

https://riptutorial.com/ 622
InfoWindow Click Listener

Here is an example of how to define a different action for each Marker's InfoWindow click event.

https://riptutorial.com/ 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.

Declare the HashMap as an instance variable of the Activity or Fragment:

//Declare HashMap to store mapping of marker to Activity


HashMap<String, String> markerMap = new HashMap<String, String>();

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:

Marker markerOne = googleMap.addMarker(new MarkerOptions().position(latLng1)


.title("Marker One")
.snippet("This is Marker One");
String idOne = markerOne.getId();
markerMap.put(idOne, "action_one");

Marker markerTwo = googleMap.addMarker(new MarkerOptions().position(latLng2)


.title("Marker Two")
.snippet("This is Marker Two");
String idTwo = markerTwo.getId();
markerMap.put(idTwo, "action_two");

In the InfoWindow click listener, get the action from the HashMap, and open up the corresponding
Activity based on the action of the Marker:

mGoogleMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick(Marker marker) {

String actionId = markerMap.get(marker.getId());

if (actionId.equals("action_one")) {
Intent i = new Intent(MainActivity.this, ActivityOne.class);
startActivity(i);
} else if (actionId.equals("action_two")) {
Intent i = new Intent(MainActivity.this, ActivityTwo.class);
startActivity(i);
}
}
});

Note If the code is in a Fragment, replace MainActivity.this with getActivity().

Change Offset

https://riptutorial.com/ 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(location.getLatitude(),location.getLongitude());

public void changeOffsetCenter(double latitude,double longitude) {


Point mappoint = mGoogleMap.getProjection().toScreenLocation(new LatLng(latitude,
longitude));
mappoint.set(mappoint.x, mappoint.y-100); // change these values as you need ,
just hard coded a value if you want you can give it based on a ratio like using DisplayMetrics
as well

mGoogleMap.animateCamera(CameraUpdateFactory.newLatLng(mGoogleMap.getProjection().fromScreenLocation(ma

Read Google Maps API v2 for Android online: https://riptutorial.com/android/topic/170/google-


maps-api-v2-for-android

https://riptutorial.com/ 625
Chapter 119: Google Play Store
Examples
Open Google Play Store Listing for your app

The following code snippet shows how to open the Google Play Store Listing of your app in a safe
way. Usually you want to use it when asking the user to leave a review for your app.

private void openPlayStore() {


String packageName = getPackageName();
Intent playStoreIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse("market://details?id=" + packageName));
setFlags(playStoreIntent);
try {
startActivity(playStoreIntent);
} catch (Exception e) {
Intent webIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse("https://play.google.com/store/apps/details?id=" + packageName));
setFlags(webIntent);
startActivity(webIntent);
}
}

@SuppressWarnings("deprecation")
private void setFlags(Intent intent) {
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
else
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
}

Note: The code opens the Google Play Store if the app is installed. Otherwise it will just open the
web browser.

Open Google Play Store with the list of all applications from your publisher
account

You can add a "Browse Our Other Apps" button in your app, listing all your(publisher) applications
in the Google Play Store app.

String urlApp = "market://search?q=pub:Google+Inc.";


String urlWeb = "http://play.google.com/store/search?q=pub:Google+Inc.";
try {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(urlApp));
setFlags(i);
startActivity(i);
} catch (android.content.ActivityNotFoundException anfe) {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(urlWeb)));
setFlags(i);
startActivity(i);

https://riptutorial.com/ 626
}

@SuppressWarnings("deprecation")
public void setFlags(Intent i) {
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
i.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
}
else {
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
}
}

Read Google Play Store online: https://riptutorial.com/android/topic/10900/google-play-store

https://riptutorial.com/ 627
Chapter 120: Google signin integration on
android
Introduction
This topic is based on How to integrate google sign-in, On android apps

Examples
Integration of google Auth in your project. (Get a configuration file)

First get the Configuration File for Sign-in from

Open link below

[https://developers.google.com/identity/sign-in/android/start-integrating][1]

click on get A configuration file

• Enter App name And package name and click on choose and configure services
• provide SHA1 Enable google SIGNIN and generate configuration files

Download the configuration file and place the file in app/ folder of your project

1. Add the dependency to your project-level build.gradle:

classpath 'com.google.gms:google-services:3.0.0'

2. Add the plugin to your app-level build.gradle:(bottom)

apply plugin: 'com.google.gms.google-services'

3. add this dependency to your app gradle file

dependencies { compile 'com.google.android.gms:play-services-auth:9.8.0' }

Code Implementation Google SignIn

• In your sign-in activity's onCreate method, configure Google Sign-In to request the user data
required by your app.

GoogleSignInOptions gso = new


GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();

• create a GoogleApiClient object with access to the Google Sign-In API and the options you

https://riptutorial.com/ 628
specified.

mGoogleApiClient = new GoogleApiClient.Builder(this)


.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();

• Now When User click on Google signin button call this Function.

private void signIn() {


Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}

• implement OnActivityResult to get the response.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);


if (requestCode == RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
}
}

• Last step Handle The Result and get User Data

private void handleSignInResult(GoogleSignInResult result) {


Log.d(TAG, "handleSignInResult:" + result.isSuccess());
if (result.isSuccess()) {
// Signed in successfully, show authenticated UI.
GoogleSignInAccount acct = result.getSignInAccount();
mStatusTextView.setText(getString(R.string.signed_in_fmt, acct.getDisplayName()));
updateUI(true);
} else {
// Signed out, show unauthenticated UI.
updateUI(false);
}
}

Read Google signin integration on android online:


https://riptutorial.com/android/topic/9960/google-signin-integration-on-android

https://riptutorial.com/ 629
Chapter 121: Gradle for Android
Introduction
Gradle is a JVM-based build system that enables developers to write high-level scripts that can be
used to automate the process of compilation and application production. It is a flexible plugin-
based system, which allows you to automate various aspects of the build process; including
compiling and signing a .jar, downloading and managing external dependencies, injecting fields
into the AndroidManifest or utilising specific SDK versions.

Syntax
• apply plugin:The plugins which should been used normally just 'com.android.application' or
'com.android.library'.

• android: The main configuration of your app

○ compileSdkVersion: The compile SDK version


○ buildToolsVersion: The build tools version
○ defaultConfig: The default settings which can been overwritten by flavors and build
types
○ applicationId: The application id you use e.g. in the PlayStore mostly the same
as your package name
○ minSdkVersion: The minimal required SDK version
○ targetSdkVersion: The SDK version you compile against (should be always the
newst one)
○ versionCode: The internal version number which needs to be bigger on each
update
○ versionName: The version number the user can see in the app details page
○ buildTypes: See somewhere else (TODO)

• dependencies: The maven or local dependencies of your app

○ compile a single dependency


○ testCompile: a dependency for the unit or integration tests

Remarks
See also

• The official gradle homepage


• How to configure gradle builds
• The android plugin for gradle
• Android Gradle DSL

https://riptutorial.com/ 630
Gradle for Android - Extended documentation:
There is another tag where you can find more topics and examples about the use of gradle in
Android.
http://www.riptutorial.com/topic/2092

Examples
A basic build.gradle file

This is an example of a default build.gradle file in a module.

apply plugin: 'com.android.application'

android {
compileSdkVersion 25
buildToolsVersion '25.0.3'

signingConfigs {
applicationName {
keyAlias 'applicationName'
keyPassword 'password'
storeFile file('../key/applicationName.jks')
storePassword 'keystorePassword'
}
}
defaultConfig {
applicationId 'com.company.applicationName'
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName '1.0'
signingConfig signingConfigs.applicationName
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])

compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:design:25.3.1'

testCompile 'junit:junit:4.12'
}

DSL (domain-specific language)

https://riptutorial.com/ 631
Each block in the file above is called a DSL (domain-specific language).

Plugins
The first line, apply plugin: 'com.android.application', applies the Android plugin for Gradle to the
build and makes the android {} block available to declare Android-specific build options.

For an Android Application:

apply plugin: 'com.android.application'

For an Android Library:

apply plugin: 'com.android.library'

Understanding the DSLs in the sample above


The second part, The android {...} block, is the Android DSL which contains information about
your project.

For example, you can set the compileSdkVersion which specifies the Android API level , Which
should be used by Gradle to compile your app.
The sub-block defaultConfig holds the defaults for your manifest. You can override them with
Product Flavors.

You can find more info in these examples:

• DSL for the app module


• Build Types
• Product Flavors
• Signing settings

Dependencies
The dependencies block is defined outside the android block {...} : This means it's not defined by
the Android plugin but it's standard Gradle.
The dependencies block specifies what external libraries (typically Android libraries, but Java
libraries are also valid) you wish to include in your app. Gradle will automatically download these
dependencies for you (if there is no local copy available), you just need to add similar compile lines
when you wish to add another library.

Let's look at one of the lines present here:

https://riptutorial.com/ 632
compile 'com.android.support:design:25.3.1'

This line basically says

add a dependency on the Android support design library to my project.

Gradle will ensure that the library is downloaded and present so that you can use it in your app,
and its code will also be included in your app.

If you're familiar with Maven, this syntax is the GroupId, a colon, ArtifactId, another colon, then the
version of the dependency you wish to include, giving you full control over versioning.

While it is possible to specify artifact versions using the plus (+) sign, best practice is to avoid
doing so; it can lead to issues if the library gets updated with breaking changes without your
knowledge, which would likely lead to crashes in your app.

You can add different kind of dependencies:

• local binary dependencies


• module dependencies
• remote dependencies

A particular attention should be dedicated to the aar flat dependencies.

You can find more details in this topic.

Note about the -v7 in appcompat-v7

compile 'com.android.support:appcompat-v7:25.3.1'

This simply means that this library (appcompat) is compatible with the Android API level 7 and
forward.

Note about the junit:junit:4.12

This is Testing dependency for Unit testing.

Specifying dependencies specific to different


build configurations
You can specify that a dependency should only be used for a certain build configuration or you
can define different dependencies for the build types or the product flavors (e.g., debug, test or
release) by using debugCompile, testCompile or releaseCompile instead of the usual compile.

This is helpful for keeping test- and debug- related dependencies out of your release build, which
will keep your release APK as slim as possible and help to ensure that any debug information
cannot be used to obtain internal information about your app.

https://riptutorial.com/ 633
signingConfig
The signingConfig allows you to configure your Gradle to include keystore information and ensure
that the APK built using these configurations are signed and ready for Play Store release.

Here you can find a dedicated topic.

Note: It's not recommended though to keep the signing credentials inside your Gradle file. To
remove the signing configurations, just omit the signingConfigs portion.
You can specify them in different ways:

• storing in an external file


• storing them in setting environment variables.

See this topic for more details : Sign APK without exposing keystore password.

You can find further information about Gradle for Android in the dedicated Gradle topic.

Defining product flavors

Product flavors are defined in the build.gradle file inside the android { ... } block as seen below.

...
android {
...
productFlavors {
free {
applicationId "com.example.app.free"
versionName "1.0-free"
}
paid {
applicationId "com.example.app.paid"
versionName "1.0-paid"
}
}
}

By doing this, we now have two additional product flavors: free and paid. Each can have its own
specific configuration and attributes. For example, both of our new flavors has a separate
applicationId and versionName than our existing main flavor (available by default, so not shown
here).

Adding product flavor-specific dependencies

Dependencies can be added for a specific product flavor, similar to how they can be added for
specific build configurations.

For this example, assume that we have already defined two product flavors called free and paid
(more on defining flavors here).

https://riptutorial.com/ 634
We can then add the AdMob dependency for the free flavor, and the Picasso library for the paid
one like so:

android {
...

productFlavors {
free {
applicationId "com.example.app.free"
versionName "1.0-free"
}
paid {
applicationId "com.example.app.paid"
versionName "1.0-paid"
}
}
}

...
dependencies {
...
// Add AdMob only for free flavor
freeCompile 'com.android.support:appcompat-v7:23.1.1'
freeCompile 'com.google.android.gms:play-services-ads:8.4.0'
freeCompile 'com.android.support:support-v4:23.1.1'

// Add picasso only for paid flavor


paidCompile 'com.squareup.picasso:picasso:2.5.2'
}
...

Adding product flavor-specific resources

Resources can be added for a specific product flavor.

For this example, assume that we have already defined two product flavors called free and paid. In
order to add product flavor-specific resources, we create additional resource folders alongside the
main/res folder, which we can then add resources to like usual. For this example, we'll define a
string, status, for each product flavor:

/src/main/res/values/strings.xml

<resources>
<string name="status">Default</string>
</resources>

/src/free/res/values/strings.xml

<resources>
<string name="status">Free</string>
</resources>

/src/paid/res/values/strings.xml

https://riptutorial.com/ 635
<resources>
<string name="status">Paid</string>
</resources>

The product flavor-specific status strings will override the value for status in the main flavor.

Define and use Build Configuration Fields

BuildConfigField
Gradle allows buildConfigField lines to define constants. These constants will be accessible at
runtime as static fields of the BuildConfig class. This can be used to create flavors by defining all
fields within the defaultConfig block, then overriding them for individual build flavors as needed.

This example defines the build date and flags the build for production rather than test:

android {
...
defaultConfig {
...
// defining the build date
buildConfigField "long", "BUILD_DATE", System.currentTimeMillis() + "L"
// define whether this build is a production build
buildConfigField "boolean", "IS_PRODUCTION", "false"
// note that to define a string you need to escape it
buildConfigField "String", "API_KEY", "\"my_api_key\""
}

productFlavors {
prod {
// override the productive flag for the flavor "prod"
buildConfigField "boolean", "IS_PRODUCTION", "true"
resValue 'string', 'app_name', 'My App Name'
}
dev {
// inherit default fields
resValue 'string', 'app_name', 'My App Name - Dev'
}
}
}

The automatically-generated <package_name>.BuildConfig.java in the gen folder contains the


following fields based on the directive above:

public class BuildConfig {


// ... other generated fields ...
public static final long BUILD_DATE = 1469504547000L;
public static final boolean IS_PRODUCTION = false;
public static final String API_KEY = "my_api_key";
}

The defined fields can now be used within the app at runtime by accessing the generated
BuildConfig class:

https://riptutorial.com/ 636
public void example() {
// format the build date
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
String buildDate = dateFormat.format(new Date(BuildConfig.BUILD_DATE));
Log.d("build date", buildDate);

// do something depending whether this is a productive build


if (BuildConfig.IS_PRODUCTION) {
connectToProductionApiEndpoint();
} else {
connectToStagingApiEndpoint();
}
}

ResValue
The resValue in the productFlavors creates a resource value. It can be any type of resource (string,
dimen, color, etc.). This is similar to defining a resource in the appropriate file: e.g. defining string in
a strings.xml file. The advantage being that the one defined in gradle can be modified based on
your productFlavor/buildVariant. To access the value, write the same code as if you were
accessing a res from the resources file:

getResources().getString(R.string.app_name)

The important thing is that resources defined this way cannot modify existing resources defined in
files. They can only create new resource values.

Some libraries (such as the Google Maps Android API) require an API key provided in the
Manifest as a meta-data tag. If different keys are needed for debugging and production builds,
specify a manifest placeholder filled in by Gradle.

In your AndroidManifest.xml file:

<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}"/>

And then set the field accordingly in your build.gradle file:

android {
defaultConfig {
...
// Your development key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}

productFlavors {
prod {
// Your production key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
}

https://riptutorial.com/ 637
}

The Android build system generates a number of fields automatically and places them in
BuildConfig.java. These fields are:

Field Description

DEBUG a Boolean stating if the app is in debug or release mode

APPLICATION_ID a String containing the ID of the application (e.g. com.example.app)

a String containing the build type of the application (usually either debug or
BUILD_TYPE
release)

FLAVOR a String containing the particular flavor of the build

an int containing the version (build) number.


VERSION_CODE This is the same as versionCode in build.gradle or versionCode in
AndroidManifest.xml

a String containing the version (build) name.


VERSION_NAME This is the same as versionName in build.gradle or versionName in
AndroidManifest.xml

In addition to the above, if you have defined multiple dimensions of flavor then each dimension will
have its own value. For example, if you had two dimensions of flavor for color and size you will
also have the following variables:

Field Description

FLAVOR_color a String containing the value for the 'color' flavor.

FLAVOR_size a String containing the value for the 'size' flavor.

Centralizing dependencies via "dependencies.gradle" file

When working with multi-module projects, it is helpful to centralize dependencies in a single


location rather than having them spread across many build files, especially for common libraries
such as the Android support libraries and the Firebase libraries.

One recommended way is to separate the Gradle build files, with one build.gradle per module, as
well as one in the project root and another one for the dependencies, for example:

root
+- gradleScript/
| dependencies.gradle
+- module1/
| build.gradle
+- module2/

https://riptutorial.com/ 638
| build.gradle
+- build.gradle

Then, all of your dependencies can be located in gradleScript/dependencies.gradle:

ext {
// Version
supportVersion = '24.1.0'

// Support Libraries dependencies


supportDependencies = [
design: "com.android.support:design:${supportVersion}",
recyclerView: "com.android.support:recyclerview-v7:${supportVersion}",
cardView: "com.android.support:cardview-v7:${supportVersion}",
appCompat: "com.android.support:appcompat-v7:${supportVersion}",
supportAnnotation: "com.android.support:support-annotations:${supportVersion}",
]

firebaseVersion = '9.2.0';

firebaseDependencies = [
core: "com.google.firebase:firebase-core:${firebaseVersion}",
database: "com.google.firebase:firebase-database:${firebaseVersion}",
storage: "com.google.firebase:firebase-storage:${firebaseVersion}",
crash: "com.google.firebase:firebase-crash:${firebaseVersion}",
auth: "com.google.firebase:firebase-auth:${firebaseVersion}",
messaging: "com.google.firebase:firebase-messaging:${firebaseVersion}",
remoteConfig: "com.google.firebase:firebase-config:${firebaseVersion}",
invites: "com.google.firebase:firebase-invites:${firebaseVersion}",
adMod: "com.google.firebase:firebase-ads:${firebaseVersion}",
appIndexing: "com.google.android.gms:play-services-
appindexing:${firebaseVersion}",
];
}

Which can then be applied from that file in the top level file build.gradle like so:

// Load dependencies
apply from: 'gradleScript/dependencies.gradle'

and in the module1/build.gradle like so:

// Module build file


dependencies {
// ...
compile supportDependencies.appCompat
compile supportDependencies.design
compile firebaseDependencies.crash
}

Another approach
A less verbose approach for centralizing library dependencies versions can be achieved by
declaring the version number as a variable once, and using it everywhere.

https://riptutorial.com/ 639
In the workspace root build.gradle add this:

ext.v = [
supportVersion:'24.1.1',
]

And in every module that uses the same library add the needed libraries

compile "com.android.support:support-v4:${v.supportVersion}"
compile "com.android.support:recyclerview-v7:${v.supportVersion}"
compile "com.android.support:design:${v.supportVersion}"
compile "com.android.support:support-annotations:${v.supportVersion}"

Directory structure for flavor-specific resources

Different flavors of application builds can contain different resources. To create a flavor-specific
resource make a directory with the lower-case name of your flavor in the src directory and add
your resources in the same way you would normally.

For example, if you had a flavour Development and wanted to provide a distinct launcher icon for it
you would create a directory src/development/res/drawable-mdpi and inside that directory create an
ic_launcher.png file with your development-specific icon.

The directory structure will look like this:

src/
main/
res/
drawable-mdpi/
ic_launcher.png <-- the default launcher icon
development/
res/
drawable-mdpi/
ic_launcher.png <-- the launcher icon used when the product flavor is 'Development'

(Of course, in this case you would also create icons for drawable-hdpi, drawable-xhdpi etc).

Why are there two build.gradle files in an Android Studio project?

<PROJECT_ROOT>\app\build.gradle is specific for app module.

<PROJECT_ROOT>\build.gradleis a "Top-level build file" where you can add configuration options
common to all sub-projects/modules.

If you use another module in your project, as a local library you would have another build.gradle
file: <PROJECT_ROOT>\module\build.gradle

In the top level file you can specify common properties as the buildscript block or some common
properties.

buildscript {

https://riptutorial.com/ 640
repositories {
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.google.gms:google-services:3.0.0'
}
}

ext {
compileSdkVersion = 23
buildToolsVersion = "23.0.1"
}

In the app\build.gradle you define only the properties for the module:

apply plugin: 'com.android.application'

android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}

dependencies {
//.....
}

Executing a shell script from gradle

A shell script is a very versatile way to extend your build to basically anything you can think of.

As an exmaple, here is a simple script to compile protobuf files and add the result java files to the
source directory for further compilation:

def compilePb() {
exec {
// NOTICE: gradle will fail if there's an error in the protoc file...
executable "../pbScript.sh"
}
}

project.afterEvaluate {
compilePb()
}

The 'pbScript.sh' shell script for this example, located in the project's root folder:

#!/usr/bin/env bash
pp=/home/myself/my/proto

/usr/local/bin/protoc -I=$pp \
--java_out=./src/main/java \
--proto_path=$pp \
$pp/my.proto \

https://riptutorial.com/ 641
--proto_path=$pp \
$pp/my_other.proto

Debugging your Gradle errors

The following is an excerpt from Gradle - What is a non-zero exit value and how do I fix it?, see it
for the full discussion.

Let's say you are developing an application and you get some Gradle error that appears that
generally will look like so.

:module:someTask FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':module:someTask'.
> some message here... finished with non-zero exit value X
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get
more log output.
BUILD FAILED
Total time: Y.ZZ secs

You search here on StackOverflow for your problem, and people say to clean and rebuild your
project, or enable MultiDex, and when you try that, it just isn't fixing the problem.

There are ways to get more information, but the Gradle output itself should point at the actual error
in the few lines above that message between :module:someTask FAILED and the last
:module:someOtherTask that passed. Therefore, if you ask a question about your error, please edit
your questions to include more context to the error.

So, you get a "non-zero exit value." Well, that number is a good indicator of what you should try to
fix. Here are a few occur most frequently.

• 1 is a just a general error code and the error is likely in the Gradle output
• 2 seems to be related to overlapping dependencies or project misconfiguration.
• 3 seems to be from including too many dependencies, or a memory issue.

The general solutions for the above (after attempting a Clean and Rebuild of the project) are:

• 1- Address the error that is mentioned. Generally, this is a compile-time error, meaning
some piece of code in your project is not valid. This includes both XML and Java for an
Android project.
• 2 & 3 - Many answers here tell you to enable multidex. While it may fix the problem, it is most
likely a workaround. If you don't understand why you are using it (see the link), you probably
don't need it. General solutions involve cutting back your overuse of library dependencies
(such as all of Google Play Services, when you only need to use one library, like Maps or
Sign-In, for example).

Specifying different application IDs for build types and product flavors

https://riptutorial.com/ 642
You can specify different application IDs or package names for each buildType or productFlavor
using the applicationIdSuffix configuration attribute:

Example of suffixing the applicationId for each buildType:

defaultConfig {
applicationId "com.package.android"
minSdkVersion 17
targetSdkVersion 23
versionCode 1
versionName "1.0"
}

buildTypes {
release {
debuggable false
}

development {
debuggable true
applicationIdSuffix ".dev"
}

testing {
debuggable true
applicationIdSuffix ".qa"
}
}

Our resulting applicationIds would now be:

• com.package.android for release


• com.package.android.dev for development
• com.package.android.qa for testing

This can be done for productFlavors as well:

productFlavors {
free {
applicationIdSuffix ".free"
}
paid {
applicationIdSuffix ".paid"
}
}

The resulting applicationIds would be:

• com.package.android.free for the free flavor


• com.package.android.paid for the paid flavor

Sign APK without exposing keystore password

You can define the signing configuration to sign the apk in the build.gradle file using these
properties:

https://riptutorial.com/ 643
• storeFile : the keystore file
• storePassword: the keystore password
• keyAlias: a key alias name
• keyPassword: A key alias password

In many case you may need to avoid this kind of info in the build.gradle file.

Method A: Configure release signing using a


keystore.properties file
It's possible to configure your app's build.gradle so that it will read your signing configuration
information from a properties file like keystore.properties.

Setting up signing like this is beneficial because:

• Your signing configuration information is separate from your build.gradle file


• You do not have to intervene during the signing process in order to provide passwords for
your keystore file
• You can easily exclude the keystore.properties file from version control

First, create a file called keystore.properties in the root of your project with content like this
(replacing the values with your own):

storeFile=keystore.jks
storePassword=storePassword
keyAlias=keyAlias
keyPassword=keyPassword

Now, in your app's build.gradle file, set up the signingConfigs block as follows:

android {
...

signingConfigs {
release {
def propsFile = rootProject.file('keystore.properties')
if (propsFile.exists()) {
def props = new Properties()
props.load(new FileInputStream(propsFile))
storeFile = file(props['storeFile'])
storePassword = props['storePassword']
keyAlias = props['keyAlias']
keyPassword = props['keyPassword']
}
}
}
}

That's really all there is to it, but don't forget to exclude both your keystore file and your

https://riptutorial.com/ 644
keystore.properties file from version control.

A couple of things to note:

• The storeFile path specified in the keystore.properties file should be relative to your app's
build.gradle file. This example assumes that the keystore file is in the same directory as the
app's build.gradle file.
• This example has the keystore.properties file in the root of the project. If you put it
somewhere else, be sure to change the value in rootProject.file('keystore.properties') to
the location of yours, relative to the root of your project.

Method B: By using an environment variable


The same can be achieved also without a properties file, making the password harder to find:

android {

signingConfigs {
release {
storeFile file('/your/keystore/location/key')
keyAlias 'your_alias'
String ps = System.getenv("ps")
if (ps == null) {
throw new GradleException('missing ps env variable')
}
keyPassword ps
storePassword ps
}
}

The "ps" environment variable can be global, but a safer approach can be by adding it to the shell
of Android Studio only.
In linux this can be done by editing Android Studio's Desktop Entry

Exec=sh -c "export ps=myPassword123 ; /path/to/studio.sh"

You can find more details in this topic.

Versioning your builds via "version.properties" file

You can use Gradle to auto-increment your package version each time you build it. To do so
create a version.properties file in the same directory as your build.gradle with the following
contents:

VERSION_MAJOR=0
VERSION_MINOR=1
VERSION_BUILD=1

(Changing the values for major and minor as you see fit). Then in your build.gradle add the

https://riptutorial.com/ 645
following code to the android section:

// Read version information from local file and increment as appropriate


def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()

versionProps.load(new FileInputStream(versionPropsFile))

def versionMajor = versionProps['VERSION_MAJOR'].toInteger()


def versionMinor = versionProps['VERSION_MINOR'].toInteger()
def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1

// Update the build number in the local file


versionProps['VERSION_BUILD'] = versionBuild.toString()
versionProps.store(versionPropsFile.newWriter(), null)

defaultConfig {
versionCode versionBuild
versionName "${versionMajor}.${versionMinor}." + String.format("%05d", versionBuild)
}
}

The information can be accessed in Java as a string BuildConfig.VERSION_NAME for the complete
{major}.{minor}.{build} number and as an integer BuildConfig.VERSION_CODE for just the build
number.

Changing output apk name and add version name:

This is the code for changing output application file name (.apk). The name can be configured by
assigning a different value to newName

android {

applicationVariants.all { variant ->


def newName = "ApkName";
variant.outputs.each { output ->
def apk = output.outputFile;

newName += "-v" + defaultConfig.versionName;


if (variant.buildType.name == "release") {
newName += "-release.apk";
} else {
newName += ".apk";
}
if (!output.zipAlign) {
newName = newName.replace(".apk", "-unaligned.apk");
}

output.outputFile = new File(apk.parentFile, newName);


logger.info("INFO: Set outputFile to "
+ output.outputFile
+ " for [" + output.name + "]");
}
}
}

https://riptutorial.com/ 646
Disable image compression for a smaller APK file size

If you are optimizing all images manually, disable APT Cruncher for a smaller APK file size.

android {

aaptOptions {
cruncherEnabled = false
}
}

Enable Proguard using gradle

For enabling Proguard configurations for your application you need to enable it in your module-
level gradle file. You need to set the value of minifyEnabled to true.

buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

The above code will apply your Proguard configurations contained in the default Android SDK
combined with the "proguard-rules.pro" file on your module to your released apk.

Enable experimental NDK plugin support for Gradle and AndroidStudio

Enable and configure the experimental Gradle plugin to improve AndroidStudio's NDK support.
Check that you fulfill the following requirements:

• Gradle 2.10 (for this example)


• Android NDK r10 or later
• Android SDK with build tools v19.0.0 or later

Configure MyApp/build.gradle file


Edit the dependencies.classpath line in build.gradle from e.g.

classpath 'com.android.tools.build:gradle:2.1.2'

to

classpath 'com.android.tools.build:gradle-experimental:0.7.2'

(v0.7.2 was the latest version at the time of writing. Check the latest version yourself and adapt
your line accordingly)

https://riptutorial.com/ 647
The build.gradle file should look similar to this:

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
}
}

allprojects {
repositories {
jcenter()
}
}

task clean(type: Delete) {


delete rootProject.buildDir
}

Configure MyApp/app/build.gradle file


Edit the build.gradle file to look similar to the following example. Your version numbers may look
different.

apply plugin: 'com.android.model.application'

model {
android {
compileSdkVersion 19
buildToolsVersion "24.0.1"

defaultConfig {
applicationId "com.example.mydomain.myapp"
minSdkVersion.apiLevel 19
targetSdkVersion.apiLevel 19
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-android.txt'))
}
}
ndk {
moduleName "myLib"

/* The following lines are examples of a some optional flags that


you may set to configure your build environment
*/
cppFlags.add("-I${file("path/to/my/includes/dir")}".toString())
cppFlags.add("-std=c++11")
ldLibs.addAll(['log', 'm'])
stl = "c++_static"
abiFilters.add("armeabi-v7a")

https://riptutorial.com/ 648
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}

Sync and check that there are no errors in the Gradle files before proceeding.

Test if plugin is enabled


First make sure you have downloaded the Android NDK module. Then create an new app in
AndroidStudio and add the following to the ActivityMain file:

public class MainActivity implements Activity {


onCreate() {
// Pregenerated code. Not important here
}
static {
System.loadLibrary("myLib");
}
public static native String getString();
}

The getString() part should be highlighted red saying that the corresponding JNI function could
not be found. Hover your mouse over the function call until a red lightbulb appears. Click the bulb
and select create function JNI_.... This should generate a myLib.c file in the
myApp/app/src/main/jni directory with the correct JNI function call. It should look similar to this:

#include <jni.h>

JNIEXPORT jstring JNICALL


Java_com_example_mydomain_myapp_MainActivity_getString(JNIEnv *env, jobject instance)
{
// TODO

return (*env)->NewStringUTF(env, returnValue);


}

If it doesn't look like this, then the plugin has not correctly been configured or the NDK has not
been downloaded

Show all gradle project tasks

gradlew tasks -- show all tasks

Android tasks
-------------
androidDependencies - Displays the Android dependencies of the project.

https://riptutorial.com/ 649
signingReport - Displays the signing info for each variant.
sourceSets - Prints out all the source sets defined in this project.

Build tasks
-----------
assemble - Assembles all variants of all applications and secondary packages.
assembleAndroidTest - Assembles all the Test applications.
assembleDebug - Assembles all Debug builds.
assembleRelease - Assembles all Release builds.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
compileDebugAndroidTestSources
compileDebugSources
compileDebugUnitTestSources
compileReleaseSources
compileReleaseUnitTestSources
extractDebugAnnotations - Extracts Android annotations for the debug variant into the archive
file
extractReleaseAnnotations - Extracts Android annotations for the release variant into the
archive file
jar - Assembles a jar archive containing the main classes.
mockableAndroidJar - Creates a version of android.jar that's suitable for unit tests.
testClasses - Assembles test classes.

Build Setup tasks


-----------------
init - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]

Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.

Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project
'LeitnerBoxPro'.
components - Displays the components produced by root project 'LeitnerBoxPro'. [incubating]
dependencies - Displays all dependencies declared in root project 'LeitnerBoxPro'.
dependencyInsight - Displays the insight into a specific dependency in root project
'LeitnerBoxPro'.
help - Displays a help message.
model - Displays the configuration model of root project 'LeitnerBoxPro'. [incubating]
projects - Displays the sub-projects of root project 'LeitnerBoxPro'.
properties - Displays the properties of root project 'LeitnerBoxPro'.
tasks - Displays the tasks runnable from root project 'LeitnerBoxPro' (some of the displayed
tasks may belong to subprojects)
.

Install tasks
-------------
installDebug - Installs the Debug build.
installDebugAndroidTest - Installs the android (on device) tests for the Debug build.
uninstallAll - Uninstall all applications.
uninstallDebug - Uninstalls the Debug build.
uninstallDebugAndroidTest - Uninstalls the android (on device) tests for the Debug build.
uninstallRelease - Uninstalls the Release build.

https://riptutorial.com/ 650
Verification tasks
------------------
check - Runs all checks.
connectedAndroidTest - Installs and runs instrumentation tests for all flavors on connected
devices.
connectedCheck - Runs all device checks on currently connected devices.
connectedDebugAndroidTest - Installs and runs the tests for debug on connected devices.
deviceAndroidTest - Installs and runs instrumentation tests using all Device Providers.
deviceCheck - Runs all device checks using Device Providers and Test Servers.
lint - Runs lint on all variants.
lintDebug - Runs lint on the Debug build.
lintRelease - Runs lint on the Release build.
test - Run unit tests for all variants.
testDebugUnitTest - Run unit tests for the debug build.
testReleaseUnitTest - Run unit tests for the release build.

Other tasks
-----------
assembleDefault
clean
jarDebugClasses
jarReleaseClasses
transformResourcesWithMergeJavaResForDebugUnitTest
transformResourcesWithMergeJavaResForReleaseUnitTest

Delete "unaligned" apk automatically

If you don't need automatically generated apk files with unaligned suffix (which you probably don't),
you may add the following code to build.gradle file:

// delete unaligned files


android.applicationVariants.all { variant ->
variant.assemble.doLast {
variant.outputs.each { output ->
println "aligned " + output.outputFile
println "unaligned " + output.packageApplication.outputFile

File unaligned = output.packageApplication.outputFile;


File aligned = output.outputFile
if (!unaligned.getName().equalsIgnoreCase(aligned.getName())) {
println "deleting " + unaligned.getName()
unaligned.delete()
}
}
}
}

From here

Ignoring build variant

For some reasons you may want to ignore your build variants. For example: you have 'mock'
product flavour and you use it only for debug purposes, such as unit/instrumentation tests.

Let's ignore mockRelease variant from our project. Open build.gradle file and write:

https://riptutorial.com/ 651
// Remove mockRelease as it's not needed.
android.variantFilter { variant ->
if (variant.buildType.name.equals('release') &&
variant.getFlavors().get(0).name.equals('mock')) {
variant.setIgnore(true);
}
}

Seeing dependency tree

Use the task dependencies. Depending on how your modules are set up, it may be either
./gradlew dependencies or to see the dependencies of module app use ./gradlew :app:dependencies

The example following build.gradle file

dependencies {
compile 'com.android.support:design:23.2.1'
compile 'com.android.support:cardview-v7:23.1.1'

compile 'com.google.android.gms:play-services:6.5.87'
}

will produce the following graph:

Parallel execution is an incubating feature.


:app:dependencies

------------------------------------------------------------
Project :app
------------------------------------------------------------
. . .
_releaseApk - ## Internal use, do not manually configure ##
+--- com.android.support:design:23.2.1
| +--- com.android.support:support-v4:23.2.1
| | \--- com.android.support:support-annotations:23.2.1
| +--- com.android.support:appcompat-v7:23.2.1
| | +--- com.android.support:support-v4:23.2.1 (*)
| | +--- com.android.support:animated-vector-drawable:23.2.1
| | | \--- com.android.support:support-vector-drawable:23.2.1
| | | \--- com.android.support:support-v4:23.2.1 (*)
| | \--- com.android.support:support-vector-drawable:23.2.1 (*)
| \--- com.android.support:recyclerview-v7:23.2.1
| +--- com.android.support:support-v4:23.2.1 (*)
| \--- com.android.support:support-annotations:23.2.1
+--- com.android.support:cardview-v7:23.1.1
\--- com.google.android.gms:play-services:6.5.87
\--- com.android.support:support-v4:21.0.0 -> 23.2.1 (*)

. . .

Here you can see the project is directly including com.android.support:design version 23.2.1, which
itself is bringing com.android.support:support-v4 with version 23.2.1. However,
com.google.android.gms:play-services itself has a dependency on the same support-v4 but with an
older version 21.0.0, which is a conflict detected by gradle.

(*)

https://riptutorial.com/ 652
are used when gradle skips the subtree because those dependencies were already listed
previously.

Use gradle.properties for central versionnumber/buildconfigurations

You can define central config info's in

• a separate gradle include file Centralizing dependencies via "dependencies.gradle" file


• a stand alone properties file Versioning your builds via "version.properties" file

or do it with root gradle.properties file

the project structure

root
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
+- gradle.properties

global setting for all submodules in gradle.properties

# used for manifest


# todo increment for every release
appVersionCode=19
appVersionName=0.5.2.160726

# android tools settings


appCompileSdkVersion=23
appBuildToolsVersion=23.0.2

usage in a submodule

apply plugin: 'com.android.application'


android {
// appXXX are defined in gradle.properties
compileSdkVersion = Integer.valueOf(appCompileSdkVersion)
buildToolsVersion = appBuildToolsVersion

defaultConfig {
// appXXX are defined in gradle.properties
versionCode = Long.valueOf(appVersionCode)
versionName = appVersionName
}
}

dependencies {
...
}

Note: If you want to publish your app in the F-Droid app store you have to use magic numbers in
the gradle file because else f-droid robot cannot read current versionnumner to detect/verify

https://riptutorial.com/ 653
version changes.

Display signing information

In some circumstances (for example obtaining a Google API key) you need to find your keystore
fingerprint. Gradle has a convenient task that display all the signing information, including keystore
fingerprints:

./gradlew signingReport

This is a sample output:

:app:signingReport
Variant: release
Config: none
----------
Variant: debug
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: debugAndroidTest
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: debugUnitTest
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: releaseUnitTest
Config: none
----------

Defining build types

You can create and configure build types in the module-level build.gradle file inside the android {}
block.

android {
...
defaultConfig {...}

buildTypes {
release {

https://riptutorial.com/ 654
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-
rules.pro'
}

debug {
applicationIdSuffix ".debug"
}
}
}

Read Gradle for Android online: https://riptutorial.com/android/topic/95/gradle-for-android

https://riptutorial.com/ 655
Chapter 122: GreenDAO
Introduction
GreenDAO is an Object-Relational Mapping library to help developers use SQLite databases for
persistent local storage.

Examples
Helper methods for SELECT, INSERT, DELETE, UPDATE queries

This example shows a helper class that contains methods useful, when executing the queries for
data. Every method here uses Java Generic's in order to be very flexible.

public <T> List<T> selectElements(AbstractDao<T, ?> dao) {


if (dao == null) {
return null;
}
QueryBuilder<T> qb = dao.queryBuilder();
return qb.list();
}

public <T> void insertElements(AbstractDao<T, ?> absDao, List<T> items) {


if (items == null || items.size() == 0 || absDao == null) {
return;
}
absDao.insertOrReplaceInTx(items);
}

public <T> T insertElement(AbstractDao<T, ?> absDao, T item) {


if (item == null || absDao == null) {
return null;
}
absDao.insertOrReplaceInTx(item);
return item;
}

public <T> void updateElements(AbstractDao<T, ?> absDao, List<T> items) {


if (items == null || items.size() == 0 || absDao == null) {
return;
}
absDao.updateInTx(items);
}

public <T> T selectElementByCondition(AbstractDao<T, ?> absDao,


WhereCondition... conditions) {
if (absDao == null) {
return null;
}
QueryBuilder<T> qb = absDao.queryBuilder();
for (WhereCondition condition : conditions) {
qb = qb.where(condition);
}
List<T> items = qb.list();

https://riptutorial.com/ 656
return items != null && items.size() > 0 ? items.get(0) : null;
}

public <T> List<T> selectElementsByCondition(AbstractDao<T, ?> absDao,


WhereCondition... conditions) {
if (absDao == null) {
return null;
}
QueryBuilder<T> qb = absDao.queryBuilder();
for (WhereCondition condition : conditions) {
qb = qb.where(condition);
}
List<T> items = qb.list();
return items != null ? items : null;
}

public <T> List<T> selectElementsByConditionAndSort(AbstractDao<T, ?> absDao,


Property sortProperty,
String sortStrategy,
WhereCondition... conditions) {
if (absDao == null) {
return null;
}
QueryBuilder<T> qb = absDao.queryBuilder();
for (WhereCondition condition : conditions) {
qb = qb.where(condition);
}
qb.orderCustom(sortProperty, sortStrategy);
List<T> items = qb.list();
return items != null ? items : null;
}

public <T> List<T> selectElementsByConditionAndSortWithNullHandling(AbstractDao<T, ?> absDao,


Property sortProperty,
boolean handleNulls,
String sortStrategy,
WhereCondition...
conditions) {
if (!handleNulls) {
return selectElementsByConditionAndSort(absDao, sortProperty, sortStrategy,
conditions);
}
if (absDao == null) {
return null;
}
QueryBuilder<T> qb = absDao.queryBuilder();
for (WhereCondition condition : conditions) {
qb = qb.where(condition);
}
qb.orderRaw("(CASE WHEN " + "T." + sortProperty.columnName + " IS NULL then 1 ELSE 0
END)," + "T." + sortProperty.columnName + " " + sortStrategy);
List<T> items = qb.list();
return items != null ? items : null;
}

public <T, V extends Class> List<T> selectByJoin(AbstractDao<T, ?> absDao,


V className,
Property property, WhereCondition
whereCondition) {
QueryBuilder<T> qb = absDao.queryBuilder();
qb.join(className, property).where(whereCondition);

https://riptutorial.com/ 657
return qb.list();
}

public <T> void deleteElementsByCondition(AbstractDao<T, ?> absDao,


WhereCondition... conditions) {
if (absDao == null) {
return;
}
QueryBuilder<T> qb = absDao.queryBuilder();
for (WhereCondition condition : conditions) {
qb = qb.where(condition);
}
List<T> list = qb.list();
absDao.deleteInTx(list);
}

public <T> T deleteElement(DaoSession session, AbstractDao<T, ?> absDao, T object) {


if (absDao == null) {
return null;
}
absDao.delete(object);
session.clear();
return object;
}

public <T, V extends Class> void deleteByJoin(AbstractDao<T, ?> absDao,


V className,
Property property, WhereCondition
whereCondition) {
QueryBuilder<T> qb = absDao.queryBuilder();
qb.join(className, property).where(whereCondition);
qb.buildDelete().executeDeleteWithoutDetachingEntities();
}

public <T> void deleteAllFromTable(AbstractDao<T, ?> absDao) {


if (absDao == null) {
return;
}
absDao.deleteAll();
}

public <T> long countElements(AbstractDao<T, ?> absDao) {


if (absDao == null) {
return 0;
}
return absDao.count();
}

Creating an Entity with GreenDAO 3.X that has a Composite Primary Key

When creating a model for a table that has a composite primary key, additional work is required on
the Object for the model Entity to respect those constraints.

The following example SQL table and Entity demonstrates the structure to store a review left by a
customer for an item in an online store. In this example, we want the customer_id and item_id
columns to be a composite primary key, allowing only one review to exist between a specific
customer and item.

https://riptutorial.com/ 658
SQL Table

CREATE TABLE review (


customer_id STRING NOT NULL,
item_id STRING NOT NULL,
star_rating INTEGER NOT NULL,
content STRING,
PRIMARY KEY (customer_id, item_id)
);

Usually we would use the @Id and @Unique annotations above the respective fields in the entity
class, however for a composite primary key we do the following:

1. Add the @Index annotation inside the class-level @Entity annotation. The value property
contains a comma-delimited list of the fields that make up the key. Use the unique property
as shown to enforce uniqueness on the key.

2. GreenDAO requires every Entity have a long or Long object as a primary key. We still need to
add this to the Entity class, however we do not need to use it or worry about it affecting our
implementation. In the example below it is called localID

Entity

@Entity(indexes = { @Index(value = "customer_id,item_id", unique = true)})


public class Review {

@Id(autoincrement = true)
private Long localID;

private String customer_id;


private String item_id;

@NotNull
private Integer star_rating;

private String content;

public Review() {}
}

Getting started with GreenDao v3.X

After adding the GreenDao library dependency and Gradle plugin, we need to first create an entity
object.

Entity

An entity is a Plain Old Java Object (POJO) that models some data in the database. GreenDao
will use this class to create a table in the SQLite database and automatically generate helper
classes we can use to access and store data without having to write SQL statements.

@Entity
public class Users {

https://riptutorial.com/ 659
@Id(autoincrement = true)
private Long id;

private String firstname;


private String lastname;

@Unique
private String email;

// Getters and setters for the fields...

One-time GreenDao setup

Each time an application is launched GreenDao needs to be initialized. GreenDao suggests


keeping this code in an Application class or somewhere it will only be run once.

DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "mydatabase", null);


db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
DaoSession daoSession = daoMaster.newSession();

GreenDao Helper Classes

After the entity object is created, GreenDao automatically creates the helper classes used to
interact with the database. These are named similarly to the name of the entity object that was
created, followed by Dao and are retrieved from the daoSession object.

UsersDao usersDao = daoSession.getUsersDao();

Many typical database actions can now be performed using this Dao object with the entity object.

Query

String email = "[email protected]";


String firstname = "John";

// Single user query WHERE email matches "[email protected]"


Users user = userDao.queryBuilder()
.where(UsersDao.Properties.Email.eq(email)).build().unique();

// Multiple user query WHERE firstname = "John"


List<Users> user = userDao.queryBuilder()
.where(UsersDao.Properties.Firstname.eq(firstname)).build().list();

Insert

Users newUser = new User("John","Doe","[email protected]");


usersDao.insert(newUser);

Update

https://riptutorial.com/ 660
// Modify a previously retrieved user object and update
user.setLastname("Dole");
usersDao.update(user);

Delete

// Delete a previously retrieved user object


usersDao.delete(user);

Read GreenDAO online: https://riptutorial.com/android/topic/1345/greendao

https://riptutorial.com/ 661
Chapter 123: GreenRobot EventBus
Syntax
• @Subscribe(threadMode = ThreadMode.POSTING) public void onEvent(EventClass event) {
}

Parameters

Thread Mode Description

Will be called on the same thread that the event was posted on. This
ThreadMode.POSTING
is the default mode.

ThreadMode.MAIN Will be called on the main UI thread.

Will be called on a background thread. If the posting thread isn't the


ThreadMode.BACKGROUND main thread it will be used. If posted on the main thread EventBus has
a single background thread that it will use.

ThreadMode.ASYNC Will be called on its own thread.

Examples
Creating an Event object

For sending and receiving events we first need an Event object. Event objects are actually simple
POJOs.

public class ArbitaryEvent{


public static final int TYPE_1 = 1;
public static final int TYPE_2 = 2;
private int eventType;
public ArbitaryEvent(int eventType){
this.eventType = eventType;
}

public int getEventType(){


return eventType;
}
}

Receiving Events

For receiving events you need to register your class on the EventBus.

https://riptutorial.com/ 662
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}

@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}

And then subscribe to the events.

@Subscribe(threadMode = ThreadMode.MAIN)
public void handleEvent(ArbitaryEvent event) {
Toast.makeText(getActivity(), "Event type: "+event.getEventType(),
Toast.LENGTH_SHORT).show();
}

Sending Events

Sending events is as easy as creating the Event object and then posting it.

EventBus.getDefault().post(new ArbitaryEvent(ArbitaryEvent.TYPE_1));

Passing a Simple Event

The first thing we need to do it add EventBus to our module's gradle file:

dependencies {
...
compile 'org.greenrobot:eventbus:3.0.0'
...
}

Now we need to create a model for our event. It can contain anything we want to pass along. For
now we'll just make an empty class.

public class DeviceConnectedEvent


{
}

Now we can add the code to our Activity that will register with EventBus and subscribe to the
event.

public class MainActivity extends AppCompatActivity


{
private EventBus _eventBus;

@Override
protected void onCreate (Bundle savedInstanceState)

https://riptutorial.com/ 663
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

_eventBus = EventBus.getDefault();
}

@Override
protected void onStart ()
{
super.onStart();
_eventBus.register(this);
}

@Override
protected void onStop ()
{
_eventBus.unregister(this);
super.onStop();
}

@Subscribe(threadMode = ThreadMode.MAIN)
public void onDeviceConnected (final DeviceConnectedEvent event)
{
// Process event and update UI
}
}

In this Activity we get an instance of EventBus in the onCreate() method. We register / unregister
for events in onStart() / onStop(). It's important to remember to unregister when your listener loses
scope or you could leak your Activity.

Finally we define the method that we want called with the event. The @Subscribe annotation tells
EventBus which methods it can look for to handle events. You have to have at least one methods
annotated with @Subscribe to register with EventBus or it will throw an exception. In the annotation
we define the thread mode. This tells EventBus which thread to call the method on. It is a very
handy way of passing information from a background thread to the UI thread! That's exactly what
we're doing here. ThreadMode.MAIN means that this method will be called on Android's main UI
thread so it's safe to do any UI manipulations here that you need. The name of the method doesn't
matter. The only think, other that the @Subscribe annotation, that EventBus is looking for is the type
of the argument. As long as the type matches it will be called when an event is posted.

The last thing we need to do it to post an event. This code will be in our Service.

EventBus.getDefault().post(new DeviceConnectedEvent());

That's all there is to it! EventBus will take that DeviceConnectedEvent and look through its
registered listeners, look through the methods that they've subscribed and find the ones that take
a DeviceConnectedEvent as an argument and call them on the thread that they want to be called
on.

Read GreenRobot EventBus online: https://riptutorial.com/android/topic/3551/greenrobot-eventbus

https://riptutorial.com/ 664
Chapter 124: Gson
Introduction
Gson is a Java library that can be used to convert Java Objects into their JSON representation.
Gson considers both of these as very important design goals.

Gson Features:

Provide simple toJson() and fromJson() methods to convert Java objects to JSON and vice-versa

Allow pre-existing unmodifiable objects to be converted to and from JSON

Extensive support of Java Generics

Support arbitrarily complex objects (with deep inheritance hierarchies and extensive use of generic
types)

Syntax
• Excluder excluder()
• FieldNamingStrategy fieldNamingStrategy()
• <T> T fromJson(JsonElement json, Class<T> classOfT)
• <T> T fromJson(JsonElement json, Type typeOfT)
• <T> T fromJson(JsonReader reader, Type typeOfT)
• <T> T fromJson(Reader json, Class<T> classOfT)
• <T> T fromJson(Reader json, Type typeOfT)
• <T> T fromJson(String json, Class<T> classOfT)
• <T> T fromJson(String json, Type typeOfT)
• <T> TypeAdapter<T> getAdapter(Class<T> type)
• <T> TypeAdapter<T> getAdapter(TypeToken<T> type)
• <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T>
type)
• JsonReader newJsonReader(Reader reader)
• JsonWriter newJsonWriter(Writer writer)
• JsonElement toJsonTree(Object src)
• JsonElement toJsonTree(Object src, Type typeOfSrc)
• boolean serializeNulls()
• boolean htmlSafe()
• String toJson(JsonElement jsonElement)
• String toJson(Object src)
• String toJson(Object src, Type typeOfSrc)
• String toString()
• void toJson(Object src, Type typeOfSrc, Appendable writer)
• void toJson(Object src, Type typeOfSrc, JsonWriter writer)

https://riptutorial.com/ 665
• void toJson(JsonElement jsonElement, Appendable writer)
• void toJson(JsonElement jsonElement, JsonWriter writer)
• void toJson(Object src, Appendable writer)

Examples
Parsing JSON with Gson

The example shows parsing a JSON object using the Gson library from Google.

Parsing objects:

class Robot {
//OPTIONAL - this annotation allows for the key to be different from the field name, and
can be omitted if key and field name are same . Also this is good coding practice as it
decouple your variable names with server keys name
@SerializedName("version")
private String version;

@SerializedName("age")
private int age;

@SerializedName("robotName")
private String name;

// optional : Benefit it allows to set default values and retain them, even if key is
missing from Json response. Not required for primitive data types.

public Robot{
version = "";
name = "";
}

Then where parsing needs to occur, use the following:

String robotJson = "{


\"version\": \"JellyBean\",
\"age\": 3,
\"robotName\": \"Droid\"
}";

Gson gson = new Gson();


Robot robot = gson.fromJson(robotJson, Robot.class);

Parsing a list:

When retrieving a list of JSON objects, often you will want to parse them and convert them into
Java objects.

The JSON string that we will try to convert is the following:

https://riptutorial.com/ 666
{
"owned_dogs": [
{
"name": "Ron",
"age": 12,
"breed": "terrier"
},
{
"name": "Bob",
"age": 4,
"breed": "bulldog"
},
{
"name": "Johny",
"age": 3,
"breed": "golden retriever"
}
]
}

This particular JSON array contains three objects. In our Java code we'll want to map these
objects to Dog objects. A Dog object would look like this:

private class Dog {


public String name;
public int age;

@SerializedName("breed")
public String breedName;
}

To convert the JSON array to a Dog[]:

Dog[] arrayOfDogs = gson.fromJson(jsonArrayString, Dog[].class);

Converting a Dog[] to a JSON string:

String jsonArray = gson.toJson(arrayOfDogs, Dog[].class);

To convert the JSON array to an ArrayList<Dog> we can do the following:

Type typeListOfDogs = new TypeToken<List<Dog>>(){}.getType();


List<Dog> listOfDogs = gson.fromJson(jsonArrayString, typeListOfDogs);

The Type object typeListOfDogs defines what a list of Dog objects would look like. GSON can use
this type object to map the JSON array to the right values.

Alternatively, converting a List<Dog> to a JSON array can be done in a similar manner.

String jsonArray = gson.toJson(listOfDogs, typeListOfDogs);

Parsing JSON property to enum with Gson

https://riptutorial.com/ 667
If you want to parse a String to enum with Gson:

{"status" : "open"}

public enum Status {


@SerializedName("open")
OPEN,
@SerializedName("waiting")
WAITING,
@SerializedName("confirm")
CONFIRM,
@SerializedName("ready")
READY
}

Parsing a List with Gson

Method 1

Gson gson = new Gson();


String json = "[ \"Adam\", \"John\", \"Mary\" ]";

Type type = new TypeToken<List<String>>(){}.getType();


List<String> members = gson.fromJson(json, type);
Log.v("Members", members.toString());

This is useful for most generic container classes, since you can't get the class of a parameterized
type (ie: you can't call List<String>.class).

Method 2

public class StringList extends ArrayList<String> { }

...

List<String> members = gson.fromJson(json, StringList.class);

Alternatively, you can always subclass the type you want, and then pass in that class. However
this isn't always best practice, since it will return to you an object of type StringList;

JSON Serialization/Deserialization with AutoValue and Gson

Import in your gradle root file

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

Import in your gradle app file

apt 'com.google.auto.value:auto-value:1.2'
apt 'com.ryanharter.auto.value:auto-value-gson:0.3.1'
provided 'com.jakewharton.auto.value:auto-value-annotations:1.2-update1'
provided 'org.glassfish:javax.annotation:10.0-b28'

https://riptutorial.com/ 668
Create object with autovalue:

@AutoValue public abstract class SignIn {


@SerializedName("signin_token") public abstract String signinToken();
public abstract String username();

public static TypeAdapter<SignIn> typeAdapter(Gson gson) {


return new AutoValue_SignIn.GsonTypeAdapter(gson);
}

public static SignIn create(String signin, String username) {


return new AutoValue_SignIn(signin, username);
}
}

Create your Gson converter with your GsonBuilder

Gson gson = new GsonBuilder()


.registerTypeAdapterFactory(
new AutoValueGsonTypeAdapterFactory())
.create());

Deserialize

String myJsonData = "{


\"signin_token\": \"mySigninToken\",
\"username\": \"myUsername\" }";
SignIn signInData = gson.fromJson(myJsonData, Signin.class);

Serialize

Signin myData = SignIn.create("myTokenData", "myUsername");


String myJsonData = gson.toJson(myData);

Using Gson is a great way to simplify Serialization and Deserialization code by using POJO
objects. The side effect is that reflection is costly performance wise. That's why using AutoValue-
Gson to generate CustomTypeAdapter will avoid this reflection cost while staying very simple to
update when an api change is happening.

Parsing JSON to Generic Class Object with Gson

Suppose we have a JSON string

["first","second","third"]

We can parse this JSON string into a String array :

Gson gson = new Gson();


String jsonArray = "[\"first\",\"second\",\"third\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);

https://riptutorial.com/ 669
But if we want parse it into a List<String> object, we must use TypeToken.

Here is the sample :

Gson gson = new Gson();


String jsonArray = "[\"first\",\"second\",\"third\"]";
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>()
{}.getType());

Suppose we have two classes below:

public class Outer<T> {


public int index;
public T data;
}

public class Person {


public String firstName;
public String lastName;
}

and we have a JSON string that should be parsed to a Outer<Person> object.

This example shows how to parse this JSON string to the related generic class object:

String json = "......";


Type userType = new TypeToken<Outer<Person>>(){}.getType();
Result<User> userResult = gson.fromJson(json,userType);

If the JSON string should be parsed to a Outer<List<Person>> object :

Type userListType = new TypeToken<Outer<List<Person>>>(){}.getType();


Result<List<User>> userListResult = gson.fromJson(json,userListType);

Adding Gson to your project

dependencies {
compile 'com.google.code.gson:gson:2.8.1'
}

To use latest version of Gson

The below line will compile latest version of gson library everytime you compile, you do not have to
change version.

Pros: You can use latest features, speed and less bugs.
Cons: It might break compatibility with your code.

compile 'com.google.code.gson:gson:+'

https://riptutorial.com/ 670
Using Gson to load a JSON file from disk.

This will load a JSON file from disk and convert it to the given type.

public static <T> T getFile(String fileName, Class<T> type) throws FileNotFoundException {


Gson gson = new GsonBuilder()
.create();
FileReader json = new FileReader(fileName);
return gson.fromJson(json, type);
}

Adding a custom Converter to Gson

Sometimes you need to serialize or deserialize some fields in a desired format, for example your
backend may use the format "YYYY-MM-dd HH:mm" for dates and you want your POJOS to use
the DateTime class in Joda Time.

In order to automatically convert these strings into DateTimes object, you can use a custom
converter.

/**
* Gson serialiser/deserialiser for converting Joda {@link DateTime} objects.
*/
public class DateTimeConverter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime>
{

private final DateTimeFormatter dateTimeFormatter;

@Inject
public DateTimeConverter() {
this.dateTimeFormatter = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm");
}

@Override
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext
context) {
return new JsonPrimitive(dateTimeFormatter.print(src));
}

@Override
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext
context)
throws JsonParseException {

if (json.getAsString() == null || json.getAsString().isEmpty()) {


return null;
}

return dateTimeFormatter.parseDateTime(json.getAsString());
}
}

To make Gson use the newly created converter you need to assign it when creating the Gson
object:

https://riptutorial.com/ 671
DateTimeConverter dateTimeConverter = new DateTimeConverter();
Gson gson = new GsonBuilder().registerTypeAdapter(DateTime.class, dateTimeConverter)
.create();

String s = gson.toJson(DateTime.now());
// this will show the date in the desired format

In order to deserialize the date in that format you only have to define a field in the DateTime
format:

public class SomePojo {


private DateTime someDate;
}

When Gson encounters a field of type DateTime, it will call your converter in order to deserialize
the field.

Using Gson as serializer with Retrofit

First of all you need to add the GsonConverterFactory to your build.gradle file

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

Then, you have to add the converter factory when creating the Retrofit Service:

Gson gson = new GsonBuilder().create();


new Retrofit.Builder()
.baseUrl(someUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(RetrofitService.class);

You can add custom converters when creating the Gson object that you are passing to the factory.
Allowing you to create custom type conversions.

Parsing json array to generic class using Gson

Suppose we have a json

{
"total_count": 132,
"page_size": 2,
"page_index": 1,
"twitter_posts": [
{
"created_on": 1465935152,
"tweet_id": 210462857140252672,
"tweet": "Along with our new #Twitterbird, we've also updated our Display Guidelines",
"url": "https://twitter.com/twitterapi/status/210462857140252672"
},
{
"created_on": 1465995741,

https://riptutorial.com/ 672
"tweet_id": 735128881808691200,
"tweet": "Information on the upcoming changes to Tweets is now on the developer site",
"url": "https://twitter.com/twitterapi/status/735128881808691200"
}
]
}

We can parse this array into a Custom Tweets (tweets list container) object manually, but it is
easier to do it with fromJson method:

Gson gson = new Gson();


String jsonArray = "....";
Tweets tweets = gson.fromJson(jsonArray, Tweets.class);

Suppose we have two classes below:

class Tweets {
@SerializedName("total_count")
int totalCount;
@SerializedName("page_size")
int pageSize;
@SerializedName("page_index")
int pageIndex;
// all you need to do it is just define List variable with correct name
@SerializedName("twitter_posts")
List<Tweet> tweets;
}

class Tweet {
@SerializedName("created_on")
long createdOn;
@SerializedName("tweet_id")
String tweetId;
@SerializedName("tweet")
String tweetBody;
@SerializedName("url")
String url;
}

and if you need just parse a json array you can use this code in your parsing:

String tweetsJsonArray = "[{.....},{.....}]"


List<Tweet> tweets = gson.fromJson(tweetsJsonArray, new TypeToken<List<Tweet>>()
{}.getType());

Custom JSON Deserializer using Gson

Imagine you have all dates in all responses in some custom format, for instance
/Date(1465935152)/ and you want apply general rule to deserialize all Json dates to java Date
instances. In this case you need to implement custom Json Deserializer.

Example of json:

https://riptutorial.com/ 673
"id": 1,
"created_on": "Date(1465935152)",
"updated_on": "Date(1465968945)",
"name": "Oleksandr"
}

Suppose we have this class below:

class User {
@SerializedName("id")
long id;
@SerializedName("created_on")
Date createdOn;
@SerializedName("updated_on")
Date updatedOn;
@SerializedName("name")
String name;
}

Custom deserializer:

class DateDeSerializer implements JsonDeserializer<Date> {


private static final String DATE_PREFIX = "/Date(";
private static final String DATE_SUFFIX = ")/";

@Override
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext
context) throws JsonParseException {
String dateString = json.getAsString();
if (dateString.startsWith(DATE_PREFIX) && dateString.endsWith(DATE_SUFFIX)) {
dateString = dateString.substring(DATE_PREFIX.length(), dateString.length() -
DATE_SUFFIX.length());
} else {
throw new JsonParseException("Wrong date format: " + dateString);
}
return new Date(Long.parseLong(dateString) - TimeZone.getDefault().getRawOffset());
}
}

And the usage:

Gson gson = new GsonBuilder()


.registerTypeAdapter(Date.class, new DateDeSerializer())
.create();
String json = "....";
User user = gson.fromJson(json, User.class);

Serialize and deserialize Jackson JSON strings with Date types

This also applies to the case where you want to make Gson Date conversion compatible with
Jackson, for example.

Jackson usually serializes Date to "milliseconds since epoch" whereas Gson uses a readable
format like Aug 31, 2016 10:26:17 to represent Date. This leads to JsonSyntaxExceptions in Gson
when you try to deserialize a Jackson format Date.

https://riptutorial.com/ 674
To circumvent this, you can add a custom serializer and a custom deserializer:

JsonSerializer<Date> ser = new JsonSerializer<Date>() {


@Override
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext
context) {
return src == null ? null : new JsonPrimitive(src.getTime());
}
};

JsonDeserializer<Date> deser = new JsonDeserializer<Date>() {


@Override
public Date deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
return json == null ? null : new Date(json.getAsLong());
}
};

Gson gson = new GsonBuilder()


.registerTypeAdapter(Date.class, ser)
.registerTypeAdapter(Date.class, deser)
.create();

Using Gson with inheritance

Gson does not support inheritance out of the box.

Let's say we have the following class hierarchy:

public class BaseClass {


int a;

public int getInt() {


return a;
}
}

public class DerivedClass1 extends BaseClass {


int b;

@Override
public int getInt() {
return b;
}
}

public class DerivedClass2 extends BaseClass {


int c;

@Override
public int getInt() {
return c;
}
}

And now we want to serialize an instance of DerivedClass1 to a JSON string

https://riptutorial.com/ 675
DerivedClass1 derivedClass1 = new DerivedClass1();
derivedClass1.b = 5;
derivedClass1.a = 10;

Gson gson = new Gson();


String derivedClass1Json = gson.toJson(derivedClass1);

Now, in another place, we receive this json string and want to deserialize it - but in compile time
we only know it is supposed to be an instance of BaseClass:

BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);


System.out.println(maybeDerivedClass1.getInt());

But GSON does not know derivedClass1Json was originally an instance of DerivedClass1, so this will
print out 10.

How to solve this?

You need to build your own JsonDeserializer, that handles such cases. The solution is not
perfectly clean, but I could not come up with a better one.

First, add the following field to your base class

@SerializedName("type")
private String typeName;

And initialize it in the base class constructor

public BaseClass() {
typeName = getClass().getName();
}

Now add the following class:

public class JsonDeserializerWithInheritance<T> implements JsonDeserializer<T> {

@Override
public T deserialize(
JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
JsonPrimitive classNamePrimitive = (JsonPrimitive) jsonObject.get("type");

String className = classNamePrimitive.getAsString();

Class<?> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e.getMessage());
}
return context.deserialize(jsonObject, clazz);
}
}

https://riptutorial.com/ 676
All there is left to do is hook everything up -

GsonBuilder builder = new GsonBuilder();


builder
.registerTypeAdapter(BaseClass.class, new JsonDeserializerWithInheritance<BaseClass>());
Gson gson = builder.create();

And now, running the following code-

DerivedClass1 derivedClass1 = new DerivedClass1();


derivedClass1.b = 5;
derivedClass1.a = 10;
String derivedClass1Json = gson.toJson(derivedClass1);

BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);


System.out.println(maybeDerivedClass1.getInt());

Will print out 5.

Read Gson online: https://riptutorial.com/android/topic/4158/gson

https://riptutorial.com/ 677
Chapter 125: Handler
Remarks
A Handler can be easily used to execute code after a delayed amount of time. It is also useful for
executing code repeatedly after a specified amount of time by calling the Handler.postDelayed()
method again from within the Runnable's run() method.

Examples
Using a Handler to execute code after a delayed amount of time

Executing code after 1.5 seconds:

Handler handler = new Handler();


handler.postDelayed(new Runnable() {
@Override
public void run() {
//The code you want to run after the time is up
}
}, 1500); //the time you want to delay in milliseconds

Executing code repeatedly every 1 second:

Handler handler = new Handler();


handler.postDelayed(new Runnable() {
@Override
public void run() {
handler.postDelayed(this, 1000);
}
}, 1000); //the time you want to delay in milliseconds

HandlerThreads and communication between Threads

As Handlers are used to send Messages and Runnables to a Thread's message queue it's easy to
implement event based communication between multiple Threads. Every Thread that has a Looper
is able to receive and process messages. A HandlerThread is a Thread that implements such a
Looper, for example the main Thread (UI Thread) implements the features of a HandlerThread.

Creating a Handler for the current Thread

Handler handler = new Handler();

Creating a Handler for the main Thread (UI Thread)

https://riptutorial.com/ 678
Handler handler = new Handler(Looper.getMainLooper());

Send a Runnable from another Thread to the main Thread

new Thread(new Runnable() {


public void run() {
// this is executed on another Thread

// create a Handler associated with the main Thread


Handler handler = new Handler(Looper.getMainLooper());

// post a Runnable to the main Thread


handler.post(new Runnable() {
public void run() {
// this is executed on the main Thread
}
});
}
}).start();

Creating a Handler for another HandlerThread and sending


events to it

// create another Thread


HandlerThread otherThread = new HandlerThread("name");

// create a Handler associated with the other Thread


Handler handler = new Handler(otherThread.getLooper());

// post an event to the other Thread


handler.post(new Runnable() {
public void run() {
// this is executed on the other Thread
}
});

Stop handler from execution

To stop the Handler from execution remove the callback attached to it using the runnable running
inside it:

Runnable my_runnable = new Runnable() {


@Override
public void run() {
// your code here
}
};

public Handler handler = new Handler(); // use 'new Handler(Looper.getMainLooper());' if you


want this handler to control something in the UI
// to start the handler
public void start() {
handler.postDelayed(my_runnable, 10000);

https://riptutorial.com/ 679
}

// to stop the handler


public void stop() {
handler.removeCallbacks(my_runnable);
}

// to reset the handler


public void restart() {
handler.removeCallbacks(my_runnable);
handler.postDelayed(my_runnable, 10000);
}

Use Handler to create a Timer (similar to javax.swing.Timer)

This can be useful if you're writing a game or something that needs to execute a piece of code
every a few seconds.

import android.os.Handler;

public class Timer {


private Handler handler;
private boolean paused;

private int interval;

private Runnable task = new Runnable () {


@Override
public void run() {
if (!paused) {
runnable.run ();
Timer.this.handler.postDelayed (this, interval);
}
}
};

private Runnable runnable;

public int getInterval() {


return interval;
}

public void setInterval(int interval) {


this.interval = interval;
}

public void startTimer () {


paused = false;
handler.postDelayed (task, interval);
}

public void stopTimer () {


paused = true;
}

public Timer (Runnable runnable, int interval, boolean started) {


handler = new Handler ();
this.runnable = runnable;
this.interval = interval;

https://riptutorial.com/ 680
if (started)
startTimer ();
}
}

Example usage:

Timer timer = new Timer(new Runnable() {


public void run() {
System.out.println("Hello");
}
}, 1000, true)

This code will print "Hello" every second.

Read Handler online: https://riptutorial.com/android/topic/1425/handler

https://riptutorial.com/ 681
Chapter 126: Handling Deep Links
Introduction
Deep links are URLs that take users directly to specific content in your app. You can set up deep
links by adding intent filters and extracting data from incoming intents to drive users to the right
screen in your app.

Parameters

<data>
Details
Attribute

scheme The scheme part of a URI (case-sensitive). Examples: http, https, ftp

host The host part of a URI (case-sensitive). Examples: google.com, example.org

port The port part of a URI. Examples: 80, 443

path The path part of a URI. Must begin with /. Examples: /, /about

pathPrefix A prefix for the path part of a URI. Examples: /item, /article

pathPattern A pattern to match for the path part of a URI. Examples: /item/.*,
/article/[0-9]*

mimeType A mime type to match. Examples: image/jpeg, audio/*

Remarks

The <intent-filter>
This combination of <action> and <category> elements is what tells the Android system that a
specific Activity should be launched when the user clicks on a link in another application.

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data ... />

</intent-filter>

Multiple <data> tags

https://riptutorial.com/ 682
The set of deep links that your <intent-filter> supports is the cross-product of all the <data>
elements that you define in that intent-filter. The multiple domain, multiple path, and multiple
scheme examples demonstrate this.

Resources
• Enabling Deep Links for App Content (developer.android.com)
• <intent-filter> (developer.android.com

Examples
Simple deep link

AndroidManifest.xml:

<activity android:name="com.example.MainActivity" >

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="http"
android:host="www.example.com" />

</intent-filter>

</activity>

This will accept any link starting with http://www.example.com as a deep link to start your
MainActivity.

Multiple paths on a single domain

AndroidManifest.xml:

<activity android:name="com.example.MainActivity" >

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="http"
android:host="www.example.com" />

<data android:path="/" />


<data android:path="/about" />
<data android:path="/map" />

</intent-filter>

https://riptutorial.com/ 683
</activity>

This will launch your MainActivity when the user clicks any of these links:

• http://www.example.com/
• http://www.example.com/about
• http://www.example.com/map

Multiple domains and multiple paths

AndroidManifest.xml:

<activity android:name="com.example.MainActivity" >

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="http"
android:host="www.example.com" />

<data android:scheme="http"
android:host="www.example2.com" />

<data android:path="/" />


<data android:path="/map" />

</intent-filter>

</activity>

This will launch your MainActivity when the user clicks any of these links:

• http://www.example.com/
• http://www.example2.com/
• http://www.example.com/map
• http://www.example2.com/map

Both http and https for the same domain

AndroidManifest.xml:

<activity android:name="com.example.MainActivity" >

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="http" />


<data android:scheme="https" />

<data android:host="www.example.com" />

https://riptutorial.com/ 684
<data android:path="/" />
<data android:path="/map" />

</intent-filter>

</activity>

This will launch your MainActivity when the user clicks any of these links:

• http://www.example.com/
• https://www.example.com/
• http://www.example.com/map
• https://www.example.com/map

Retrieving query parameters

public class MainActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Intent intent = getIntent();


Uri data = intent.getData();

if (data != null) {
String param1 = data.getQueryParameter("param1");
String param2 = data.getQueryParameter("param2");
}
}

If the user clicks on a linkto http://www.example.com/map?param1=FOO&param2=BAR, then param1 here will


have a value of "FOO" and param2 will have a value of "BAR".

Using pathPrefix

AndroidManifest.xml:

<activity android:name="com.example.MainActivity" >

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="http"
android:host="www.example.com"
android:path="/item" />

</intent-filter>

</activity>

https://riptutorial.com/ 685
This will launch your MainActivity when the user clicks any link starting with
http://www.example.com/item, such as:

• https://www.example.com/item
• http://www.example.com/item/1234
• https://www.example.com/item/xyz/details

Read Handling Deep Links online: https://riptutorial.com/android/topic/3716/handling-deep-links

https://riptutorial.com/ 686
Chapter 127: Handling touch and motion
events
Introduction
A summary of some of the basic touch/motion-handling systems in the Android API.

Parameters

Listener Details

onTouchListener Handles single touches for buttons, surfaces and more

A listener that can be found in surfaces(e.g. SurfaceView). Does not need


onTouchEvent
to be set like other listeners(e,g. onTouchListener)

Similar to onTouch, but listens for long presses in buttons, surfaces and
onLongTouch
more.

Examples
Buttons

Touch events related to a Button can be checked as follows:

public class ExampleClass extends Activity implements View.OnClickListener,


View.OnLongClickListener{
public Button onLong, onClick;

@Override
public void onCreate(Bundle sis){
super.onCreate(sis);
setContentView(R.layout.layout);
onLong = (Button) findViewById(R.id.onLong);
onClick = (Button) findViewById(R.id.onClick);
// The buttons are created. Now we need to tell the system that
// these buttons have a listener to check for touch events.
// "this" refers to this class, as it contains the appropriate event listeners.
onLong.setOnLongClickListener(this);
onClick.setOnClickListener(this);

[OR]

onClick.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
// Take action. This listener is only designed for one button.
// This means, no other input will come here.

https://riptutorial.com/ 687
// This makes a switch statement unnecessary here.
}
});

onLong.setOnLongClickListener(new View.OnLongClickListener(){
@Override
public boolean onLongClick(View v){
// See comment in onClick.setOnClickListener().
}
});
}

@Override
public void onClick(View v) {
// If you have several buttons to handle, use a switch to handle them.
switch(v.getId()){
case R.id.onClick:
// Take action.
break;
}
}

@Override
public boolean onLongClick(View v) {
// If you have several buttons to handle, use a switch to handle them.
switch(v.getId()){
case R.id.onLong:
// Take action.
break;
}
return false;
}
}

Surface

Touch event handler for surfaces (e.g. SurfaceView, GLSurfaceView, and others):

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;

public class ExampleClass extends Activity implements View.OnTouchListener{


@Override
public void onCreate(Bundle sis){
super.onCreate(sis);
CustomSurfaceView csv = new CustomSurfaceView(this);
csv.setOnTouchListener(this);
setContentView(csv);
}

@Override
public boolean onTouch(View v, MotionEvent event) {
// Add a switch (see buttons example) if you handle multiple views
// here you can see (using MotionEvent event) to see what touch event
// is being taken. Is the pointer touching or lifted? Is it moving?
return false;

https://riptutorial.com/ 688
}
}

Or alternatively (in the surface):

public class CustomSurfaceView extends SurfaceView {


@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
// Handle touch events here. When doing this, you do not need to call a listener.
// Please note that this listener only applies to the surface it is placed in
// (in this case, CustomSurfaceView), which means that anything else which is
// pressed outside the SurfaceView is handled by the parts of your app that
// have a listener in that area.
return true;
}
}

Handling multitouch in a surface

public class CustomSurfaceView extends SurfaceView {


@Override
public boolean onTouchEvent(MotionEvent e) {
super.onTouchEvent(e);
if(e.getPointerCount() > 2){
return false; // If we want to limit the amount of pointers, we return false
// which disallows the pointer. It will not be reacted on either, for
// any future touch events until it has been lifted and repressed.
}

// What can you do here? Check if the amount of pointers are [x] and take action,
// if a pointer leaves, a new enters, or the [x] pointers are moved.
// Some examples as to handling etc. touch/motion events.

switch (MotionEventCompat.getActionMasked(e)) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
// One or more pointers touch the screen.
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
// One or more pointers stop touching the screen.
break;
case MotionEvent.ACTION_MOVE:
// One or more pointers move.
if(e.getPointerCount() == 2){
move();
}else if(e.getPointerCount() == 1){
paint();
}else{
zoom();
}
break;
}
return true; // Allow repeated action.
}
}

https://riptutorial.com/ 689
Read Handling touch and motion events online: https://riptutorial.com/android/topic/9315/handling-
touch-and-motion-events

https://riptutorial.com/ 690
Chapter 128: Hardware Button Events/Intents
(PTT, LWP, etc.)
Introduction
Several android devices have custom buttons added by the manufacturer. This opens new
possibilities for the developer in handling those buttons especially when making Apps targeted for
Hardware Devices.

This topic documents buttons which have intents attached to them which you can listen for via
intent-receivers.

Examples
Sonim Devices

Sonim devices have varying by model a lot of different custom buttons:

PTT_KEY
com.sonim.intent.action.PTT_KEY_DOWN
com.sonim.intent.action.PTT_KEY_UP

YELLOW_KEY
com.sonim.intent.action.YELLOW_KEY_DOWN
com.sonim.intent.action.YELLOW_KEY_UP

SOS_KEY
com.sonim.intent.action.SOS_KEY_DOWN
com.sonim.intent.action.SOS_KEY_UP

GREEN_KEY
com.sonim.intent.action.GREEN_KEY_DOWN
com.sonim.intent.action.GREEN_KEY_UP

https://riptutorial.com/ 691
Registering the buttons
To receive those intents you will have to assign the buttons to your app in the Phone-Settings.
Sonim has a possibilty to auto-register the buttons to the App when it is installed. In order to do
that you will have to contact them and get a package-specific key to include in your Manifest like
this:

<meta-data
android:name="app_key_green_data"
android:value="your-key-here" />

RugGear Devices

PTT Button
android.intent.action.PTT.down
android.intent.action.PTT.up

Confirmed on: RG730, RG740A

Read Hardware Button Events/Intents (PTT, LWP, etc.) online:


https://riptutorial.com/android/topic/10418/hardware-button-events-intents--ptt--lwp--etc--

https://riptutorial.com/ 692
Chapter 129: How to store passwords
securely
Examples
Using AES for salted password encryption

This examples uses the AES algorithm for encrypting passwords. The salt length can be up to 128
bit.

We are using the SecureRandom class to generate a salt, which is combined with the password to
generate a secret key. The classes used are already existing in Android packages javax.crypto
and java.security.

Once a key is generated, we have to preserve this key in a variable or store it. We are storing it
among the shared preferences in the value S_KEY. Then, a password is encrypted using the doFinal
method of the Cipher class once it is initialised in ENCRYPT_MODE. Next, the encrypted password is
converted from a byte array into a string and stored among the shared preferences. The key used
to generate an encrypted password can be used to decrypt the password in a similar way:

public class MainActivity extends AppCompatActivity {


public static final String PROVIDER = "BC";
public static final int SALT_LENGTH = 20;
public static final int IV_LENGTH = 16;
public static final int PBE_ITERATION_COUNT = 100;

private static final String RANDOM_ALGORITHM = "SHA1PRNG";


private static final String HASH_ALGORITHM = "SHA-512";
private static final String PBE_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
public static final String SECRET_KEY_ALGORITHM = "AES";
private static final String TAG = "EncryptionPassword";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String originalPassword = "ThisIsAndroidStudio%$";
Log.e(TAG, "originalPassword => " + originalPassword);
String encryptedPassword = encryptAndStorePassword(originalPassword);
Log.e(TAG, "encryptedPassword => " + encryptedPassword);
String decryptedPassword = decryptAndGetPassword();
Log.e(TAG, "decryptedPassword => " + decryptedPassword);
}

private String decryptAndGetPassword() {


SharedPreferences prefs = getSharedPreferences("pswd", MODE_PRIVATE);
String encryptedPasswrd = prefs.getString("token", "");
String passwrd = "";
if (encryptedPasswrd!=null && !encryptedPasswrd.isEmpty()) {
try {
String output = prefs.getString("S_KEY", "");
byte[] encoded = hexStringToByteArray(output);

https://riptutorial.com/ 693
SecretKey aesKey = new SecretKeySpec(encoded, SECRET_KEY_ALGORITHM);
passwrd = decrypt(aesKey, encryptedPasswrd);
} catch (Exception e) {
e.printStackTrace();
}
}
return passwrd;
}

public String encryptAndStorePassword(String password) {


SharedPreferences.Editor editor = getSharedPreferences("pswd", MODE_PRIVATE).edit();
String encryptedPassword = "";
if (password!=null && !password.isEmpty()) {
SecretKey secretKey = null;
try {
secretKey = getSecretKey(password, generateSalt());

byte[] encoded = secretKey.getEncoded();


String input = byteArrayToHexString(encoded);
editor.putString("S_KEY", input);
encryptedPassword = encrypt(secretKey, password);
} catch (Exception e) {
e.printStackTrace();
}
editor.putString("token", encryptedPassword);
editor.commit();
}
return encryptedPassword;
}

public static String encrypt(SecretKey secret, String cleartext) throws Exception {


try {
byte[] iv = generateIv();
String ivHex = byteArrayToHexString(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);

Cipher encryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);


encryptionCipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
byte[] encryptedText = encryptionCipher.doFinal(cleartext.getBytes("UTF-8"));
String encryptedHex = byteArrayToHexString(encryptedText);

return ivHex + encryptedHex;

} catch (Exception e) {
Log.e("SecurityException", e.getCause().getLocalizedMessage());
throw new Exception("Unable to encrypt", e);
}
}

public static String decrypt(SecretKey secret, String encrypted) throws Exception {


try {
Cipher decryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
String ivHex = encrypted.substring(0, IV_LENGTH * 2);
String encryptedHex = encrypted.substring(IV_LENGTH * 2);
IvParameterSpec ivspec = new IvParameterSpec(hexStringToByteArray(ivHex));
decryptionCipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
byte[] decryptedText =
decryptionCipher.doFinal(hexStringToByteArray(encryptedHex));
String decrypted = new String(decryptedText, "UTF-8");
return decrypted;
} catch (Exception e) {

https://riptutorial.com/ 694
Log.e("SecurityException", e.getCause().getLocalizedMessage());
throw new Exception("Unable to decrypt", e);
}
}

public static String generateSalt() throws Exception {


try {
SecureRandom random = SecureRandom.getInstance(RANDOM_ALGORITHM);
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
String saltHex = byteArrayToHexString(salt);
return saltHex;
} catch (Exception e) {
throw new Exception("Unable to generate salt", e);
}
}

public static String byteArrayToHexString(byte[] b) {


StringBuffer sb = new StringBuffer(b.length * 2);
for (int i = 0; i < b.length; i++) {
int v = b[i] & 0xff;
if (v < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(v));
}
return sb.toString().toUpperCase();
}

public static byte[] hexStringToByteArray(String s) {


byte[] b = new byte[s.length() / 2];
for (int i = 0; i < b.length; i++) {
int index = i * 2;
int v = Integer.parseInt(s.substring(index, index + 2), 16);
b[i] = (byte) v;
}
return b;
}

public static SecretKey getSecretKey(String password, String salt) throws Exception {


try {
PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(),
hexStringToByteArray(salt), PBE_ITERATION_COUNT, 256);
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBE_ALGORITHM, PROVIDER);
SecretKey tmp = factory.generateSecret(pbeKeySpec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), SECRET_KEY_ALGORITHM);
return secret;
} catch (Exception e) {
throw new Exception("Unable to get secret key", e);
}
}

private static byte[] generateIv() throws NoSuchAlgorithmException,


NoSuchProviderException {
SecureRandom random = SecureRandom.getInstance(RANDOM_ALGORITHM);
byte[] iv = new byte[IV_LENGTH];
random.nextBytes(iv);
return iv;
}
}

https://riptutorial.com/ 695
Read How to store passwords securely online: https://riptutorial.com/android/topic/9093/how-to-
store-passwords-securely

https://riptutorial.com/ 696
Chapter 130: How to use SparseArray
Introduction
A SparseArray is an alternative for a Map. A Map requires its keys to be objects. The phenomenon of
autoboxing occurs when we want to use a primitive int value as key. The compiler automatically
converts primitive values to their boxed types (e.g. int to Integer). The difference in memory
footprint is noticeable: int uses 4 bytes, Integer uses 16 bytes. A SparseArray uses int as key
value.

Remarks
Advantage :

• Less memory usage(because of the primitive keys).


• No auto-boxing.

Disadvantage :

• SparseArray uses binary search for find value ( O(log n) ), so its may not be the best solution
if have to work with large number of element(use HashMap).

There are several variants of the family like : -SparseArray <Integer, Object> -
SparseBooleanArray <Integer, Boolean> -SparseIntArray <Integer, Integer> -SparseLongArray
<Integer, Long> -LongSparseArray <Long, Object> -LongSparseLongArray <Long, Long>

SparseArray operations

• adding element -- put(int, x): Adds a mapping from the specified key to the specified value,
replacing the previous mapping from the specified key if there was one. -- append(int, x):
Puts a key/value pair into the array, optimizing for the case where the key is greater than all
existing keys in the array. You should use append() in case of sequential keys to optimize
performance. Otherwise put() is fine.

• removing element -- delete(int): Removes the mapping from the specified key, if there was
any. -- removeAt(int): Removes the mapping at the given index. -- removeAtRange(int, int):
Remove a range of mappings as a batch.

• accessing element -- get(int): Gets the int mapped from the specified key, or 0 if no such
mapping has been made. -- get(int, E): Gets the int mapped from the specified key, or the
specified value if no such mapping has been made. -- valueAt(int): Given an index in the
range 0...size()-1, returns the value from the indexth key-value mapping that this
SparseIntArray stores. Indices are ordered in ascending order.

• index/key search -- keyAt(int): Given an index in the range 0...size()-1, returns the key from
the indexth key-value mapping that this SparseIntArray stores. Indices are ordered in

https://riptutorial.com/ 697
ascending order. -- valueAt(int): Given an index in the range 0...size()-1, returns the value
from the indexth key-value mapping that this SparseIntArray stores. Indices are ordered in
ascending order. -- indexOfKey(int): Returns the index for which keyAt(int) would return the
specified key, or a negative number if the specified key is not mapped. -- indexOfValue(E):
Returns an index for which valueAt(int) would return the specified key, or a negative number
if no keys map to the specified value. Beware that this is a linear search, unlike lookups by
key, and that multiple keys can map to the same value and this will find only one of them.
The difference in their memory footprint is noticeable: the int uses 4 bytes, the Integer uses
16 bytes.SparseArray uses int as key value.

Examples
Basic example using SparseArray

class Person {
String name;

public Person(String name) {


this.name = name;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Person person = (Person) o;

return name != null ? name.equals(person.name) : person.name == null;


}

@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}

final Person steve = new Person("Steve");


Person[] persons = new Person[] { new Person("John"), new Person("Gwen"), steve, new
Person("Rob") };
int[] identifiers = new int[] {1234, 2345, 3456, 4567};

final SparseArray<Person> demo = new SparseArray<>();

// Mapping persons to identifiers.


for (int i = 0; i < persons.length; i++) {
demo.put(identifiers[i], persons[i]);
}

https://riptutorial.com/ 698
// Find the person with identifier 1234.
Person id1234 = demo.get(1234); // Returns John.

// Find the person with identifier 6410.


Person id6410 = demo.get(6410); // Returns null.

// Find the 3rd person.


Person third = demo.valueAt(3); // Returns Rob.

// Find the 42th person.


//Person fortysecond = demo.valueAt(42); // Throws ArrayIndexOutOfBoundsException.

// Remove the last person.


demo.removeAt(demo.size() - 1); // Rob removed.

// Remove the person with identifier 1234.


demo.delete(1234); // John removed.

// Find the index of Steve.


int indexOfSteve = demo.indexOfValue(steve);

// Find the identifier of Steve.


int identifierOfSteve = demo.keyAt(indexOfSteve);

Tutorial on YouTube

Read How to use SparseArray online: https://riptutorial.com/android/topic/8824/how-to-use-


sparsearray

https://riptutorial.com/ 699
Chapter 131: HttpURLConnection
Syntax
• abstract void disconnect()
• abstract boolean usingProxy()
• static boolean getFollowRedirects()
• static void setFollowRedirects(boolean set)
• String getHeaderField(int n)
• String getHeaderFieldKey(int n)
• String getRequestMethod()
• String getResponseMessage()
• int getResponseCode()
• long getHeaderFieldDate(String name, long Default)
• boolean getInstanceFollowRedirects()
• Permission getPermission()
• InputStream getErrorStream()
• void setChunkedStreamingMode(int chunklen)
• void setFixedLengthStreamingMode(int contentLength)
• void setFixedLengthStreamingMode(long contentLength)
• void setInstanceFollowRedirects(boolean followRedirects)
• void setRequestMethod(String method)

Remarks
HttpURLConnection is the standard HTTP client for Android, used to send and receive data over the
web. It is a concrete implementation of URLConnection for HTTP (RFC 2616).

Examples
Creating an HttpURLConnection

In order to create a new Android HTTP Client HttpURLConnection, call openConnection() on a URL
instance. Since openConnection() returns a URLConnection, you need to explicitly cast the returned
value.

URL url = new URL("http://example.com");


HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// do something with the connection

If you are creating a new URL, you also have to handle the exceptions associated with URL
parsing.

try {

https://riptutorial.com/ 700
URL url = new URL("http://example.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// do something with the connection
} catch (MalformedURLException e) {
e.printStackTrace();
}

Once the response body has been read and the connection is no longer required, the connection
should be closed by calling disconnect().

Here is an example:

URL url = new URL("http://example.com");


HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try {
// do something with the connection
} finally {
connection.disconnect();
}

Sending an HTTP GET request

URL url = new URL("http://example.com");


HttpURLConnection connection = (HttpURLConnection) url.openConnection();

try {
BufferedReader br = new BufferedReader(new
InputStreamReader(connection.getInputStream()));

// read the input stream


// in this case, I simply read the first line of the stream
String line = br.readLine();
Log.d("HTTP-GET", line);

} finally {
connection.disconnect();
}

Please note that exceptions are not handled in the example above. A full example, including (a
trivial) exception handling, would be:

URL url;
HttpURLConnection connection = null;

try {
url = new URL("http://example.com");
connection = (HttpURLConnection) url.openConnection();
BufferedReader br = new BufferedReader(new
InputStreamReader(connection.getInputStream()));

// read the input stream


// in this case, I simply read the first line of the stream
String line = br.readLine();
Log.d("HTTP-GET", line);

} catch (IOException e) {

https://riptutorial.com/ 701
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}

Reading the body of an HTTP GET request

URL url = new URL("http://example.com");


HttpURLConnection connection = (HttpURLConnection) url.openConnection();

try {
BufferedReader br = new BufferedReader(new
InputStreamReader(connection.getInputStream()));

// use a string builder to bufferize the response body


// read from the input strea.
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append('\n');
}

// use the string builder directly,


// or convert it into a String
String body = sb.toString();

Log.d("HTTP-GET", body);

} finally {
connection.disconnect();
}

Please note that exceptions are not handled in the example above.

Use HttpURLConnection for multipart/form-data

Create custom class for calling multipart/form-data HttpURLConnection request

MultipartUtility.java

public class MultipartUtility {


private final String boundary;
private static final String LINE_FEED = "\r\n";
private HttpURLConnection httpConn;
private String charset;
private OutputStream outputStream;
private PrintWriter writer;

/**
* This constructor initializes a new HTTP POST request with content type
* is set to multipart/form-data
*
* @param requestURL
* @param charset

https://riptutorial.com/ 702
* @throws IOException
*/
public MultipartUtility(String requestURL, String charset)
throws IOException {
this.charset = charset;

// creates a unique boundary based on time stamp


boundary = "===" + System.currentTimeMillis() + "===";
URL url = new URL(requestURL);
httpConn = (HttpURLConnection) url.openConnection();
httpConn.setUseCaches(false);
httpConn.setDoOutput(true); // indicates POST method
httpConn.setDoInput(true);
httpConn.setRequestProperty("Content-Type",
"multipart/form-data; boundary=" + boundary);
outputStream = httpConn.getOutputStream();
writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),
true);
}

/**
* Adds a form field to the request
*
* @param name field name
* @param value field value
*/
public void addFormField(String name, String value) {
writer.append("--" + boundary).append(LINE_FEED);
writer.append("Content-Disposition: form-data; name=\"" + name + "\"")
.append(LINE_FEED);
writer.append("Content-Type: text/plain; charset=" + charset).append(
LINE_FEED);
writer.append(LINE_FEED);
writer.append(value).append(LINE_FEED);
writer.flush();
}

/**
* Adds a upload file section to the request
*
* @param fieldName name attribute in <input type="file" name="..." />
* @param uploadFile a File to be uploaded
* @throws IOException
*/
public void addFilePart(String fieldName, File uploadFile)
throws IOException {
String fileName = uploadFile.getName();
writer.append("--" + boundary).append(LINE_FEED);
writer.append(
"Content-Disposition: form-data; name=\"" + fieldName
+ "\"; filename=\"" + fileName + "\"")
.append(LINE_FEED);
writer.append(
"Content-Type: "
+ URLConnection.guessContentTypeFromName(fileName))
.append(LINE_FEED);
writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
writer.append(LINE_FEED);
writer.flush();

FileInputStream inputStream = new FileInputStream(uploadFile);

https://riptutorial.com/ 703
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
inputStream.close();
writer.append(LINE_FEED);
writer.flush();
}

/**
* Adds a header field to the request.
*
* @param name - name of the header field
* @param value - value of the header field
*/
public void addHeaderField(String name, String value) {
writer.append(name + ": " + value).append(LINE_FEED);
writer.flush();
}

/**
* Completes the request and receives response from the server.
*
* @return a list of Strings as response in case the server returned
* status OK, otherwise an exception is thrown.
* @throws IOException
*/
public List<String> finish() throws IOException {
List<String> response = new ArrayList<String>();
writer.append(LINE_FEED).flush();
writer.append("--" + boundary + "--").append(LINE_FEED);
writer.close();

// checks server's status code first


int status = httpConn.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(
httpConn.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
response.add(line);
}
reader.close();
httpConn.disconnect();
} else {
throw new IOException("Server returned non-OK status: " + status);
}
return response;
}
}

Use it (Async way)

MultipartUtility multipart = new MultipartUtility(requestURL, charset);

// In your case you are not adding form data so ignore this
/*This is to add parameter values */
for (int i = 0; i < myFormDataArray.size(); i++) {

https://riptutorial.com/ 704
multipart.addFormField(myFormDataArray.get(i).getParamName(),
myFormDataArray.get(i).getParamValue());
}

//add your file here.


/*This is to add file content*/
for (int i = 0; i < myFileArray.size(); i++) {
multipart.addFilePart(myFileArray.getParamName(),
new File(myFileArray.getFileName()));
}

List<String> response = multipart.finish();


Debug.e(TAG, "SERVER REPLIED:");
for (String line : response) {
Debug.e(TAG, "Upload Files Response:::" + line);
// get your server response here.
responseString = line;
}

Sending an HTTP POST request with parameters

Use a HashMap to store the parameters that should be sent to the server through POST
parameters:

HashMap<String, String> params;

Once the params HashMap is populated, create the StringBuilder that will be used to send them to
the server:

StringBuilder sbParams = new StringBuilder();


int i = 0;
for (String key : params.keySet()) {
try {
if (i != 0){
sbParams.append("&");
}
sbParams.append(key).append("=")
.append(URLEncoder.encode(params.get(key), "UTF-8"));

} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
i++;
}

Then, create the HttpURLConnection, open the connection, and send the POST parameters:

try{
String url = "http://www.example.com/test.php";
URL urlObj = new URL(url);
HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept-Charset", "UTF-8");

https://riptutorial.com/ 705
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);

conn.connect();

String paramsString = sbParams.toString();

DataOutputStream wr = new DataOutputStream(conn.getOutputStream());


wr.writeBytes(paramsString);
wr.flush();
wr.close();
} catch (IOException e) {
e.printStackTrace();
}

Then receive the result that the server sends back:

try {
InputStream in = new BufferedInputStream(conn.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}

Log.d("test", "result from server: " + result.toString());

} catch (IOException e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
}

Upload (POST) file using HttpURLConnection

Quite often it's necessary to send/upload a file to a remote server, for example, an image, video,
audio or a backup of the application database to a remote private server. Assuming the server is
expecting a POST request with the content, here's a simple example of how to complete this task
in Android.

File uploads are sent using multipart/form-data POST requests. It's very easy to implement:

URL url = new URL(postTarget);


HttpURLConnection connection = (HttpURLConnection) url.openConnection();

String auth = "Bearer " + oauthToken;


connection.setRequestProperty("Authorization", basicAuth);

String boundary = UUID.randomUUID().toString();


connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

https://riptutorial.com/ 706
DataOutputStream request = new DataOutputStream(uc.getOutputStream());

request.writeBytes("--" + boundary + "\r\n");


request.writeBytes("Content-Disposition: form-data; name=\"description\"\r\n\r\n");
request.writeBytes(fileDescription + "\r\n");

request.writeBytes("--" + boundary + "\r\n");


request.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" +
file.fileName + "\"\r\n\r\n");
request.write(FileUtils.readFileToByteArray(file));
request.writeBytes("\r\n");

request.writeBytes("--" + boundary + "--\r\n");


request.flush();
int respCode = connection.getResponseCode();

switch(respCode) {
case 200:
//all went ok - read response
...
break;
case 301:
case 302:
case 307:
//handle redirect - for example, re-post to the new location
...
break;
...
default:
//do something sensible
}

Of course, exceptions will need to be caught or declared as being thrown. A couple points to note
about this code:

1. postTarget is the destination URL of the POST; oauthToken is the authentication token;
fileDescription is the description of the file, which is sent as the value of field description;
file is the file to be sent - it's of type java.io.File - if you have the file path, you can use new
File(filePath) instead.
2. It sets Authorization header for an oAuth auth
3. It uses Apache Common FileUtil to read the file into a byte array - if you already have the
content of the file in a byte array or in some other way in memory, then there's no need to
read it.

A multi-purpose HttpURLConnection class to handle all types of HTTP


requests

The following class can be used as a single class that can handle GET, POST, PUT, PATCH, and other
requests:

class APIResponseObject{
int responseCode;
String response;

APIResponseObject(int responseCode,String response)

https://riptutorial.com/ 707
{
this.responseCode = responseCode;
this.response = response;
}
}

public class APIAccessTask extends AsyncTask<String,Void,APIResponseObject> {


URL requestUrl;
Context context;
HttpURLConnection urlConnection;
List<Pair<String,String>> postData, headerData;
String method;
int responseCode = HttpURLConnection.HTTP_OK;

interface OnCompleteListener{
void onComplete(APIResponseObject result);
}

public OnCompleteListener delegate = null;

APIAccessTask(Context context, String requestUrl, String method, OnCompleteListener


delegate){
this.context = context;
this.delegate = delegate;
this.method = method;
try {
this.requestUrl = new URL(requestUrl);
}
catch(Exception ex){
ex.printStackTrace();
}
}

APIAccessTask(Context context, String requestUrl, String method, List<Pair<String,String>>


postData, OnCompleteListener delegate){
this(context, requestUrl, method, delegate);
this.postData = postData;
}

APIAccessTask(Context context, String requestUrl, String method, List<Pair<String,String>>


postData,
List<Pair<String,String>> headerData, OnCompleteListener delegate ){
this(context, requestUrl,method,postData,delegate);
this.headerData = headerData;
}

@Override
protected void onPreExecute() {
super.onPreExecute();
}

@Override
protected APIResponseObject doInBackground(String... params) {
Log.d("debug", "url = "+ requestUrl);
try {
urlConnection = (HttpURLConnection) requestUrl.openConnection();

if(headerData != null) {
for (Pair pair : headerData) {

urlConnection.setRequestProperty(pair.first.toString(),pair.second.toString());

https://riptutorial.com/ 708
}
}

urlConnection.setDoInput(true);
urlConnection.setChunkedStreamingMode(0);
urlConnection.setRequestMethod(method);
urlConnection.connect();

StringBuilder sb = new StringBuilder();

if(!(method.equals("GET"))) {
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-
8"));
writer.write(getPostDataString(postData));
writer.flush();
writer.close();
out.close();
}

urlConnection.connect();
responseCode = urlConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-
8"));
String line;

while ((line = reader.readLine()) != null) {


sb.append(line);
}
}

return new APIResponseObject(responseCode, sb.toString());


}
catch(Exception ex){
ex.printStackTrace();
}
return null;
}

@Override
protected void onPostExecute(APIResponseObject result) {
delegate.onComplete(result);
super.onPostExecute(result);
}

private String getPostDataString(List<Pair<String, String>> params) throws


UnsupportedEncodingException {
StringBuilder result = new StringBuilder();
boolean first = true;
for(Pair<String,String> pair : params){
if (first)
first = false;
else
result.append("&");

result.append(URLEncoder.encode(pair.first,"UTF-8"));
result.append("=");
result.append(URLEncoder.encode(pair.second, "UTF-8"));
}

https://riptutorial.com/ 709
return result.toString();
}
}

Usage
Use any of the given constructors of the class depending on whether you need to send POST data
or any extra headers.

The onComplete() method will be called when the data fetching is complete. The data is returned as
an object of the APIResponseObject class, which has a status code stating the HTTP status code of
the request and a string containing the response. You can parse this response in your class, i.e.
XML or JSON.

Call execute() on the object of the class to execute the request, as shown in the following example:

class MainClass {
String url = "https://example.com./api/v1/ex";
String method = "POST";
List<Pair<String,String>> postData = new ArrayList<>();

postData.add(new Pair<>("email","whatever");
postData.add(new Pair<>("password", "whatever");

new APIAccessTask(MainActivity.this, url, method, postData,


new APIAccessTask.OnCompleteListener() {
@Override
public void onComplete(APIResponseObject result) {
if (result.responseCode == HttpURLConnection.HTTP_OK) {
String str = result.response;
// Do your XML/JSON parsing here
}
}
}).execute();
}

Read HttpURLConnection online: https://riptutorial.com/android/topic/781/httpurlconnection

https://riptutorial.com/ 710
Chapter 132: Image Compression
Examples
How to compress image without size change

Get Compressed Bitmap from Singleton class:

ImageView imageView = (ImageView)findViewById(R.id.imageView);


Bitmap bitmap = ImageUtils.getInstant().getCompressedBitmap("Your_Image_Path_Here");
imageView.setImageBitmap(bitmap);

ImageUtils.java:

public class ImageUtils {

public static ImageUtils mInstant;

public static ImageUtils getInstant(){


if(mInstant==null){
mInstant = new ImageUtils();
}
return mInstant;
}

public Bitmap getCompressedBitmap(String imagePath) {


float maxHeight = 1920.0f;
float maxWidth = 1080.0f;
Bitmap scaledBitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(imagePath, options);

int actualHeight = options.outHeight;


int actualWidth = options.outWidth;
float imgRatio = (float) actualWidth / (float) actualHeight;
float maxRatio = maxWidth / maxHeight;

if (actualHeight > maxHeight || actualWidth > maxWidth) {


if (imgRatio < maxRatio) {
imgRatio = maxHeight / actualHeight;
actualWidth = (int) (imgRatio * actualWidth);
actualHeight = (int) maxHeight;
} else if (imgRatio > maxRatio) {
imgRatio = maxWidth / actualWidth;
actualHeight = (int) (imgRatio * actualHeight);
actualWidth = (int) maxWidth;
} else {
actualHeight = (int) maxHeight;
actualWidth = (int) maxWidth;

}
}

options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);

https://riptutorial.com/ 711
options.inJustDecodeBounds = false;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16 * 1024];

try {
bmp = BitmapFactory.decodeFile(imagePath, options);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();

}
try {
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight,
Bitmap.Config.ARGB_8888);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}

float ratioX = actualWidth / (float) options.outWidth;


float ratioY = actualHeight / (float) options.outHeight;
float middleX = actualWidth / 2.0f;
float middleY = actualHeight / 2.0f;

Matrix scaleMatrix = new Matrix();


scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);

Canvas canvas = new Canvas(scaledBitmap);


canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2,
new Paint(Paint.FILTER_BITMAP_FLAG));

ExifInterface exif = null;


try {
exif = new ExifInterface(imagePath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
} else if (orientation == 3) {
matrix.postRotate(180);
} else if (orientation == 8) {
matrix.postRotate(270);
}
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(),
scaledBitmap.getHeight(), matrix, true);
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 85, out);

byte[] byteArray = out.toByteArray();

Bitmap updatedBitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);

return updatedBitmap;
}

private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int


reqHeight) {

https://riptutorial.com/ 712
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {


final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
final float totalPixels = width * height;
final float totalReqPixelsCap = reqWidth * reqHeight * 2;

while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {


inSampleSize++;
}
return inSampleSize;
}
}

Dimensions are same after compressing Bitmap.

How did I checked ?

Bitmap beforeBitmap = BitmapFactory.decodeFile("Your_Image_Path_Here");


Log.i("Before Compress Dimension", beforeBitmap.getWidth()+"-"+beforeBitmap.getHeight());

Bitmap afterBitmap = ImageUtils.getInstant().getCompressedBitmap("Your_Image_Path_Here");


Log.i("After Compress Dimension", afterBitmap.getWidth() + "-" + afterBitmap.getHeight());

Output:

Before Compress : Dimension: 1080-1452
After Compress : Dimension: 1080-1452

Read Image Compression online: https://riptutorial.com/android/topic/5588/image-compression

https://riptutorial.com/ 713
Chapter 133: ImageView
Introduction
ImageView (android.widget.ImageView) is a View for displaying and manipulating image resources,
such as Drawables and Bitmaps.

Some effects, discussed in this topic, can be applied to the image. The image source can be set in
XML file (layout folder) or by programatically in Java code.

Syntax
• The method setImageResource(int resId) sets a drawable as the content of this ImageView.
• Usage: imageView.setImageResource(R.drawable.anyImage)

Parameters

Parameter Description

resId your Image file name in the res folder (usually in drawable folder)

Examples
Set Image Resource

<ImageView
android:id="@+id/imgExample"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
...
/>

set a drawable as content of ImageView using XML attribute:

android:src="@drawable/android2"

set a drawable programmatically:

ImageView imgExample = (ImageView) findViewById(R.id.imgExample);


imgExample.setImageResource(R.drawable.android2);

Set alpha

"alpha" is used to specify the opacity for an image.

https://riptutorial.com/ 714
set alpha using XML attribute:

android:alpha="0.5"

Note: takes float value from 0 (transparent) to 1 (fully visible)

set alpha programmatically:

imgExample.setAlpha(0.5f);

ImageView ScaleType - Center

The image contained in the ImageView may not fit the exact size given to the container. In that
case, the framework allows you to resize the image in a number of ways.

https://riptutorial.com/ 715
Center

<ImageView android:layout_width="20dp"
android:layout_height="20dp"
android:src="@mipmap/ic_launcher"
android:id="@+id/imageView"
android:scaleType="center"
android:background="@android:color/holo_orange_light"/>

This will not resize the image, and it will center it inside the container (Orange = container)

https://riptutorial.com/ 716
https://riptutorial.com/ 717
which has a black background and we want to display a rectangular drawable in white background
in ImageView.

<ImageView
android:id="@+id/imgExample"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#000"
android:src="@drawable/android2"
android:scaleType="..."/>

scaleType must be one of the following values:

1. center:Center the image in the view, but perform no scaling.

2. centerCrop: Scale the image uniformly (maintain the image's aspect ratio) so both dimensions
(width and height) of the image will be equal to or larger than the corresponding dimension of
the view (minus padding). The image is then centered in the view.

https://riptutorial.com/ 718
3. centerInside: Scale the image uniformly (maintain the image's aspect ratio) so that both
dimensions (width and height) of the image will be equal to or less than the corresponding
dimension of the view (minus padding). The image is then centered in the view.

4. matrix : Scale using the image matrix when drawing.

https://riptutorial.com/ 719
5. fitXY: Scale the image using FILL.

6. fitStart: Scale the image using START.

https://riptutorial.com/ 720
7. fitCenter: Scale the image using CENTER.

8. fitEnd: Scale the image using END.

https://riptutorial.com/ 721
Set tint

Set a tinting color for the image. By default, the tint will blend using SRC_ATOP mode.

set tint using XML attribute:

android:tint="#009c38"

Note: Must be a color value, in the form of "#rgb", "#argb", "#rrggbb", or "#aarrggbb".

set tint programmatically:

imgExample.setColorFilter(Color.argb(255, 0, 156, 38));

and you can clear this color filter:

imgExample.clearColorFilter();

Example:

https://riptutorial.com/ 722
MLRoundedImageView.java

Copy and Paste following class in your package:

public class MLRoundedImageView extends ImageView {

public MLRoundedImageView(Context context) {


super(context);
}

public MLRoundedImageView(Context context, AttributeSet attrs) {


super(context, attrs);
}

public MLRoundedImageView(Context context, AttributeSet attrs, int defStyle) {


super(context, attrs, defStyle);
}

@Override
protected void onDraw(Canvas canvas) {

Drawable drawable = getDrawable();

if (drawable == null) {
return;
}

if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);

int w = getWidth(), h = getHeight();

Bitmap roundBitmap = getCroppedBitmap(bitmap, w);

https://riptutorial.com/ 723
canvas.drawBitmap(roundBitmap, 0, 0, null);

public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {


Bitmap sbmp;

if (bmp.getWidth() != radius || bmp.getHeight() != radius) {


float smallest = Math.min(bmp.getWidth(), bmp.getHeight());
float factor = smallest / radius;
sbmp = Bitmap.createScaledBitmap(bmp, (int)(bmp.getWidth() / factor),
(int)(bmp.getHeight() / factor), false);
} else {
sbmp = bmp;
}

Bitmap output = Bitmap.createBitmap(radius, radius,


Config.ARGB_8888);
Canvas canvas = new Canvas(output);

final int color = 0xffa19774;


final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, radius, radius);

paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawCircle(radius / 2 + 0.7f,
radius / 2 + 0.7f, radius / 2 + 0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(sbmp, rect, rect, paint);

return output;
}
}

Use this Class in XML with package name instead of ImageView

<com.androidbuts.example.MLRoundedImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" />

Read ImageView online: https://riptutorial.com/android/topic/4709/imageview

https://riptutorial.com/ 724
Chapter 134: Implicit Intents
Syntax
• Intent()
• Intent (Intent o)
• Intent (String action)
• Intent (String action, Uri uri)
• Intent (Context packageContext, Class<?> cls)
• Intent (String action, Uri uri, Context packageContext, Class<?> cls)

Parameters

Parameters Details

o Intent

action String: The Intent action, such as ACTION_VIEW.

uri Uri: The Intent data URI.

packageContext Context: A Context of the application package implementing this class.

cls Class: The component class that is to be used for the intent.

Remarks
• More about Intent

• More about Intent Types

Examples
Implicit and Explicit Intents

An explicit intent is used for starting an activity or service within the same application package. In
this case the name of the intended class is explicitly mentioned:

Intent intent = new Intent(this, MyComponent.class);


startActivity(intent);

However, an implicit intent is sent across the system for any application installed on the user's
device that can handle that intent. This is used to share information between different applications.

https://riptutorial.com/ 725
Intent intent = new Intent("com.stackoverflow.example.VIEW");

//We need to check to see if there is an application installed that can handle this intent
if (getPackageManager().resolveActivity(intent, 0) != null){
startActivity(intent);
}else{
//Handle error
}

More details on the differences can be found in the Android Developer docs here: Intent
Resolution

Implicit Intents

Implicit intents do not name a specific component, but instead declare a general action to perform,
which allows a component from another app to handle it.

For example, if you want to show the user a location on a map, you can use an implicit intent to
request that another capable app show a specified location on a map.

Example:

// Create the text message with a string


Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity


if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}

Read Implicit Intents online: https://riptutorial.com/android/topic/5336/implicit-intents

https://riptutorial.com/ 726
Chapter 135: In-app Billing
Examples
Consumable In-app Purchases

Consumable Managed Products are products that can be bought multiple times such as in-game
currency, game lives, power-ups, etc.

In this example, we are going to implement 4 different consumable managed products "item1",
"item2", "item3", "item4".

Steps in summary:
1. Add the In-app Billing library to your project (AIDL File).
2. Add the required permission in AndroidManifest.xml file.
3. Deploy a signed apk to Google Developers Console.
4. Define your products.
5. Implement the code.
6. Test In-app Billing (optional).

Step 1:
First of all, we will need to add the AIDL file to your project as clearly explained in Google
Documentation here.

IInAppBillingService.aidl is an Android Interface Definition Language (AIDL) file that defines the
interface to the In-app Billing Version 3 service. You will use this interface to make billing requests
by invoking IPC method calls.

Step 2:
After adding the AIDL file, add BILLING permission in AndroidManifest.xml:

<!-- Required permission for implementing In-app Billing -->


<uses-permission android:name="com.android.vending.BILLING" />

Step 3:
Generate a signed apk, and upload it to Google Developers Console. This is required so that we
can start defining our in-app products there.

https://riptutorial.com/ 727
Step 4:
Define all your products with different productID, and set a price to each one of them. There are 2
types of products (Managed Products and Subscriptions). As we already said, we are going to
implement 4 different consumable managed products "item1", "item2", "item3", "item4".

Step 5:
After doing all the steps above, you are now ready to start implementing the code itself in your
own activity.

MainActivity:

public class MainActivity extends Activity {

IInAppBillingService inAppBillingService;
ServiceConnection serviceConnection;

// productID for each item. You should define them in the Google Developers Console.
final String item1 = "item1";
final String item2 = "item2";
final String item3 = "item3";
final String item4 = "item4";

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Instantiate the views according to your layout file.


final Button buy1 = (Button) findViewById(R.id.buy1);
final Button buy2 = (Button) findViewById(R.id.buy2);
final Button buy3 = (Button) findViewById(R.id.buy3);
final Button buy4 = (Button) findViewById(R.id.buy4);

// setOnClickListener() for each button.


// buyItem() here is the method that we will implement to launch the PurchaseFlow.
buy1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
buyItem(item1);
}
});

buy2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
buyItem(item2);
}
});

buy3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

https://riptutorial.com/ 728
buyItem(item3);
}
});

buy4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
buyItem(item4);
}
});

// Attach the service connection.


serviceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
inAppBillingService = null;
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
inAppBillingService = IInAppBillingService.Stub.asInterface(service);
}
};

// Bind the service.


Intent serviceIntent = new
Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE);

// Get the price of each product, and set the price as text to
// each button so that the user knows the price of each item.
if (inAppBillingService != null) {
// Attention: You need to create a new thread here because
// getSkuDetails() triggers a network request, which can
// cause lag to your app if it was called from the main thread.
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
ArrayList<String> skuList = new ArrayList<>();
skuList.add(item1);
skuList.add(item2);
skuList.add(item3);
skuList.add(item4);
Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);

try {
Bundle skuDetails = inAppBillingService.getSkuDetails(3,
getPackageName(), "inapp", querySkus);
int response = skuDetails.getInt("RESPONSE_CODE");

if (response == 0) {
ArrayList<String> responseList =
skuDetails.getStringArrayList("DETAILS_LIST");

for (String thisResponse : responseList) {


JSONObject object = new JSONObject(thisResponse);
String sku = object.getString("productId");
String price = object.getString("price");

https://riptutorial.com/ 729
switch (sku) {
case item1:
buy1.setText(price);
break;
case item2:
buy2.setText(price);
break;
case item3:
buy3.setText(price);
break;
case item4:
buy4.setText(price);
break;
}
}
}
} catch (RemoteException | JSONException e) {
e.printStackTrace();
}
}
});
thread.start();
}
}

// Launch the PurchaseFlow passing the productID of the item the user wants to buy as a
parameter.
private void buyItem(String productID) {
if (inAppBillingService != null) {
try {
Bundle buyIntentBundle = inAppBillingService.getBuyIntent(3, getPackageName(),
productID, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
startIntentSenderForResult(pendingIntent.getIntentSender(), 1003, new
Intent(), 0, 0, 0);
} catch (RemoteException | IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
}

// Unbind the service in onDestroy(). If you don’t unbind, the open


// service connection could cause your device’s performance to degrade.
@Override
public void onDestroy() {
super.onDestroy();
if (inAppBillingService != null) {
unbindService(serviceConnection);
}
}

// Check here if the in-app purchase was successful or not. If it was successful,
// then consume the product, and let the app make the required changes.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == 1003 && resultCode == RESULT_OK) {

final String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");

https://riptutorial.com/ 730
// Attention: You need to create a new thread here because
// consumePurchase() triggers a network request, which can
// cause lag to your app if it was called from the main thread.
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
JSONObject jo = new JSONObject(purchaseData);
// Get the productID of the purchased item.
String sku = jo.getString("productId");
String productName = null;

// increaseCoins() here is a method used as an example in a game to


// increase the in-game currency if the purchase was successful.
// You should implement your own code here, and let the app apply
// the required changes after the purchase was successful.
switch (sku) {
case item1:
productName = "Item 1";
increaseCoins(2000);
break;
case item2:
productName = "Item 2";
increaseCoins(8000);
break;
case item3:
productName = "Item 3";
increaseCoins(18000);
break;
case item4:
productName = "Item 4";
increaseCoins(30000);
break;
}

// Consume the purchase so that the user is able to purchase the same
product again.
inAppBillingService.consumePurchase(3, getPackageName(),
jo.getString("purchaseToken"));
Toast.makeText(MainActivity.this, productName + " is successfully
purchased. Excellent choice, master!", Toast.LENGTH_LONG).show();
} catch (JSONException | RemoteException e) {
Toast.makeText(MainActivity.this, "Failed to parse purchase data.",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
});
thread.start();
}
}
}

Step 6:
After implementing the code, you can test it by deploying your apk to beta/alpha channel, and let
other users test the code for you. However, real in-app purchases can't be made while in testing
mode. You have to publish your app/game first to Play Store so that all the products are fully

https://riptutorial.com/ 731
activated.

More info on testing In-app Billing can be found here.

(Third party) In-App v3 Library

Step 1: First of all follow these two steps to add in app functionality :

1. Add the library using :

repositories {
mavenCentral()
}
dependencies {
compile 'com.anjlab.android.iab.v3:library:1.0.+'
}

2. Add permission in manifest file.

<uses-permission android:name="com.android.vending.BILLING" />

Step 2: Initialise your billing processor:

BillingProcessor bp = new BillingProcessor(this, "YOUR LICENSE KEY FROM GOOGLE PLAY CONSOLE
HERE", this);

and implement Billing Handler : BillingProcessor.IBillingHandler which contains 4 methods : a.


onBillingInitialized(); b. onProductPurchased(String productId, TransactionDetails details) : This is
where you need to handle actions to be performed after successful purchase c. onBillingError(int
errorCode, Throwable error) : Handle any error occurred during purchase process d.
onPurchaseHistoryRestored() : For restoring in app purchases

Step 3: How to purchase a product.

To purchase a managed product :

bp.purchase(YOUR_ACTIVITY, "YOUR PRODUCT ID FROM GOOGLE PLAY CONSOLE HERE");

And to Purchase a subscription :

bp.subscribe(YOUR_ACTIVITY, "YOUR SUBSCRIPTION ID FROM GOOGLE PLAY CONSOLE HERE");

Step 4 : Consuming a product.

To consume a product simply call consumePurchase method.

bp.consumePurchase("YOUR PRODUCT ID FROM GOOGLE PLAY CONSOLE HERE");

For other methods related to in app visit github

https://riptutorial.com/ 732
Read In-app Billing online: https://riptutorial.com/android/topic/2843/in-app-billing

https://riptutorial.com/ 733
Chapter 136: Installing apps with ADB
Examples
Install an app

Write the following command in your terminal:

adb install [-rtsdg] <file>

Note that you have to pass a file that is on your computer and not on your device.

If you append -r at the end, then any existing conflicting apks will be overwritten. Otherwise, the
command will quit with an error.

-g will immediately grant all runtime permissions.

-d allows version code downgrade (only appliable on debuggable packages).

Use -s to install the application on the external SD card.

-t will allow to use test applications.

Uninstall an app

Write the following command in your terminal to uninstall an app with a provided package name:

adb uninstall <packagename>

Install all apk file in directory

Windows :

for %f in (C:\your_app_path\*.apk) do adb install "%f"

Linux :

for f in *.apk ; do adb install "$f" ; done

Read Installing apps with ADB online: https://riptutorial.com/android/topic/5301/installing-apps-


with-adb

https://riptutorial.com/ 734
Chapter 137: Instant Run in Android Studio
Remarks
Instant Run is an extended behavior for the run and debug commands that enables faster
debugging by not requiring a full build and reinstall for eevry change done in your app's code.

Introduced in Android Studio 2.0, Instant Run is a behavior for the Run and Debug
commands that significantly reduces the time between updates to your app. Although
your first build may take longer to complete, Instant Run pushes subsequent updates
to your app without building a new APK, so changes are visible much more quickly.

Instant Run is supported only when you deploy the debug build variant, use Android
Plugin for Gradle version 2.0.0 or higher, and set minSdkVersion to 15 or higher in your
app's module-level build.gradle file. For the best performance, set minSdkVersion to 21
or higher.

After deploying an app, a small, yellow thunderbolt icon appears within the Run button
(or Debug button), indicating that Instant Run is ready to push updates the next time
you click the button. Instead of building a new APK, it pushes just those new changes
and, in some cases, the app doesn't even need to restart but immediately shows the
effect of those code changes.

Instant Run pushes updated code and resources to your connected device or emulator
by performing a hot swap, warm swap, or cold swap. It automatically determines the
type of swap to perform based on the type of change you made. The video above
provides interesting detail about how this all works under the hood. For a quick
summary of how Instant Run behaves when you push certain code changes to a target
device, however, see the following table.

Documentation

Examples
Enabling or disabling Instant Run

1. Open the Settings or Preferences dialog:


• On Windows or Linux, select File > Settings from the main menu.
• On Mac OSX, select Android Studio > Preferences from the main menu.
2. Navigate to Build, Execution, Deployment > Compiler.
3. In the text field next to Command-line Options, enter your command-line options.
4. Click OK to save and exit.

https://riptutorial.com/ 735
The top option is Instant run. Check/uncheck that box.

Documentation

https://riptutorial.com/ 736
Types of code Swaps in Instant Run

There are three types of code swaps that Instant run enables to support faster debugging and
running app from your code in Android Studio.

• Hot Swap
• Warm Swap
• Cold Swap

When are each of these swaps triggered?

HOT SWAP is triggered when an existing method's implementation is changed.

WARM SWAP is triggered when an existing resource is changed or removed (anything in the res
folder)

COLD SWAP whenever there is a structural code change in your app's code e.g.

1. Add, remove, or change:

• an annotation
• an instance field
• a static field
• a static method signature
• an instance method signature

2. Change which parent class the current class inherits from


3. Change the list of implemented interfaces
4. Change a class's static initializer
5. Reorder layout elements that use dynamic resource IDs

What happens when a code swap happens?

HOT SWAP changes are visible instantly - as soon as the next call to the method whose
implementation is changed is made.

WARM SWAP restarts the current activity

COLD SWAP restarts the entire app (without reinstall)

Unsupported code changes when using Instant Run

There are a few changes where instant won't do its trick and a full build and reinstall fo your app
will happen just like it used to happen before Instant Run was born.

1. Change the app manifest


2. Change resources referenced by the app manifest
3. Change an Android widget UI element (requires a Clean and Rerun)

Documentation

https://riptutorial.com/ 737
Read Instant Run in Android Studio online: https://riptutorial.com/android/topic/2119/instant-run-in-
android-studio

https://riptutorial.com/ 738
Chapter 138: Integrate Google Sign In
Syntax
• newInstance() - To create single instance of Google Helper
• initGoogleSignIn() - To initialize Google log in
• getGoogleAccountDetails() - To get logged in Account details
• signOut() - To log out user
• getGoogleClient() - To get GoogleApiClient used

Parameters

Parameter Detail

TAG A String used while logging

GoogleSignInHelper A static reference for helper

AppCompatActivity An Activity reference

GoogleApiClient A reference of GoogleAPIClient

RC_SIGN_IN An integer represents activity result constant

isLoggingOut A boolean to check if log-out task is running or not

Examples
Google Sign In with Helper class

Add below to your build.gradle out of android tag:

// Apply plug-in to app.


apply plugin: 'com.google.gms.google-services'

Add below helper class to your util package:

/**
* Created by Andy
*/
public class GoogleSignInHelper implements GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks {
private static final String TAG = GoogleSignInHelper.class.getSimpleName();

private static GoogleSignInHelper googleSignInHelper;


private AppCompatActivity mActivity;

https://riptutorial.com/ 739
private GoogleApiClient mGoogleApiClient;
public static final int RC_SIGN_IN = 9001;
private boolean isLoggingOut = false;

public static GoogleSignInHelper newInstance(AppCompatActivity mActivity) {


if (googleSignInHelper == null) {
googleSignInHelper = new GoogleSignInHelper(mActivity, fireBaseAuthHelper);
}
return googleSignInHelper;
}

public GoogleSignInHelper(AppCompatActivity mActivity) {


this.mActivity = mActivity;
initGoogleSignIn();
}

private void initGoogleSignIn() {


// [START config_sign_in]
// Configure Google Sign In
GoogleSignInOptions gso = new
GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(mActivity.getString(R.string.default_web_client_id))
.requestEmail()
.build();
// [END config_sign_in]

mGoogleApiClient = new GoogleApiClient.Builder(mActivity)


.enableAutoManage(mActivity /* FragmentActivity */, this /*
OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.addConnectionCallbacks(this)
.build();

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
// An unresolvable error has occurred and Google APIs (including Sign-In) will not
// be available.
Log.d(TAG, "onConnectionFailed:" + connectionResult);
Toast.makeText(mActivity, "Google Play Services error.", Toast.LENGTH_SHORT).show();
}

public void getGoogleAccountDetails(GoogleSignInResult result) {


// Google Sign In was successful, authenticate with FireBase
GoogleSignInAccount account = result.getSignInAccount();
// You are now logged into Google
}
public void signOut() {

if (mGoogleApiClient.isConnected()) {

// Google sign out


Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
isLoggingOut = false;
}
});

https://riptutorial.com/ 740
} else {
isLoggingOut = true;
}
}

public GoogleApiClient getGoogleClient() {


return mGoogleApiClient;
}

@Override
public void onConnected(@Nullable Bundle bundle) {
Log.w(TAG, "onConnected");
if (isLoggingOut) {
signOut();
}
}

@Override
public void onConnectionSuspended(int i) {
Log.w(TAG, "onConnectionSuspended");
}
}

Add below code to your OnActivityResult in Activity file:

// [START onactivityresult]
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

// Result returned from launching the Intent from


GoogleSignInApi.getSignInIntent(...);
if (requestCode == GoogleSignInHelper.RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess()) {
googleSignInHelper.getGoogleAccountDetails(result);
} else {
// Google Sign In failed, update UI appropriately
// [START_EXCLUDE]
Log.d(TAG, "signInWith Google failed");
// [END_EXCLUDE]
}
}
}
// [END onactivityresult]

// [START signin]
public void signIn() {
Intent signInIntent =
Auth.GoogleSignInApi.getSignInIntent(googleSignInHelper.getGoogleClient());
startActivityForResult(signInIntent, GoogleSignInHelper.RC_SIGN_IN);
}

// [END signin]

Read Integrate Google Sign In online: https://riptutorial.com/android/topic/2837/integrate-google-


sign-in

https://riptutorial.com/ 741
Chapter 139: Integrate OpenCV into Android
Studio
Remarks
The Open CV libraries can be found on the web by using a search engine.

The Gotchas:

• If you lower your target platform below KitKat some of the OpenCV libraries will no longer
function, specifically the classes related to org.opencv.android.Camera2Renderer and other
related classes. You can probably get around this by simply removing the apprpriate
OpenCV .java files.
• If you raise your target platform to Lollipop or above my example of loading a file might not
work because use of absolute file paths is frowned upon. So you might have to change the
example to load a file from the gallery or somewhere else. There are numerous examples
floating around.

Examples
Instructions

Tested with A.S. v1.4.1 but should work with newer versions too.

1. Create a new Android Studio project using the project wizard (Menu:/File/New Project):

• Call it "cvtest1"
• Form factor: API 19, Android 4.4 (KitKat)
• Blank Activity named MainActivity

You should have a cvtest1 directory where this project is stored. (the title bar of Android
studio shows you where cvtest1 is when you open the project)

2. Verify that your app runs correctly. Try changing something like the "Hello World" text to
confirm that the build/test cycle is OK for you. (I'm testing with an emulator of an API 19
device).

3. Download the OpenCV package for Android v3.1.0 and unzip it in some temporary directory
somewhere. (Make sure it is the package specifically for Android and not just the OpenCV
for Java package.) I'll call this directory "unzip-dir" Below unzip-dir you should have a
sdk/native/libs directory with subdirectories that start with things like arm..., mips... and x86
... (one for each type of "architecture" Android runs on)

4. From Android Studio import OpenCV into your project as a module:


Menu:/File/New/Import_Module:

https://riptutorial.com/ 742
• Source-directory: {unzip-dir}/sdk/java
• Module name: Android studio automatically fills in this field with openCVLibrary310
(the exact name probably doesn't matter but we'll go with this).
• Click on next. You get a screen with three checkboxes and questions about jars,
libraries and import options. All three should be checked. Click on Finish.

Android Studio starts to import the module and you are shown an import-summary.txt file
that has a list of what was not imported (mostly javadoc files) and other pieces of
information.

https://riptutorial.com/ 743
But you also get an error message saying failed to find target with hash string 'android-
14'.... This happens because the build.gradle file in the OpenCV zip file you downloaded
says to compile using android API version 14, which by default you don't have with Android
Studio v1.4.1.

https://riptutorial.com/ 744
5. Open the project structure dialogue (Menu:/File/Project_Structure). Select the "app"
module, click on the Dependencies tab and add :openCVLibrary310 as a Module
Dependency. When you select Add/Module_Dependency it should appear in the list of
modules you can add. It will now show up as a dependency but you will get a few more
cannot-find-android-14 errors in the event log.

6. Look in the build.gradle file for your app module. There are multiple build.gradle files in an
Android project. The one you want is in the cvtest1/app directory and from the project view it
looks like build.gradle (Module: app). Note the values of these four fields:

• compileSDKVersion (mine says 23)


• buildToolsVersion (mine says 23.0.2)
• minSdkVersion (mine says 19)
• targetSdkVersion (mine says 23)

7. Your project now has a cvtest1/OpenCVLibrary310 directory but it is not visible from the
project view:

Use some other tool, such as any file manager, and go to this directory. You can also switch the
project view from Android to Project Files and you can find this directory as shown in this
screenshot:

https://riptutorial.com/ 745
Inside there is another build.gradle file (it's highlighted in the above screenshot). Update this file
with the four values from step 6.

8. Resynch your project and then clean/rebuild it. (Menu:/Build/Clean_Project) It should clean
and build without errors and you should see many references to :openCVLibrary310 in the
0:Messages screen.

At this point the module should appear in the project hierarchy as openCVLibrary310, just
like app. (Note that in that little drop-down menu I switched back from Project View to
Android View ). You should also see an additional build.gradle file under "Gradle Scripts"
but I find the Android Studio interface a little bit glitchy and sometimes it does not do this
right away. So try resynching, cleaning, even restarting Android Studio.

You should see the openCVLibrary310 module with all the OpenCV functions under java like
in this screenshot:

https://riptutorial.com/ 746
9. Copy the {unzip-dir}/sdk/native/libs directory (and everything under it) to your Android
project, to cvtest1/OpenCVLibrary310/src/main/, and then rename your copy from libs to
jniLibs. You should now have a cvtest1/OpenCVLibrary310/src/main/jniLibs directory.
Resynch your project and this directory should now appear in the project view under
openCVLibrary310.

https://riptutorial.com/ 747
10. Go to the onCreate method of MainActivity.java and append this code:

if (!OpenCVLoader.initDebug()) {
Log.e(this.getClass().getSimpleName(), " OpenCVLoader.initDebug(), not working.");
} else {
Log.d(this.getClass().getSimpleName(), " OpenCVLoader.initDebug(), working.");
}

Then run your application. You should see lines like this in the Android Monitor:

https://riptutorial.com/ 748
(I don't know why that line with the error message is there)

11. Now try to actually use some openCV code. In the example below I copied a .jpg file to the
cache directory of the cvtest1 application on the android emulator. The code below loads this
image, runs the canny edge detection algorithm and then writes the results back to a .png
file in the same directory.

Put this code just below the code from the previous step and alter it to match your own
files/directories.

String inputFileName="simm_01";
String inputExtension = "jpg";
String inputDir = getCacheDir().getAbsolutePath(); // use the cache directory for i/o
String outputDir = getCacheDir().getAbsolutePath();
String outputExtension = "png";
String inputFilePath = inputDir + File.separator + inputFileName + "." + inputExtension;

Log.d (this.getClass().getSimpleName(), "loading " + inputFilePath + "...");


Mat image = Imgcodecs.imread(inputFilePath);
Log.d (this.getClass().getSimpleName(), "width of " + inputFileName + ": " +
image.width());
// if width is 0 then it did not read your image.

// for the canny edge detection algorithm, play with these to see different results
int threshold1 = 70;
int threshold2 = 100;

https://riptutorial.com/ 749
Mat im_canny = new Mat(); // you have to initialize output image before giving it to the
Canny method
Imgproc.Canny(image, im_canny, threshold1, threshold2);
String cannyFilename = outputDir + File.separator + inputFileName + "_canny-" + threshold1
+ "-" + threshold2 + "." + outputExtension;
Log.d (this.getClass().getSimpleName(), "Writing " + cannyFilename);
Imgcodecs.imwrite(cannyFilename, im_canny);

12. Run your application. Your emulator should create a black and white "edge" image. You can
use the Android Device Monitor to retrieve the output or write an activity to show it.

Read Integrate OpenCV into Android Studio online:


https://riptutorial.com/android/topic/7068/integrate-opencv-into-android-studio

https://riptutorial.com/ 750
Chapter 140: Intent
Introduction
An Intent is a small message passed around the Android system. This message may hold
information about our intention to perform a task.

It is basically a passive data structure holding an abstract description of an action to be performed.

Syntax
• Intent Intent()
• Intent Intent(Intent intent)
• Intent Intent(String action)
• Intent Intent(String action, Uri uri)
• Intent Intent(Context packageContext, Class<?> cls)
• Intent Intent(String action, Uri uri, Context packageContext, Class<?> cls)
• void startActivity(Intent intent)
• void startActivity(Intent intent, Bundle options)
• void startActivityForResult (Intent intent, int requestCode)
• void startActivityForResult (Intent intent, int requestCode, Bundle options)
• Intent putExtra(String name, double[] value)
• Intent putExtra(String name, int value)
• Intent putExtra(String name, CharSequence value)
• Intent putExtra(String name, char value)
• Intent putExtra(String name, Bundle value)
• Intent putExtra(String name, Parcelable[] value)
• Intent putExtra(String name, Serializable value)
• Intent putExtra(String name, int[] value)
• Intent putExtra(String name, float value)
• Intent putExtra(String name, byte[] value)
• Intent putExtra(String name, long[] value)
• Intent putExtra(String name, Parcelable value)
• Intent putExtra(String name, float[] value)
• Intent putExtra(String name, long value)
• Intent putExtra(String name, String[] value)
• Intent putExtra(String name, boolean value)
• Intent putExtra(String name, boolean[] value)
• Intent putExtra(String name, short value)
• Intent putExtra(String name, double value)
• Intent putExtra(String name, short[] value)
• Intent putExtra(String name, String value)
• Intent putExtra(String name, byte value)
• Intent putExtra(String name, char[] value)

https://riptutorial.com/ 751
• Intent putExtra(String name, CharSequence[] value)

Parameters

Parameter Details

intent The intent to start

requestCode Unique number to identify the request

Additional options for how the Activity should be


options
started

name The name of the extra data

value The value of the extra data

the code of the request, to identify it on


CHOOSE_CONTACT_REQUEST_CODE
onActivityResult method

Any action to perform via this intent, ex:


action
Intent.ACTION_VIEW

data uri to be used by intent to perform specified


uri
action

packageContext Context to use to initialize the Intent

cls Class to be used by this intent

Remarks

Caveats of using implicit intent


When calling a implicit intent it's always helpful to check if it's possible by the system to handle it.

This can be done by checking using PackageManager.queryIntentActivities(Intent intent, int


flags)

PackageManager pm = getActivity().getPackageManager();
if (intent.resolveActivity(pm) != null) {
//intent can be handled
startActivity(intent);
} else {
//intent can not be handled
}

https://riptutorial.com/ 752
Starting Activity which is a singleTask or singleTop

When the activity's launch mode is singleTask or singleTop, the onActivityResult will be called as
soon as the activity is started with a data null. To prevent this, use Intent.setFlags(0) to reset the
default flags.

Examples
Start an activity

This example will start DestinationActivity from OriginActivity.

Here, the Intent constructor takes two parameters:

1. A Context as its first parameter (this is used because the Activity class is a subclass of
Context)
2. The Class of the app component to which the system should deliver the Intent (in this case,
the activity that should be started)

public class OriginActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_origin);

Intent intent = new Intent(this, DestinationActivity.class);

startActivity(intent);
finish(); // Optionally, you can close OriginActivity. In this way when the user press
back from DestinationActivity he/she won't land on OriginActivity again.
}
}

Another way to create the Intent to open DestinationActivity is to use the default constructor for
the Intent, and use the setClass() method to tell it which Activity to open:

Intent i=new Intent();


i.setClass(this, DestinationActivity.class);
startActivity(intent);
finish(); // Optionally, you can close OriginActivity. In this way when the user press back
from DestinationActivity he/she won't land on OriginActivity

Passing data between activities

This example illustrates sending a String with value as "Some data!" from OriginActivity to
DestinationActivity.

NOTE: This is the most straightforward way of sending data between two activities. See the
example on using the starter pattern for a more robust implementation.

https://riptutorial.com/ 753
OriginActivity
public class OriginActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_origin);

// Create a new Intent object, containing DestinationActivity as target Activity.


final Intent intent = new Intent(this, DestinationActivity.class);

// Add data in the form of key/value pairs to the intent object by using putExtra()
intent.putExtra(DestinationActivity.EXTRA_DATA, "Some data!");

// Start the target Activity with the intent object


startActivity(intent);
}
}

DestinationActivity
public class DestinationActivity extends AppCompatActivity {

public static final String EXTRA_DATA = "EXTRA_DATA";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_destination);

// getIntent() returns the Intent object which was used to start this Activity
final Intent intent = getIntent();

// Retrieve the data from the intent object by using the same key that
// was previously used to add data to the intent object in OriginActivity.
final String data = intent.getStringExtra(EXTRA_DATA);
}
}

It is also possible to pass other primitive data types as well as arrays, Bundle and Parcelable data.
Passing Serializable is also possible, but should be avoided as it is more than three times slower
than Parcelable.

Serializable is a standard Java interface. You simply mark a class as Serializable by


implementing the Serializable interface and Java will automatically serialize it during required
situations.

Parcelable is an Android specific interface which can be implemented on custom data types (i.e.
your own objects / POJO objects ), it allows your object to be flattened and reconstruct itself
without the destination needing to do anything. There is a documentation example of making an
object parcelable.

https://riptutorial.com/ 754
Once you have a parcelable object you can send it like a primitive type, with an intent object:

intent.putExtra(DestinationActivity.EXTRA_DATA, myParcelableObject);

Or in a bundle / as an argument for a fragment:

bundle.putParcelable(DestinationActivity.EXTRA_DATA, myParcelableObject);

and then also read it from the intent at the destination using getParcelableExtra:

final MyParcelableType data = intent.getParcelableExtra(EXTRA_DATA);

Or when reading in a fragment from a bundle:

final MyParcelableType data = bundle.getParcelable(EXTRA_DATA);

Once you have a Serializable object you can put it in an intent object:

bundle.putSerializable(DestinationActivity.EXTRA_DATA, mySerializableObject);

and then also read it from the intent object at the destination as shown below:

final SerializableType data = (SerializableType)bundle.getSerializable(EXTRA_DATA);

Sending emails

// Compile a Uri with the 'mailto' schema


Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(
"mailto","[email protected]", null));
// Subject
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Hello World!");
// Body of email
emailIntent.putExtra(Intent.EXTRA_TEXT, "Hi! I am sending you a test email.");
// File attachment
emailIntent.putExtra(Intent.EXTRA_STREAM, attachedFileUri);

// Check if the device has an email client


if (emailIntent.resolveActivity(getPackageManager()) != null) {
// Prompt the user to select a mail app
startActivity(Intent.createChooser(emailIntent,"Choose your mail application"));
} else {
// Inform the user that no email clients are installed or provide an alternative
}

This will pre-fill an email in a mail app of the user's choice.

If you need to add an attachment, you can use Intent.ACTION_SEND instead of Intent.ACTION_SENDTO.
For multiple attachments you can use ACTION_SEND_MULTIPLE

A word of caution: not every device has a provider for ACTION_SENDTO, and calling startActivity()

https://riptutorial.com/ 755
without checking with resolveActivity() first may throw an ActivityNotFoundException.

Getting a result from another Activity

By using startActivityForResult(Intent intent, int requestCode) you can start another Activity
and then receive a result from that Activity in the onActivityResult(int requestCode, int
resultCode, Intent data) method. The result will be returned as an Intent. An intent can contain
data via a Bundle

In this example MainActivity will start a DetailActivity and then expect a result from it. Each
request type should have its own int request code, so that in the overridden onActivityResult(int
requestCode, int resultCode, Intent data) method in MainActivity , it can be determined which
request to process by comparing values of requestCode and REQUEST_CODE_EXAMPLE (though in this
example, there is only one).

MainActivity:

public class MainActivity extends Activity {

// Use a unique request code for each use case


private static final int REQUEST_CODE_EXAMPLE = 0x9345;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Create a new instance of Intent to start DetailActivity


final Intent intent = new Intent(this, DetailActivity.class);

// Start DetailActivity with the request code


startActivityForResult(intent, REQUEST_CODE_EXAMPLE);
}

// onActivityResult only get called


// when the other Activity previously started using startActivityForResult
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

// First we need to check if the requestCode matches the one we used.


if(requestCode == REQUEST_CODE_EXAMPLE) {

// The resultCode is set by the DetailActivity


// By convention RESULT_OK means that whatever
// DetailActivity did was executed successfully
if(resultCode == Activity.RESULT_OK) {
// Get the result from the returned Intent
final String result = data.getStringExtra(DetailActivity.EXTRA_DATA);

// Use the data - in this case, display it in a Toast.


Toast.makeText(this, "Result: " + result, Toast.LENGTH_LONG).show();
} else {
// setResult wasn't successfully executed by DetailActivity

https://riptutorial.com/ 756
// Due to some error or flow of control. No data to retrieve.
}
}
}
}

DetailActivity:

public class DetailActivity extends Activity {

// Constant used to identify data sent between Activities.


public static final String EXTRA_DATA = "EXTRA_DATA";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);

final Button button = (Button) findViewById(R.id.button);


// When this button is clicked we want to return a result
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Create a new Intent object as container for the result
final Intent data = new Intent();

// Add the required data to be returned to the MainActivity


data.putExtra(EXTRA_DATA, "Some interesting data!");

// Set the resultCode as Activity.RESULT_OK to


// indicate a success and attach the Intent
// which contains our result data
setResult(Activity.RESULT_OK, data);

// With finish() we close the DetailActivity to


// return back to MainActivity
finish();
}
});
}

@Override
public void onBackPressed() {
// When the user hits the back button set the resultCode
// as Activity.RESULT_CANCELED to indicate a failure
setResult(Activity.RESULT_CANCELED);
super.onBackPressed();
}
}

A few things you need to be aware of:


• Data is only returned once you call finish(). You need to call setResult() before calling
finish(), otherwise, no result will be returned.

https://riptutorial.com/ 757
• Make sure your Activity is not using android:launchMode="singleTask", or it will cause the
Activity to run in a separate task and therefore you will not receive a result from it. If your
Activity uses singleTask as launch mode, it will call onActivityResult() immediately with a
result code of Activity.RESULT_CANCELED.

• Be careful when using android:launchMode="singleInstance". On devices before Lollipop


(Android 5.0, API Level 21), Activities will not return a result.

• You can use explicit or implicit intents when you call startActivityForResult(). When starting
one of your own activities to receive a result, you should use an explicit intent to ensure that
you receive the expected result. An explicit intent is always delivered to its target, no matter
what it contains; the filter is not consulted. But an implicit intent is delivered to a component
only if it can pass through one of the component's filters.

Open a URL in a browser

Opening with the default browser


This example shows how you can open a URL programmatically in the built-in web browser rather
than within your application. This allows your app to open up a webpage without the need to
include the INTERNET permission in your manifest file.

public void onBrowseClick(View v) {


String url = "http://www.google.com";
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
// Verify that the intent will resolve to an activity
if (intent.resolveActivity(getPackageManager()) != null) {
// Here we use an intent without a Chooser unlike the next example
startActivity(intent);
}
}

Prompting the user to select a browser


Note that this example uses the Intent.createChooser() method:

public void onBrowseClick(View v) {


String url = "http://www.google.com";
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
// Note the Chooser below. If no applications match,
// Android displays a system message.So here there is no need for try-catch.
startActivity(Intent.createChooser(intent, "Browse with"));

In some cases, the URL may start with "www". If that is the case you will get this exception:

android.content.ActivityNotFoundException : No Activity found to handle Intent

https://riptutorial.com/ 758
The URL must always start with "http://" or "https://". Your code should therefore check for it, as
shown in the following code snippet:

if (!url.startsWith("https://") && !url.startsWith("http://")){


url = "http://" + url;
}
Intent openUrlIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
if (openUrlIntent.resolveActivity(getPackageManager()) != null) {
startActivity(openUrlIntent);
}

Best Practices
Check if there are no apps on the device that can receive the implicit intent. Otherwise, your app
will crash when it calls startActivity(). To first verify that an app exists to receive the intent, call
resolveActivity() on your Intent object. If the result is non-null, there is at least one app that can
handle the intent and it's safe to call startActivity(). If the result is null, you should not use the
intent and, if possible, you should disable the feature that invokes the intent.

Clearing an activity stack

Sometimes you may want to start a new activity while removing previous activities from the back
stack, so the back button doesn't take you back to them. One example of this might be starting an
app on the Login activity, taking you through to the Main activity of your application, but on logging
out you want to be directed back to Login without a chance to go back. In a case like that you can
set the FLAG_ACTIVITY_CLEAR_TOP flag for the intent, meaning if the activity being launched is already
running in the current task (LoginActivity), then instead of launching a new instance of that activity,
all of the other activities on top of it will be closed and this Intent will be delivered to the (now on
top) old activity as a new Intent.

Intent intent = new Intent(getApplicationContext(), LoginActivity.class);


intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

It's also possible to use the flags FLAG_ACTIVITY_NEW_TASK along with FLAG_ACTIVITY_CLEAR_TASK if you
want to clear all Activities on the back stack:

Intent intent = new Intent(getApplicationContext(), LoginActivity.class);


// Closing all the Activities, clear the back stack.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);

Intent URI

This example shows, how to start intent from browser:

<a href="intent://host.com/path#Intent;package=com.sample.test;scheme=yourscheme;end">Start
intent</a>

https://riptutorial.com/ 759
This intent will start app with package com.sample.test or will open google play with this package.

Also this intent can be started with javascript:

var intent = "intent://host.com/path#Intent;package=com.sample.test;scheme=yourscheme;end";


window.location.replace(intent)

In activity this host and path can be obtained from intent data:

@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Uri data = getIntent().getData(); // returns host.com/path
}

Intent URI syntax:

HOST/URI-path // Optional host


#Intent;
package=[string];
action=[string];
category=[string];
component=[string];
scheme=[string];
end;

Broadcasting Messages to Other Components

Intents can be used to broadcast messages to other components of your application (such as a
running background service) or to the entire Android system.

To send a broadcast within your application, use the LocalBroadcastManager class:

Intent intent = new Intent("com.example.YOUR_ACTION"); // the intent action


intent.putExtra("key", "value"); // data to be passed with your broadcast

LocalBroadcastManager manager = LocalBroadcastManager.getInstance(context);


manager.sendBroadcast(intent);

To send a broadcast to components outside of your application, use the sendBroadcast() method
on a Context object.

Intent intent = new Intent("com.example.YOUR_ACTION"); // the intent action


intent.putExtra("key", "value"); // data to be passed with your broadcast

context.sendBroadcast(intent);

Information about receiving broadcasts can be found here: Broadcast Receiver

CustomTabsIntent for Chrome Custom Tabs

4.0.3

https://riptutorial.com/ 760
Using a CustomTabsIntent, it is now possible to configure Chrome custom tabs in order to customize
key UI components in the browser that is opened from your app.

This is a good alternative to using a WebView for some cases. It allows loading of a web page with
an Intent, with the added ability to inject some degree of the look and feel of your app into the
browser.

Here is an example of how to open a url using CustomTabsIntent

String url = "https://www.google.pl/";


CustomTabsIntent intent = new CustomTabsIntent.Builder()
.setStartAnimations(getContext(), R.anim.slide_in_right,
R.anim.slide_out_left)
.setExitAnimations(getContext(), android.R.anim.slide_in_left,
android.R.anim.slide_out_right)
.setCloseButtonIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_arrow_back_white_24dp))
.setToolbarColor(Color.parseColor("#43A047"))
.enableUrlBarHiding()
.build();
intent.launchUrl(getActivity(), Uri.parse(url));

Note:

To use custom tabs, you need to add this dependency to your build.gradle

compile 'com.android.support:customtabs:24.1.1'

Sharing Multiple Files through Intent

The String List passed as a parameter to the share() method contains the paths of all the files you
want to share.

It basically loops through the paths, adds them to Uri, and starts the Activity which can accept
Files of this type.

public static void share(AppCompatActivity context,List<String> paths) {

if (paths == null || paths.size() == 0) {


return;
}
ArrayList<Uri> uris = new ArrayList<>();
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_SEND_MULTIPLE);
intent.setType("*/*");
for (String path : paths) {
File file = new File(path);
uris.add(Uri.fromFile(file));
}
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
context.startActivity(intent);
}

https://riptutorial.com/ 761
Starter Pattern

This pattern is a more strict approach to starting an Activity. Its purpose is to improve code
readability, while at the same time decrease code complexity, maintenance costs, and coupling of
your components.

The following example implements the starter pattern, which is usually implemented as a static
method on the Activity itself. This static method accepts all required parameters, constructs a
valid Intent from that data, and then starts the Activity.

An Intent is an object that provides runtime binding between separate components, such as two
activities. The Intent represents an app’s "intent to do something." You can use intents for a wide
variety of tasks, but here, your intent starts another activity.

public class ExampleActivity extends AppCompatActivity {

private static final String EXTRA_DATA = "EXTRA_DATA";

public static void start(Context context, String data) {


Intent intent = new Intent(context, ExampleActivity.class);
intent.putExtra(EXTRA_DATA, data);
context.startActivity(intent);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

Intent intent = getIntent();


if(!intent.getExtras().containsKey(EXTRA_DATA)){
throw new UnsupportedOperationException("Activity should be started using the
static start method");
}
String data = intent.getStringExtra(EXTRA_DATA);
}
}

This pattern also allows you to force additional data to be passed with the intent.

The ExampleActivity can then be started like this, where context is an activity context:

ExampleActivity.start(context, "Some data!");

Start Unbound Service using an Intent

A Service is a component which runs in the background (on the UI thread) without direct
interaction with the user. An unbound Service is just started, and is not bound to the lifecycle of
any Activity.

To start a Service you can do as shown in the example below:

// This Intent will be used to start the service

https://riptutorial.com/ 762
Intent i= new Intent(context, ServiceName.class);
// potentially add data to the intent extras
i.putExtra("KEY1", "Value to be used by the service");
context.startService(i);

You can use any extras from the intent by using an onStartCommand() override:

public class MyService extends Service {


public MyService() {
}

@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
if (intent != null) {
Bundle extras = intent.getExtras();
String key1 = extras.getString("KEY1", "");
if (key1.equals("Value to be used by the service")) {
//do something
}
}
return START_STICKY;
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

Share intent

Share simple information with differents apps.

Intent sendIntent = new Intent();


sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_to)));

Share an image with differents apps.

Intent shareIntent = new Intent();


shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
shareIntent.setType("image/jpeg");
startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)));

Start the dialer

This example shows how to open a default dialer (an app that makes regular calls) with a provided
telephone number already in place:

https://riptutorial.com/ 763
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:9988776655")); //Replace with valid phone number. Remember to
add the tel: prefix, otherwise it will crash.
startActivity(intent);

Result from running the code above:

Open Google map with specified latitude, longitude

You can pass latitude, longitude from your app to Google map using Intent

String uri = String.format(Locale.ENGLISH, "http://maps.google.com/maps?q=loc:%f,%f",


28.43242324,77.8977673);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent);

Passing different data through Intent in Activity

1. Passing integer data:

SenderActivity

Intent myIntent = new Intent(SenderActivity.this, ReceiverActivity.class);

https://riptutorial.com/ 764
myIntent.putExtra("intVariableName", intValue);
startActivity(myIntent);

ReceiverActivity

Intent mIntent = getIntent();


int intValue = mIntent.getIntExtra("intVariableName", 0); // set 0 as the default value if no
value for intVariableName found

2. Passing double data:

SenderActivity

Intent myIntent = new Intent(SenderActivity.this, ReceiverActivity.class);


myIntent.putExtra("doubleVariableName", doubleValue);
startActivity(myIntent);

ReceiverActivity

Intent mIntent = getIntent();


double doubleValue = mIntent.getDoubleExtra("doubleVariableName", 0.00); // set 0.00 as the
default value if no value for doubleVariableName found

3. Passing String data:

SenderActivity

Intent myIntent = new Intent(SenderActivity.this, ReceiverActivity.class);


myIntent.putExtra("stringVariableName", stringValue);
startActivity(myIntent);

ReceiverActivity

Intent mIntent = getIntent();


String stringValue = mIntent.getExtras().getString("stringVariableName");

or

Intent mIntent = getIntent();


String stringValue = mIntent.getStringExtra("stringVariableName");

4. Passing ArrayList data :

SenderActivity

Intent myIntent = new Intent(SenderActivity.this, ReceiverActivity.class);


myIntent.putStringArrayListExtra("arrayListVariableName", arrayList);
startActivity(myIntent);

ReceiverActivity

https://riptutorial.com/ 765
Intent mIntent = getIntent();
arrayList = mIntent.getStringArrayListExtra("arrayListVariableName");

5. Passing Object data :

SenderActivity

Intent myIntent = new Intent(SenderActivity.this, ReceiverActivity.class);


myIntent.putExtra("ObjectVariableName", yourObject);
startActivity(myIntent);

ReceiverActivity

Intent mIntent = getIntent();


yourObj = mIntent.getSerializableExtra("ObjectVariableName");

Note : Keep in mind your custom Class must implement the Serializable interface.

6. Passing HashMap<String, String> data :

SenderActivity

HashMap<String, String> hashMap;

Intent mIntent = new Intent(SenderActivity.this, ReceiverActivity.class);


mIntent.putExtra("hashMap", hashMap);
startActivity(mIntent);

ReceiverActivity

Intent mIntent = getIntent();


HashMap<String, String> hashMap = (HashMap<String, String>)
mIntent.getSerializableExtra("hashMap");

7. Passing Bitmap data :

SenderActivity

Intent myIntent = new Intent(SenderActivity.this, ReceiverActivity.class);


myIntent.putExtra("image",bitmap);
startActivity(mIntent);

ReceiverActivity

Intent mIntent = getIntent();


Bitmap bitmap = mIntent.getParcelableExtra("image");

Showing a File Chooser and Reading the Result

https://riptutorial.com/ 766
Starting a File Chooser Activity

public void showFileChooser() {


Intent intent = new Intent(Intent.ACTION_GET_CONTENT);

// Update with mime types


intent.setType("*/*");

// Update with additional mime types here using a String[].


intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);

// Only pick openable and local files. Theoretically we could pull files from google drive
// or other applications that have networked files, but that's unnecessary for this
example.
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);

// REQUEST_CODE = <some-integer>
startActivityForResult(intent, REQUEST_CODE);
}

Reading the Result

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// If the user doesn't pick a file just return
if (requestCode != REQUEST_CODE || resultCode != RESULT_OK) {
return;
}

// Import the file


importFile(data.getData());
}

public void importFile(Uri uri) {


String fileName = getFileName(uri);

// The temp file could be whatever you want


File fileCopy = copyToTempFile(uri, File tempFile)

// Done!
}

/**
* Obtains the file name for a URI using content resolvers. Taken from the following link
* https://developer.android.com/training/secure-file-sharing/retrieve-
info.html#RetrieveFileInfo
*
* @param uri a uri to query
* @return the file name with no path
* @throws IllegalArgumentException if the query is null, empty, or the column doesn't exist
*/
private String getFileName(Uri uri) throws IllegalArgumentException {
// Obtain a cursor with information regarding this uri
Cursor cursor = getContentResolver().query(uri, null, null, null, null);

if (cursor.getCount() <= 0) {

https://riptutorial.com/ 767
cursor.close();
throw new IllegalArgumentException("Can't obtain file name, cursor is empty");
}

cursor.moveToFirst();

String fileName =
cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));

cursor.close();

return fileName;
}

/**
* Copies a uri reference to a temporary file
*
* @param uri the uri used as the input stream
* @param tempFile the file used as an output stream
* @return the input tempFile for convenience
* @throws IOException if an error occurs
*/
private File copyToTempFile(Uri uri, File tempFile) throws IOException {
// Obtain an input stream from the uri
InputStream inputStream = getContentResolver().openInputStream(uri);

if (inputStream == null) {
throw new IOException("Unable to obtain input stream from URI");
}

// Copy the stream to the temp file


FileUtils.copyInputStreamToFile(inputStream, tempFile);

return tempFile;
}

Passing custom object between activities

It is also possible to pass your custom object to other activities using the Bundle class.

There are two ways:

• Serializable interface—for Java and Android


• Parcelable interface—memory efficient, only for Android (recommended)

Parcelable
Parcelable processing is much faster than serializable. One of the reasons for this is that we are
being explicit about the serialization process instead of using reflection to infer it. It also stands to
reason that the code has been heavily optimized for this purpose.

public class MyObjects implements Parcelable {

private int age;


private String name;

https://riptutorial.com/ 768
private ArrayList<String> address;

public MyObjects(String name, int age, ArrayList<String> address) {


this.name = name;
this.age = age;
this.address = address;

public MyObjects(Parcel source) {


age = source.readInt();
name = source.readString();
address = source.createStringArrayList();
}

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
dest.writeStringList(address);
}

public int getAge() {


return age;
}

public String getName() {


return name;
}

public ArrayList<String> getAddress() {


if (!(address == null))
return address;
else
return new ArrayList<String>();
}

public static final Creator<MyObjects> CREATOR = new Creator<MyObjects>() {


@Override
public MyObjects[] newArray(int size) {
return new MyObjects[size];
}

@Override
public MyObjects createFromParcel(Parcel source) {
return new MyObjects(source);
}
};
}

Sending Activity Code

MyObject mObject = new MyObject("name","age","Address array here");

https://riptutorial.com/ 769
//Passing MyOject
Intent mIntent = new Intent(FromActivity.this, ToActivity.class);
mIntent.putExtra("UniqueKey", mObject);
startActivity(mIntent);

Receiving the object in destination activity.

//Getting MyObjects
Intent mIntent = getIntent();
MyObjects workorder = (MyObjects) mIntent.getParcelable("UniqueKey");

You can pass Arraylist of Parceble object as below

//Array of MyObjects
ArrayList<MyObject> mUsers;

//Passing MyObject List


Intent mIntent = new Intent(FromActivity.this, ToActivity.class);
mIntent.putParcelableArrayListExtra("UniqueKey", mUsers);
startActivity(mIntent);

//Getting MyObject List


Intent mIntent = getIntent();
ArrayList<MyObjects> mUsers = mIntent.getParcelableArrayList("UniqueKey");

Note: There are Android Studio plugins such as this one available to generate
Parcelable code

Serializable
Sending Activity Code

Product product = new Product();


Bundle bundle = new Bundle();
bundle.putSerializable("product", product);
Intent cartIntent = new Intent(mContext, ShowCartActivity.class);
cartIntent.putExtras(bundle);
mContext.startActivity(cartIntent);

Receiving the object in destination activity.

protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);
Bundle bundle = this.getIntent().getExtras();
Product product = null;
if (bundle != null) {
product = (Product) bundle.getSerializable("product");
}

Arraylist of Serializable object: same as single object passing

Custom object should implement the Serializable interface.

https://riptutorial.com/ 770
Getting a result from Activity to Fragment

Like Getting a result from another Activity you need to call the Fragment's method
startActivityForResult(Intent intent, int requestCode). note that you should not call
getActivity().startActivityForResult() as this will take the result back to the Fragment's parent
Activity.

Receiving the result can be done using the Fragment's method onActivityResult(). You need to
make sure that the Fragment's parent Activity also overrides onActivityResult() and calls it's super
implementation.

In the following example ActivityOne contains FragmentOne, which will start ActivityTwo and expect a
result from it.

ActivityOne

public class ActivityOne extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
}

// You must override this method as the second Activity will always send its results to
this Activity and then to the Fragment
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
}

activity_one.xml

<fragment android:name="com.example.FragmentOne"
android:id="@+id/fragment_one"
android:layout_width="match_parent"
android:layout_height="match_parent" />

FragmentOne

public class FragmentOne extends Fragment {


public static final int REQUEST_CODE = 11;
public static final int RESULT_CODE = 12;
public static final String EXTRA_KEY_TEST = "testKey";

// Initializing and starting the second Activity


private void startSecondActivity() {
Intent intent = new Intent(getActivity(), ActivityTwo.class);
startActivityForResult(REQUEST_CODE, intent);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

https://riptutorial.com/ 771
if (requestCode == REQUEST_CODE && resultCode == RESULT_CODE) {
String testResult = data.getStringExtra(EXTRA_KEY_TEST);
// TODO: Do something with your extra data
}
}
}

ActivityTwo

public class ActivityTwo extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);
}

private void closeActivity() {


Intent intent = new Intent();
intent.putExtra(FragmentOne.EXTRA_KEY_TEST, "Testing passing data back to
ActivityOne");
setResult(FragmentOne.RESULT_CODE, intent); // You can also send result without any
data using setResult(int resultCode)
finish();
}
}

Read Intent online: https://riptutorial.com/android/topic/103/intent

https://riptutorial.com/ 772
Chapter 141: IntentService
Syntax
4. <service android:name=".UploadS3IntentService"android:exported="false" />

Remarks
An IntentService provides a simple way to offload work on a background thread. It handles
everything about receiving requests, putting them in a queue, stopping itself, etc. for you. It is also
easy to implement, making it the perfect thing to use when you have time-consuming operations to
do that don't belong on the Main (UI) thread.

Examples
Creating an IntentService

To create an IntentService, create a class which extends IntentService, and within it, a method
which overrides onHandleIntent:

package com.example.myapp;
public class MyIntentService extends IntentService {
@Override
protected void onHandleIntent (Intent workIntent) {
//Do something in the background, based on the contents of workIntent.
}
}

Sample Intent Service

Here is an example of an IntentService that pretends to load images in the background. All you
need to do to implement an IntentService is to provide a constructor that calls the super(String)
constructor, and you need to implement the onHandleIntent(Intent) method.

public class ImageLoaderIntentService extends IntentService {

public static final String IMAGE_URL = "url";

/**
* Define a constructor and call the super(String) constructor, in order to name the
worker
* thread - this is important if you want to debug and know the name of the thread upon
* which this Service is operating its jobs.
*/
public ImageLoaderIntentService() {
super("Example");
}

https://riptutorial.com/ 773
@Override
protected void onHandleIntent(Intent intent) {
// This is where you do all your logic - this code is executed on a background thread

String imageUrl = intent.getStringExtra(IMAGE_URL);

if (!TextUtils.isEmpty(imageUrl)) {
Drawable image = HttpUtils.loadImage(imageUrl); // HttpUtils is made-up for the
example
}

// Send your drawable back to the UI now, so that you can use it - there are many ways
// to achieve this, but they are out of reach for this example
}
}

In order to start an IntentService, you need to send an Intent to it. You can do so from an Activity,
for an example. Of course, you're not limited to that. Here is an example of how you would
summon your new Service from an Activity class.

Intent serviceIntent = new Intent(this, ImageLoaderIntentService.class); // you can use 'this'


as the first parameter if your class is a Context (i.e. an Activity, another Service, etc.),
otherwise, supply the context differently
serviceIntent.putExtra(IMAGE_URL, "http://www.example-site.org/some/path/to/an/image");
startService(serviceIntent); // if you are not using 'this' in the first line, you also have
to put the call to the Context object before startService(Intent) here

The IntentService processes the data from its Intents sequentially, so that you can send multiple
Intents without worrying whether they will collide with each other. Only one Intent at a time is
processed, the rest go in a queue. When all the jobs are complete, the IntentService will shut itself
down automatically.

Basic IntentService Example

The abstract class IntentService is a base class for services, which run in the background without
any user interface. Therefore, in order to update the UI, we have to make use of a receiver, which
may be either a BroadcastReceiver or a ResultReceiver:

• A BroadcastReceiver should be used if your service needs to communicate with multiple


components that want to listen for communication.
• A ResultReceiver: should be used if your service needs to communicate with only the parent
application (i.e. your application).

Within the IntentService, we have one key method, onHandleIntent(), in which we will do all
actions, for example, preparing notifications, creating alarms, etc.

If you want to use you own IntentService, you have to extend it as follows:

public class YourIntentService extends IntentService {


public YourIntentService () {
super("YourIntentService ");
}

https://riptutorial.com/ 774
@Override
protected void onHandleIntent(Intent intent) {
// TODO: Write your own code here.
}
}

Calling/starting the activity can be done as follows:

Intent i = new Intent(this, YourIntentService.class);


startService(i); // For the service.
startActivity(i); // For the activity; ignore this for now.

Similar to any activity, you can pass extra information such as bundle data to it as follows:

Intent passDataIntent = new Intent(this, YourIntentService.class);


msgIntent.putExtra("foo","bar");
startService(passDataIntent);

Now assume that we passed some data to the YourIntentService class. Based on this data, an
action can be performed as follows:

public class YourIntentService extends IntentService {


private String actvityValue="bar";
String retrivedValue=intent.getStringExtra("foo");

public YourIntentService () {
super("YourIntentService ");
}

@Override
protected void onHandleIntent(Intent intent) {
if(retrivedValue.equals(actvityValue)){
// Send the notification to foo.
} else {
// Retrieving data failed.
}
}
}

The code above also shows how to handle constraints in the OnHandleIntent() method.

Read IntentService online: https://riptutorial.com/android/topic/5319/intentservice

https://riptutorial.com/ 775
Chapter 142: Inter-app UI testing with
UIAutomator
Syntax
• Instrumentation getInstrumentation()
• UIDevice UiDevice.getInstance(Instrumentation instrumentation)
• boolean UIDevice.pressHome()
• boolean UIDevice.pressBack()
• boolean UIDevice.pressRecentApps()
• void UIDevice.wakeUp()
• boolean UIDevice.swipe(int startX, int startY, int endX, int endY, int steps)
• boolean UIDevice.drag(int startX, int startY, int endX, int endY, int steps)
• UIObject2 UIDevice.findObject(By.desc(String contentDesc))
• boolean UIObject2.click()

Remarks
UIAutomator are especially good for testing user stories. You run into problems if view elements
have neither a unique resource-id nor content-desc. In most of the cases there is a way to
complete the test anyways, what that takes a lot of time. If you can influence the code of your app,
UIAutomator may be your testing tool.

Examples
Prepare your project and write the first UIAutomator test

Add the required libraries into the dependencies section of your Android module's build.gradle:

android {
...
defaultConfig {
...
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}

dependencies {
...
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5'
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
androidTestCompile 'com.android.support:support-annotations:23.4.0'
}

Note that of course the versions may differ in the mean time.

https://riptutorial.com/ 776
After this sync with the changes.

Then add a new Java class inside the androidTest folder:

public class InterAppTest extends InstrumentationTestCase {

private UiDevice device;

@Override
public void setUp() throws Exception {
device = UiDevice.getInstance(getInstrumentation());
}

public void testPressHome() throws Exception {


device.pressHome();
}
}

By making a right click on the class tab and on "Run "InterAppTest" executes this test.

Writing more complex tests using the UIAutomatorViewer

In order to enable writing more complex UI tests the UIAutomatorViewer is needed. The tool
located at /tools/ makes a fullscreen screenshot including the layouts of the currently displayed
views. See the subsequent picture to get an idea of what is shown:

For the UI tests we are looking for resource-id, content-desc or something else to identify a view
and use it inside our tests.

The uiautomatorviewer is executed via terminal.

https://riptutorial.com/ 777
If we now for instance want to click on the applications button and then open some app and swipe
around, this is how the test method can look like:

public void testOpenMyApp() throws Exception {


// wake up your device
device.wakeUp();

// switch to launcher (hide the previous application, if some is opened)


device.pressHome();

// enter applications menu (timeout=200ms)


device.wait(Until.hasObject(By.desc(("Apps"))), 200);
UiObject2 appsButton = device.findObject(By.desc(("Apps")));
assertNotNull(appsButton);
appsButton.click();

// enter some application (timeout=200ms)


device.wait(Until.hasObject(By.desc(("MyApplication"))), 200);
UiObject2 someAppIcon = device.findObject(By.desc(("MyApplication")));
assertNotNull(someAppIcon);
someAppIcon.click();

// do a swipe (steps=20 is 0.1 sec.)


device.swipe(200, 1200, 1300, 1200, 20);
assertTrue(isSomeConditionTrue)
}

Creating a test suite of UIAutomator tests

Putting UIAutomator tests together to a test suite is a quick thing:

package de.androidtest.myapplication;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses({InterAppTest1.class, InterAppTest2.class})
public class AppTestSuite {}

Execute similar to a single test by clicking right and run the suite.

Read Inter-app UI testing with UIAutomator online: https://riptutorial.com/android/topic/6249/inter-


app-ui-testing-with-uiautomator

https://riptutorial.com/ 778
Chapter 143: Interfaces
Examples
Custom Listener

Define interface
//In this interface, you can define messages, which will be send to owner.
public interface MyCustomListener {
//In this case we have two messages,
//the first that is sent when the process is successful.
void onSuccess(List<Bitmap> bitmapList);
//And The second message, when the process will fail.
void onFailure(String error);
}

Create listener
In the next step we need to define an instance variable in the object that will send callback via
MyCustomListener. And add setter for our listener.

public class SampleClassB {


private MyCustomListener listener;

public void setMyCustomListener(MyCustomListener listener) {


this.listener = listener;
}
}

Implement listener
Now, in other class, we can create instance of SampleClassB.

public class SomeActivity extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
SampleClassB sampleClass = new SampleClassB();
}
}

next we can set our listener, to sampleClass, in two ways:

by implements MyCustomListener in our class:

https://riptutorial.com/ 779
public class SomeActivity extends Activity implements MyCustomListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
SampleClassB sampleClass = new SampleClassB();
sampleClass.setMyCustomListener(this);
}

@Override
public void onSuccess(List<Bitmap> bitmapList) {

@Override
public void onFailure(String error) {

}
}

or just instantiate an anonymous inner class:

public class SomeActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
SampleClassB sampleClass = new SampleClassB();
sampleClass.setMyCustomListener(new MyCustomListener() {

@Override
public void onSuccess(List<Bitmap> bitmapList) {

@Override
public void onFailure(String error) {

}
});
}
}

Trigger listener
public class SampleClassB {
private MyCustomListener listener;

public void setMyCustomListener(MyCustomListener listener) {


this.listener = listener;
}

public void doSomething() {


fetchImages();
}

private void fetchImages() {


AsyncImagefetch imageFetch = new AsyncImageFetch();
imageFetch.start(new Response<Bitmap>() {

https://riptutorial.com/ 780
@Override
public void onDone(List<Bitmap> bitmapList, Exception e) {
//do some stuff if needed

//check if listener is set or not.


if(listener == null)
return;
//Fire proper event. bitmapList or error message will be sent to
//class which set listener.
if(e == null)
listener.onSuccess(bitmapList);
else
listener.onFailure(e.getMessage());
}
});
}
}

Basic Listener

The "listener" or "observer" pattern is the most common strategy for creating asynchronous
callbacks in Android development.

public class MyCustomObject {

//1 - Define the interface


public interface MyCustomObjectListener {
public void onAction(String action);
}

//2 - Declare your listener object


private MyCustomObjectListener listener;

// and initialize it in the costructor


public MyCustomObject() {
this.listener = null;
}

//3 - Create your listener setter


public void setCustomObjectListener(MyCustomObjectListener listener) {
this.listener = listener;
}

// 4 - Trigger listener event


public void makeSomething(){
if (this.listener != null){
listener.onAction("hello!");
}
}

Now on your Activity:

public class MyActivity extends Activity {


public final String TAG = "MyActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {

https://riptutorial.com/ 781
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);

MyCustomObject mObj = new MyCustomObject();

//5 - Implement listener callback


mObj.setCustomObjectListener(new MyCustomObjectListener() {
@Override
public void onAction(String action) {
Log.d(TAG, "Value: "+action);
}
});
}
}

Read Interfaces online: https://riptutorial.com/android/topic/1785/interfaces

https://riptutorial.com/ 782
Chapter 144: Internationalization and
localization (I18N and L10N)
Introduction
Internationalization (i18n) and Localization (L10n) are used to adapt software according to
differences in languages, regional differences and target audience.

Internationalization : the process of planning for future localization i.e. making the software design
flexible to an extent that it can adjust and adapt to future localization efforts.

Localization : the process of adapting the software to a particular region/country/market (locale).

Remarks
To test a device for localization, the device or the emulator can be rebooted in a particular locale
by using adb as follows :

1. Run adb using the command : adb shell


2. Run the following command at the adb command prompt : setprop persist.sys.locale [BCP-
47 language tag];stop;sleep 5;start where [BCP-47 language tag] is the language specific
code as described here : BCP47 codes

e.g. to check Japanese localization in the app, use the command : setprop persist.sys.locale ja-
JP;stop;sleep 5;start

Examples
Planning for localization : enable RTL support in Manifest

RTL (Right-to-left) support is an essential part in planning for i18n and L10n. Unlike English
language which is written from left to right, many languages like Arabic, Japanese, Hebrew, etc.
are written from right to left. To appeal to a more global audience, it is a good idea to plan your
layouts to support these language from the very beginning of the project, so that adding
localization is easier later on.

RTL support can be enabled in an Android app by adding the supportsRtl tag in the
AndroidManifest, like so :

<application
...
android:supportsRtl="true"
...>
...
</application>

https://riptutorial.com/ 783
Planning for localization : Add RTL support in Layouts

Starting SDK 17 (Android 4.2), RTL support was added in Android layouts and is an essential part
of localization. Going forward, the left/right notation in layouts should be replaced by start/end
notation. If, however, your project has a minSdk value less than 17, then both left/right and
start/end notation should be used in layouts.

For relative layouts, alignParentStart and alignParentEnd should be used, like so:

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
</RelativeLayout>

For specifying gravity and layout gravity, similar notation should be used, like so :

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|start"
android:gravity="left|start"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|end"
android:gravity="right|end"/>

Paddings and margins should also be specified accordingly, like so :

<include layout="@layout/notification"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginStart="12dp"
android:paddingLeft="128dp"
android:paddingStart="128dp"
android:layout_toLeftOf="@id/cancel_action"
android:layout_toStartOf="@id/cancel_action"/>
<include layout="@layout/notification2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginRight="12dp"
android:layout_marginEnd="12dp"
android:paddingRight="128dp"

https://riptutorial.com/ 784
android:paddingEnd="128dp"
android:layout_toRightOf="@id/cancel_action"
android:layout_toEndOf="@id/cancel_action"/>

Planning for localization : Test layouts for RTL

To test if the layouts that have been created are RTL compatible, do the following :

Go to Settings -> Developer options -> Drawing -> Force RTL layout direction

Enabling this option would force the device to use RTL locales and you can easily verify all parts
of the app for RTL support. Note that you don't need to actually add any new locales/ language
support up till this point.

Coding for Localization : Creating default strings and resources

The first step for coding for localization is to create default resources. This step is so implicit that
many developers do not even think about it. However, creating default resources is important
because if the device runs on an unsupported locale, it would load all of its resources from the
default folders. If even one of the resources is missing from the default folders, the app would
simply crash.

The default set of strings should be put in the following folder at the specified location:

res/values/strings.xml

This file should contain the strings in the language that majority users of the app are expected to
speak.

Also, default resources for the app should be placed at the following folders and locations :

res/drawable/
res/layout/

If your app requires folders like anim, or xml, the default resources should be added to the following
folders and locations:

res/anim/
res/xml/
res/raw/

Coding for localization : Providing alternative strings

To provide translations in other languages (locales), we need to create a strings.xml in a separate


folder by the following convention :

res/values-<locale>/strings.xml

https://riptutorial.com/ 785
An example for the same is given below:

In this example, we have default English strings in the file res/values/strings.xml, French
translations are provided in the folder res/values-fr/strings.xml and Japanese translations are
provided in the folder res/values-ja/strings.xml

Other translations for other locales can similarly be added to the app.

A complete list of locale codes can be found here : ISO 639 codes

Non-translatable Strings:

Your project may have certain strings that are not to be translated. Strings which are used as keys
for SharedPreferences or strings which are used as symbols, fall in this category. These strings
should be stored only in the default strings.xml and should be marked with a translatable="false"
attribute. e.g.

<string name="pref_widget_display_label_hot">Hot News</string>


<string name="pref_widget_display_key" translatable="false">widget_display</string>
<string name="pref_widget_display_hot" translatable="false">0</string>

This attribute is important because translations are often carried out by professionals who are
bilingual. This would allow these persons involved in translations to identify strings which are not
to be translated, thus saving time and money.

Coding for localization : Providing alternate layouts

Creating language specific layouts is often unnecessary if you have specified the correct start/end
notation, as described in the earlier example. However, there may be situations where the defaults
layouts may not work correctly for certain languages. Sometimes, left-to-right layouts may not
translate for RTL languages. It is necessary to provide the correct layouts in such cases.

To provide complete optimization for RTL layouts, we can use entirely separate layout files using
the ldrtl resource qualifier (ldrtl stands for layout-direction-right-to-left}). For example, we can
save your default layout files in res/layout/ and our RTL optimized layouts in res/layout-ldrtl/.

The ldrtl qualifier is great for drawable resources, so that you can provide graphics that are
oriented in the direction corresponding to the reading direction.

https://riptutorial.com/ 786
Here is a great post which describes the precedence of the ldrtl layouts : Language specific
layouts

Read Internationalization and localization (I18N and L10N) online:


https://riptutorial.com/android/topic/8796/internationalization-and-localization--i18n-and-l10n-

https://riptutorial.com/ 787
Chapter 145: Jackson
Introduction
Jackson is a multi-purpose Java library for processing JSON. Jackson aims to be the best
possible combination of fast, correct, lightweight, and ergonomic for developers.

Jackson features

Multi processing mode, and very good collaboration

Not only annotations, but also mixed annotations

Fully support generic types

Support polymorphic types

Examples
Full Data Binding Example

JSON data

{
"name" : { "first" : "Joe", "last" : "Sixpack" },
"gender" : "MALE",
"verified" : false,
"userImage" : "keliuyue"
}

It takes two lines of Java to turn it into a User instance:

ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally


User user = mapper.readValue(new File("user.json"), User.class);

User.class

public class User {

public enum Gender {MALE, FEMALE};

public static class Name {


private String _first, _last;

public String getFirst() {


return _first;
}

public String getLast() {


return _last;

https://riptutorial.com/ 788
}

public void setFirst(String s) {


_first = s;
}

public void setLast(String s) {


_last = s;
}
}

private Gender _gender;


private Name _name;
private boolean _isVerified;
private byte[] _userImage;

public Name getName() {


return _name;
}

public boolean isVerified() {


return _isVerified;
}

public Gender getGender() {


return _gender;
}

public byte[] getUserImage() {


return _userImage;
}

public void setName(Name n) {


_name = n;
}

public void setVerified(boolean b) {


_isVerified = b;
}

public void setGender(Gender g) {


_gender = g;
}

public void setUserImage(byte[] b) {


_userImage = b;
}
}

Marshalling back to JSON is similarly straightforward:

mapper.writeValue(new File("user-modified.json"), user);

Read Jackson online: https://riptutorial.com/android/topic/10878/jackson

https://riptutorial.com/ 789
Chapter 146: Java on Android
Introduction
Android supports all Java 7 language features and a subset of Java 8 language features that vary
by platform version. This page describes the new language features you can use, how to properly
configure your project to use them and any known issues you may encounter.

Examples
Java 8 features subset with Retrolambda

Retrolambda lets you run Java 8 code with lambda expressions, method references and try-with-
resources statements on Java 7, 6 or 5. It does this by transforming your Java 8 compiled
bytecode so that it can run on an older Java runtime.

Backported Language Features:

• Lambda expressions are backported by converting them to anonymous inner classes. This
includes the optimisation of using a singleton instance for stateless lambda expressions to
avoid repeated object allocation. Method references are basically just syntax sugar for
lambda expressions and they are backported in the same way.

• Try-with-resources statements are backported by removing calls to Throwable.addSuppressed if


the target bytecode version is below Java 7. If you would like the suppressed exceptions to
be logged instead of swallowed, please create a feature request and we'll make it
configurable.

• Objects.requireNonNull calls are replaced with calls to Object.getClass if the target bytecode
version is below Java 7. The synthetic null checks generated by JDK 9 use
Objects.requireNonNull, whereas earlier JDK versions used Object.getClass.

• Optionally also:

1. Default methods are backported by copying the default methods to a companion class
(interface name + "$") as static methods, replacing the default methods in the interface
with abstract methods, and by adding the necessary method implementations to all
classes which implement that interface.

2. Static methods on interfaces are backported by moving the static methods to a


companion class (interface name + "$"), and by changing all methods calls to call the
new method location.

Known Limitations:

• Does not backport Java 8 APIs

https://riptutorial.com/ 790
• Backporting default methods and static methods on interfaces requires all backported
interfaces and all classes which implement them or call their static methods to be backported
together, with one execution of Retrolambda. In other words, you must always do a clean
build. Also, backporting default methods won't work across module or dependency
boundaries.

• May break if a future JDK 8 build stops generating a new class for each invokedynamic call.
Retrolambda works so that it captures the bytecode that java.lang.invoke.LambdaMetafactory
generates dynamically, so optimisations to that mechanism may break Retrolambda.

Retrolambda gradle plugin will automatically build your android project with Retrolambda. The
latest version can be found on the releases page.

Usage:

1. Download and install jdk8


2. Add the following to your build.gradle

buildscript {
repositories {
mavenCentral()
}

dependencies {
classpath 'me.tatarka:gradle-retrolambda:<latest version>'
}
}

// Required because retrolambda is on maven central


repositories {
mavenCentral()
}

apply plugin: 'com.android.application' //or apply plugin: 'java'


apply plugin: 'me.tatarka.retrolambda'

android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

Known Issues:

• Lint fails on java files that have lambdas. Android's lint doesn't understand java 8 syntax and
will fail silently or loudly. There is now an experimental fork that fixes the issue.

• Using Google Play Services causes Retrolambda to fail. Version 5.0.77 contains bytecode
that is incompatible with Retrolambda. This should be fixed in newer versions of play
services, if you can update, that should be the preferred solution. To work around this issue,
you can either use an earlier version like 4.4.52 or add -noverify to the jvm args.

https://riptutorial.com/ 791
retrolambda {
jvmArgs '-noverify'
}

Read Java on Android online: https://riptutorial.com/android/topic/9223/java-on-android

https://riptutorial.com/ 792
Chapter 147: JCodec
Examples
Getting Started

You can get JCodec automatically with maven. For this just add below snippet to your pom.xml .

<dependency>
<groupId>org.jcodec</groupId>
<artifactId>jcodec-javase</artifactId>
<version>0.1.9</version>
</dependency>

Getting frame from movie

Getting a single frame from a movie ( supports only AVC, H.264 in MP4, ISO BMF, Quicktime
container ):

int frameNumber = 150;


BufferedImage frame = FrameGrab.getFrame(new File("filename.mp4"), frameNumber);
ImageIO.write(frame, "png", new File("frame_150.png"));

Getting a sequence of frames from a movie ( supports only AVC, H.264 in MP4, ISO BMF,
Quicktime container ):

double startSec = 51.632;


FileChannelWrapper ch = null;
try {
ch = NIOUtils.readableFileChannel(new File("filename.mp4"));
FrameGrab fg = new FrameGrab(ch);
grab.seek(startSec);
for (int i = 0; i < 100; i++) {
ImageIO.write(grab.getFrame(), "png",
new File(System.getProperty("user.home"), String.format("Desktop/frame_%08d.png",
i)));
}
} finally {
NIOUtils.closeQuietly(ch);
}

Read JCodec online: https://riptutorial.com/android/topic/9948/jcodec

https://riptutorial.com/ 793
Chapter 148: Jenkins CI setup for Android
Projects
Examples
Step by step approach to set up Jenkins for Android

This is a step by step guide to set up the automated build process using Jenkins CI for your
Android projects. The following steps assume that you have new hardware with just any flavor of
Linux installed. It is also taken into account that you might have a remote machine.

PART I: Initial setup on your machine


1. Log in via ssh to your Ubuntu machine:

ssh [email protected]

2. Download a version of the Android SDK on your machine:

wget https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz

3. Unzip the downloaded tar file:

sudo apt-get install tar


tar -xvf android-sdk_r24.4.1-linux.tgz

4. Now you need to install Java 8 on your Ubuntu machine, which is a requirement for Android
builds on Nougat. Jenkins would require you to install JDK and JRE 7 using the steps below:

sudo apt-get install python-software-properties


sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
apt-get install openjdk-8-jdk

5. Now install Jenkins on your Ubuntu machine:

wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -


sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ >
/etc/apt/sources.list.d/jenkins.list'
sudo apt-get update
sudo apt-get install jenkins

6. Download the latest supported Gradle version for your Android setup:

wget https://services.gradle.org/distributions/gradle-2.14.1-all.zip

https://riptutorial.com/ 794
unzip gradle-2.14.1-all.zip

7. Set up Android on your Ubuntu machine. First move to the tools folder in the Android SDK
folder downloaded in step 2:

cd android-sdk-linux/tools // lists available SDK


android update sdk --no-ui // Updates SDK version
android list sdk -a | grep "SDK Build-tools" // lists available build tools
android update sdk -a -u -t 4 // updates build tools version to one listed as 4
by prev. cmd.
update java

8. Install Git or any other VCS on your machine:

sudo apt-get install git

9. Now log in to Jenkins using your internet browser. Type ipAddress:8080 into the address bar.

10. In order to receive the password for the first-time login, please check the corresponding file
as follows (you will need su permissions to access this file):

cat /var/lib/jenkins/secrets/initialAdminPassword

PART II: Set up Jenkins to build Android


Jobs
1. Once logged in, go to the following path:

Jenkins > Manage Jenkins > Global Tool Configuration

2. At this location, add JAVA_HOME with the following entries:

Name = JAVA_HOME
JAVA_HOME = /usr/lib/jvm/java-8-openjdk-amd64

3. Also add the following values to Git and save the environment variables:

Name = Default
/usr/bin/git

4. Now go to the following path:

Jenkins > Manage Jenkins > Configuration

5. At this location, add ANDROID_HOME to the "global properties":

Name = ANDROID_HOME
Value = /home/username/android-sdk-linux

https://riptutorial.com/ 795
Part III: Create a Jenkins Job for your
Android project
1. Click on New Item in the Jenkins home screen.

2. Add a Project Name and Description.

3. In the General tab, select Advanced. Then select Use custom workspace:

Directory /home/user/Code/ProjectFolder

4. In the source code management select Git. I am using Bitbucket for the purpose of this
example:

Repository URL =
https://username:[email protected]/project/projectname.git

5. Select additional behaviors for your repository:

Clean Before Checkout


Checkout to a sub-directory. Local subdirectory for repo
/home/user/Code/ProjectFolder

6. Select a branch you want to build:

*/master

7. In the Build tab, select Execute Shell in Add build step.

8. In the Execute shell, add the following command:

cd /home/user/Code/ProjectFolder && gradle clean assemble --no-daemon

9. If you want to run Lint on the project, then add another build step into the Execute shell:

/home/user/gradle/gradle-2.14.1/bin/gradle lint

Now your system is finally set up to build Android projects using Jenkins. This setup makes your
life so much easier for releasing builds to QA and UAT teams.

PS: Since Jenkins is a different user on your Ubuntu machine, you should give it rights to create
folders in your workspace by executing the following command:

chown -R jenkins .git

Read Jenkins CI setup for Android Projects online:


https://riptutorial.com/android/topic/7830/jenkins-ci-setup-for-android-projects

https://riptutorial.com/ 796
Chapter 149: Job Scheduling
Remarks
Beware of running lots of code or doing heavy work inside your JobService, for example in
onStartJob(). The code will run on the main/UI thread and therefore can lead to a blocked UI, no
longer responding app or even a crash of your app!

Because of that, you must offload the work, for example by using a Thread or AsyncTask.

Examples
Basic usage

Create a new JobService


This is done by extending the JobService class and implementing/overriding the required methods
onStartJob() and onStopJob().

public class MyJobService extends JobService


{
final String TAG = getClass().getSimpleName();

@Override
public boolean onStartJob(JobParameters jobParameters) {
Log.i(TAG, "Job started");

// ... your code here ...

jobFinished(jobParameters, false); // signal that we're done and don't want to


reschedule the job
return false; // finished: no more work to be done
}

@Override
public boolean onStopJob(JobParameters jobParameters) {
Log.w(TAG, "Job stopped");
return false;
}
}

Add the new JobService to your


AndroidManifest.xml
The following step is mandatory, otherwise you won't be able to run your job:

https://riptutorial.com/ 797
Declare your MyJobService class as a new <service> element between <application> </application>
in your AndroidManifest.xml.

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example">
<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="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service
android:name=".MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
</application>
</manifest>

Setup and run the job


After you implemented a new JobService and added it to your AndroidManifest.xml, you can
continue with the final steps.

• onButtonClick_startJob()prepares and runs a periodical job. Besides periodic jobs,


JobInfo.Builder allows to specify many other settings and constraints. For example you can
define that a plugged in charger or a network connection is required to run the job.
• onButtonClick_stopJob() cancels all running jobs

public class MainActivity extends AppCompatActivity


{
final String TAG = getClass().getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void onButtonClick_startJob(View v) {


// get the jobScheduler instance from current context
JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);

// MyJobService provides the implementation for the job


ComponentName jobService = new ComponentName(getApplicationContext(),
MyJobService.class);

// define that the job will run periodically in intervals of 10 seconds


JobInfo jobInfo = new JobInfo.Builder(1, jobService).setPeriodic(10 * 1000).build();

https://riptutorial.com/ 798
// schedule/start the job
int result = jobScheduler.schedule(jobInfo);
if (result == JobScheduler.RESULT_SUCCESS)
Log.d(TAG, "Successfully scheduled job: " + result);
else
Log.e(TAG, "RESULT_FAILURE: " + result);
}

public void onButtonClick_stopJob(View v) {


JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
Log.d(TAG, "Stopping all jobs...");
jobScheduler.cancelAll(); // cancel all potentially running jobs
}
}

After calling onButtonClick_startJob(), the job will approximately run in intervals of 10 seconds,
even when the app is in the paused state (user pressed home button and app is no longer visible).

Instead of cancelling all running jobs inside onButtonClick_stopJob(), you can also call
jobScheduler.cancel() to cancel a specific job based on it's job ID.

Read Job Scheduling online: https://riptutorial.com/android/topic/6907/job-scheduling

https://riptutorial.com/ 799
Chapter 150: JSON in Android with org.json
Syntax
• Object : An object is an unordered set of name/value pairs. An object begins with { (left
brace) and ends with } (right brace). Each name is followed by : (colon) and the name/value
pairs are separated by , (comma).

• Array : An array is an ordered collection of values. An array begins with [ (left bracket) and
ends with ] (right bracket). Values are separated by , (comma).

• Value : A value can be a string in double quotes, or a number, or true or false or null, or an
object or an array. These structures can be nested.

• String : A string is a sequence of zero or more Unicode characters, wrapped in double


quotes, using backslash escapes. A character is represented as a single character string. A
string is very much like a C or Java string.

• Number : A number is very much like a C or Java number, except that the octal and
hexadecimal formats are not used.

Remarks
This topic is about using the org.json package that is included in the Android SDK.

Examples
Parse simple JSON object

Consider the following JSON string:

{
"title": "test",
"content": "Hello World!!!",
"year": 2016,
"names" : [
"Hannah",
"David",
"Steve"
]
}

This JSON object can be parsed using the following code:

try {
// create a new instance from a string
JSONObject jsonObject = new JSONObject(jsonAsString);
String title = jsonObject.getString("title");

https://riptutorial.com/ 800
String content = jsonObject.getString("content");
int year = jsonObject.getInt("year");
JSONArray names = jsonObject.getJSONArray("names"); //for an array of String objects
} catch (JSONException e) {
Log.w(TAG,"Could not parse JSON. Error: " + e.getMessage());
}

Here is another example with a JSONArray nested inside JSONObject:

{
"books":[
{
"title":"Android JSON Parsing",
"times_sold":186
}
]
}

This can be parsed with the following code:

JSONObject root = new JSONObject(booksJson);


JSONArray booksArray = root.getJSONArray("books");
JSONObject firstBook = booksArray.getJSONObject(0);
String title = firstBook.getString("title");
int timesSold = firstBook.getInt("times_sold");

Creating a simple JSON object

Create the JSONObject using the empty constructor and add fields using the put() method, which is
overloaded so that it can be used with different types:

try {
// Create a new instance of a JSONObject
final JSONObject object = new JSONObject();

// With put you can add a name/value pair to the JSONObject


object.put("name", "test");
object.put("content", "Hello World!!!1");
object.put("year", 2016);
object.put("value", 3.23);
object.put("member", true);
object.put("null_value", JSONObject.NULL);

// Calling toString() on the JSONObject returns the JSON in string format.


final String json = object.toString();

} catch (JSONException e) {
Log.e(TAG, "Failed to create JSONObject", e);
}

The resulting JSON string looks like this:

{
"name":"test",
"content":"Hello World!!!1",

https://riptutorial.com/ 801
"year":2016,
"value":3.23,
"member":true,
"null_value":null
}

Add JSONArray to JSONObject

// Create a new instance of a JSONArray


JSONArray array = new JSONArray();

// With put() you can add a value to the array.


array.put("ASDF");
array.put("QWERTY");

// Create a new instance of a JSONObject


JSONObject obj = new JSONObject();

try {
// Add the JSONArray to the JSONObject
obj.put("the_array", array);
} catch (JSONException e) {
e.printStackTrace();
}

String json = obj.toString();

The resulting JSON string looks like this:

{
"the_array":[
"ASDF",
"QWERTY"
]
}

Create a JSON String with null value.

If you need to produce a JSON string with a value of null like this:

{
"name":null
}

Then you have to use the special constant JSONObject.NULL.

Functioning example:

jsonObject.put("name", JSONObject.NULL);

Working with null-string when parsing json

https://riptutorial.com/ 802
{
"some_string": null,
"ather_string": "something"
}

If we will use this way:

JSONObject json = new JSONObject(jsonStr);


String someString = json.optString("some_string");

We will have output:

someString = "null";

So we need to provide this workaround:

/**
* According to http://stackoverflow.com/questions/18226288/json-jsonobject-optstring-returns-
string-null
* we need to provide a workaround to opt string from json that can be null.
* <strong></strong>
*/
public static String optNullableString(JSONObject jsonObject, String key) {
return optNullableString(jsonObject, key, "");
}

/**
* According to http://stackoverflow.com/questions/18226288/json-jsonobject-optstring-returns-
string-null
* we need to provide a workaround to opt string from json that can be null.
* <strong></strong>
*/
public static String optNullableString(JSONObject jsonObject, String key, String fallback) {
if (jsonObject.isNull(key)) {
return fallback;
} else {
return jsonObject.optString(key, fallback);
}
}

And then call:

JSONObject json = new JSONObject(jsonStr);


String someString = optNullableString(json, "some_string");
String someString2 = optNullableString(json, "some_string", "");

And we will have Output as we expected:

someString = null; //not "null"


someString2 = "";

Using JsonReader to read JSON from a stream


JsonReader

https://riptutorial.com/ 803
reads a JSON encoded value as a stream of tokens.

public List<Message> readJsonStream(InputStream in) throws IOException {


JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
try {
return readMessagesArray(reader);
} finally {
reader.close();
}
}

public List<Message> readMessagesArray(JsonReader reader) throws IOException {


List<Message> messages = new ArrayList<Message>();

reader.beginArray();
while (reader.hasNext()) {
messages.add(readMessage(reader));
}
reader.endArray();
return messages;
}

public Message readMessage(JsonReader reader) throws IOException {


long id = -1;
String text = null;
User user = null;
List<Double> geo = null;

reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
if (name.equals("id")) {
id = reader.nextLong();
} else if (name.equals("text")) {
text = reader.nextString();
} else if (name.equals("geo") && reader.peek() != JsonToken.NULL) {
geo = readDoublesArray(reader);
} else if (name.equals("user")) {
user = readUser(reader);
} else {
reader.skipValue();
}
}
reader.endObject();
return new Message(id, text, user, geo);
}

public List<Double> readDoublesArray(JsonReader reader) throws IOException {


List<Double> doubles = new ArrayList<Double>();

reader.beginArray();
while (reader.hasNext()) {
doubles.add(reader.nextDouble());
}
reader.endArray();
return doubles;
}

public User readUser(JsonReader reader) throws IOException {


String username = null;
int followersCount = -1;

https://riptutorial.com/ 804
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
if (name.equals("name")) {
username = reader.nextString();
} else if (name.equals("followers_count")) {
followersCount = reader.nextInt();
} else {
reader.skipValue();
}
}
reader.endObject();
return new User(username, followersCount);
}

Create nested JSON object

To produce nested JSON object, you need to simply add one JSON object to another:

JSONObject mainObject = new JSONObject(); // Host object


JSONObject requestObject = new JSONObject(); // Included object

try {
requestObject.put("lastname", lastname);
requestObject.put("phone", phone);
requestObject.put("latitude", lat);
requestObject.put("longitude", lon);
requestObject.put("theme", theme);
requestObject.put("text", message);

mainObject.put("claim", requestObject);
} catch (JSONException e) {
return "JSON Error";
}

Now mainObject contains a key called claim with the whole requestObject as a value.

Handling dynamic key for JSON response

This is an example for how to handle dynamic key for response. Here A and B are dynamic keys it
can be anything

Response

{
"response": [
{
"A": [
{
"name": "Tango"
},
{
"name": "Ping"
}
],

https://riptutorial.com/ 805
"B": [
{
"name": "Jon"
},
{
"name": "Mark"
}
]
}
]
}

Java code

// ResponseData is raw string of response


JSONObject responseDataObj = new JSONObject(responseData);
JSONArray responseArray = responseDataObj.getJSONArray("response");
for (int i = 0; i < responseArray.length(); i++) {
// Nodes ArrayList<ArrayList<String>> declared globally
nodes = new ArrayList<ArrayList<String>>();
JSONObject obj = responseArray.getJSONObject(i);
Iterator keys = obj.keys();
while(keys.hasNext()) {
// Loop to get the dynamic key
String currentDynamicKey = (String)keys.next();
// Get the value of the dynamic key
JSONArray currentDynamicValue = obj.getJSONArray(currentDynamicKey);
int jsonArraySize = currentDynamicValue.length();
if(jsonArraySize > 0) {
for (int ii = 0; ii < jsonArraySize; ii++) {
// NameList ArrayList<String> declared globally
nameList = new ArrayList<String>();
if(ii == 0) {
JSONObject nameObj = currentDynamicValue.getJSONObject(ii);
String name = nameObj.getString("name");
System.out.print("Name = " + name);
// Store name in an array list
nameList.add(name);
}
}
}
nodes.add(nameList);
}
}

Check for the existence of fields on JSON

Sometimes it's useful to check if a field is present or absent on your JSON to avoid some
JSONException on your code.

To achieve that, use the JSONObject#has(String) or the method, like on the following example:

Sample JSON

{
"name":"James"
}

https://riptutorial.com/ 806
Java code

String jsonStr = " { \"name\":\"James\" }";


JSONObject json = new JSONObject(jsonStr);
// Check if the field "name" is present
String name, surname;

// This will be true, since the field "name" is present on our JSON.
if (json.has("name")) {
name = json.getString("name");
}
else {
name = "John";
}
// This will be false, since our JSON doesn't have the field "surname".
if (json.has("surname")) {
surname = json.getString("surname");
}
else {
surname = "Doe";
}

// Here name == "James" and surname == "Doe".

Updating the elements in the JSON

sample json to update

{
"student":{"name":"Rahul", "lastname":"sharma"},
"marks":{"maths":"88"}
}

To update the elements value in the json we need to assign the value and update.

try {
// Create a new instance of a JSONObject
final JSONObject object = new JSONObject(jsonString);

JSONObject studentJSON = object.getJSONObject("student");


studentJSON.put("name","Kumar");

object.remove("student");

object.put("student",studentJSON);

// Calling toString() on the JSONObject returns the JSON in string format.


final String json = object.toString();

} catch (JSONException e) {
Log.e(TAG, "Failed to create JSONObject", e);
}

updated value

https://riptutorial.com/ 807
"student":{"name":"Kumar", "lastname":"sharma"},
"marks":{"maths":"88"}
}

Read JSON in Android with org.json online: https://riptutorial.com/android/topic/106/json-in-


android-with-org-json

https://riptutorial.com/ 808
Chapter 151: Keyboard
Examples
Hide keyboard when user taps anywhere else on the screen

Add code in your Activity.

This would work for Fragment also, no need to add this code in Fragment.

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
View view = getCurrentFocus();
if (view != null && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() ==
MotionEvent.ACTION_MOVE) && view instanceof EditText &&
!view.getClass().getName().startsWith("android.webkit.")) {
int scrcoords[] = new int[2];
view.getLocationOnScreen(scrcoords);
float x = ev.getRawX() + view.getLeft() - scrcoords[0];
float y = ev.getRawY() + view.getTop() - scrcoords[1];
if (x < view.getLeft() || x > view.getRight() || y < view.getTop() || y >
view.getBottom())

((InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((this
0);
}
return super.dispatchTouchEvent(ev);
}

Register a callback for keyboard open and close

The idea is to measure a layout before and after each change and if there is a significant change
you can be somewhat certain that its the softkeyboard.

// A variable to hold the last content layout hight


private int mLastContentHeight = 0;

private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new


ViewTreeObserver.OnGlobalLayoutListener() {
@Override public void onGlobalLayout() {
int currentContentHeight = findViewById(Window.ID_ANDROID_CONTENT).getHeight();

if (mLastContentHeight > currentContentHeight + 100) {


Timber.d("onGlobalLayout: Keyboard is open");
mLastContentHeight = currentContentHeight;
} else if (currentContentHeight > mLastContentHeight + 100) {
Timber.d("onGlobalLayout: Keyboard is closed");
mLastContentHeight = currentContentHeight;
}
}
};

then in our onCreate set the initial value for mLastContentHeight

https://riptutorial.com/ 809
mLastContentHeight = findViewById(Window.ID_ANDROID_CONTENT).getHeight();

and add the listener

rootView.getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener);

don't forget to remove the listener on destroy

rootView.getViewTreeObserver().removeOnGlobalLayoutListener(keyboardLayoutListener);

Read Keyboard online: https://riptutorial.com/android/topic/5606/keyboard

https://riptutorial.com/ 810
Chapter 152: Layouts
Introduction
A layout defines the visual structure for a user interface, such as an activity or widget.

A layout is declared in XML, including screen elements that will appear in it. Code can be added to
the application to modify the state of screen objects at runtime, including those declared in XML.

Syntax
• android:gravity="top|bottom|left|right|center_vertical|fill_vertical|center_horizontal|fill_horizontal|cente
• android:layout_gravity="top|bottom|left|right|center_vertical|fill_vertical|center_horizontal|fill_horizont

Remarks

LayoutParams and Layout_ Attributes

https://riptutorial.com/ 811
https://riptutorial.com/ 812
requires two layout passes to render properly. For complex view hierarchies, this can have a
significant impact on performance. Nesting RelativeLayouts makes this problem even worse,
because every RelativeLayout causes the number of layout passes to go up.

Examples
LinearLayout

The LinearLayout is a ViewGroup that arranges its children in a single column or a single row. The
orientation can be set by calling the method setOrientation() or using the xml attribute
android:orientation.

1. Vertical orientation : android:orientation="vertical"

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_name" />

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@android:string/cancel" />

</LinearLayout>

Here is a screenshot how this will look like:

https://riptutorial.com/ 813
2. Horizontal orientation : android:orientation="horizontal"

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_name" />

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@android:string/cancel" />

The LinearLayout also supports assigning a weight to individual children with the
android:layout_weight attribute.

RelativeLayout

RelativeLayout is a ViewGroup that displays child views in relative positions. By default, all child

https://riptutorial.com/ 814
views are drawn at the top-left of the layout, so you must define the position of each view using the
various layout properties available from RelativeLayout.LayoutParams. The value for each layout
property is either a boolean to enable a layout position relative to the parent RelativeLayout or an
ID that references another view in the layout against which the view should be positioned.

Example:

<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView"
android:src="@mipmap/ic_launcher" />

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:layout_toRightOf="@+id/imageView"
android:layout_toEndOf="@+id/imageView"
android:hint="@string/hint" />

</RelativeLayout>

Here is a screenshot how this will look like:

https://riptutorial.com/ 815
Gravity and layout gravity

android:layout_gravity

• android:layout_gravity is used to set the position of an element in its parent (e.g. a child View
inside a Layout).
• Supported by LinearLayout and FrameLayout

android:gravity

• android:gravity is used to set the position of content inside an element (e.g. a text inside a
TextView).

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"

https://riptutorial.com/ 816
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"
android:orientation="vertical">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:layout_gravity="left"
android:gravity="center_vertical">

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/first"
android:background="@color/colorPrimary"
android:gravity="left"/>

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/second"
android:background="@color/colorPrimary"
android:gravity="center"/>

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/third"
android:background="@color/colorPrimary"
android:gravity="right"/>

</LinearLayout>

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:layout_gravity="center"
android:gravity="center_vertical">

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/first"
android:background="@color/colorAccent"
android:gravity="left"/>

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/second"
android:background="@color/colorAccent"
android:gravity="center"/>

<TextView

https://riptutorial.com/ 817
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/third"
android:background="@color/colorAccent"
android:gravity="right"/>

</LinearLayout>

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:layout_gravity="right"
android:gravity="center_vertical">

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/first"
android:background="@color/colorPrimaryDark"
android:gravity="left"/>

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/second"
android:background="@color/colorPrimaryDark"
android:gravity="center"/>

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/third"
android:background="@color/colorPrimaryDark"
android:gravity="right"/>

</LinearLayout>

</LinearLayout>

Which gets rendered as following:

https://riptutorial.com/ 818
GridLayout

GridLayout, as the name suggests is a layout used to arrange Views in a grid. A GridLayout
divides itself into columns and rows. As you can see in the example below, the amount of columns
and/or rows is specified by the properties columnCount and rowCount. Adding Views to this layout will
add the first view to the first column, the second view to the second column, and the third view to
the first column of the second row.

<?xml version="1.0" encoding="utf-8"?>


<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
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"

https://riptutorial.com/ 819
android:columnCount="2"
android:rowCount="2">

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/first"
android:background="@color/colorPrimary"
android:layout_margin="@dimen/default_margin" />

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/second"
android:background="@color/colorPrimary"
android:layout_margin="@dimen/default_margin" />

<TextView
android:layout_width="@dimen/fixed"
android:layout_height="wrap_content"
android:text="@string/third"
android:background="@color/colorPrimary"
android:layout_margin="@dimen/default_margin" />

</GridLayout>

https://riptutorial.com/ 820
Percent Layouts

2.3

The Percent Support Library provides PercentFrameLayout and PercentRelativeLayout, two


ViewGroups that provide an easy way to specify View dimensions and margins in terms of a
percentage of the overall size.

You can use the Percent Support Library by adding the following to your dependencies.

compile 'com.android.support:percent:25.3.1'

If you wanted to display a view that fills the screen horizontally but only half the screen vertically
you would do thie following.

<android.support.percent.PercentFrameLayout

https://riptutorial.com/ 821
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<FrameLayout
app:layout_widthPercent="100%"
app:layout_heightPercent="50%"
android:background="@android:color/black" />

<android.support.percent.PercentFrameLayout>

You can also define the percentages in a separate XML file with code such as:

<fraction name="margin_start_percent">25%</fraction>

And refer to them in your layouts with @fraction/margin_start_percent.

They also contain the ability to set a custom aspect ratio via app:layout_aspectRatio.
This allows you to set only a single dimension, such as only the width, and the height will be
automatically determined based on the aspect ratio you’ve defined, whether it is 4:3 or 16:9 or
even a square 1:1 aspect ratio.

For example:

<ImageView
app:layout_widthPercent="100%"
app:layout_aspectRatio="178%"
android:scaleType="centerCrop"
android:src="@drawable/header_background"/>

FrameLayout

FrameLayoutis designed to block out an area on the screen to display a single item. You can,
however, add multiple children to a FrameLayout and control their position within the FrameLayout
by assigning gravity to each child, using the android:layout_gravity attribute.

Generally, FrameLayout is used to hold a single child view. Common use cases are creating place
holders for inflating Fragments in Activity, overlapping views or applying foreground to the views.

Example:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:src="@drawable/nougat"
android:scaleType="fitCenter"
android:layout_height="match_parent"
android:layout_width="match_parent"/>

<TextView

https://riptutorial.com/ 822
android:text="FrameLayout Example"
android:textSize="30sp"
android:textStyle="bold"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:gravity="center"/>

</FrameLayout>

It will look like this:

CoordinatorLayout

2.3

The CoordinatorLayout is a container somewhat similar to FrameLayout but with extra capabilities, it
is called super-powered FrameLayout in the official documentation.

By attaching a CoordinatorLayout.Behavior to a direct child of CoordinatorLayout, you’ll be able to


intercept touch events, window insets, measurement, layout, and nested scrolling.

https://riptutorial.com/ 823
In order to use it, you will first have to add a dependency for the support library in your gradle file:

compile 'com.android.support:design:25.3.1'

The number of the latest version of the library may be found here

One practical use case of the CoordinatorLayout is creating a view with a FloatingActionButton. In
this specific case, we will create a RecyclerView with a SwipeRefreshLayout and a
FloatingActionButton on top of that. Here's how you can do that:

<?xml version="1.0" encoding="utf-8"?>


<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coord_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">

<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/recycler_view"/>

</android.support.v4.widget.SwipeRefreshLayout>

<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:clickable="true"
android:color="@color/colorAccent"
android:src="@mipmap/ic_add_white"
android:layout_gravity="end|bottom"
app:layout_anchorGravity="bottom|right|end"/>

</android.support.design.widget.CoordinatorLayout>

Notice how the FloatingActionButton is anchored to the CoordinatorLayout with


app:layout_anchor="@id/coord_layout"

CoordinatorLayout Scrolling Behavior

2.3-2.3.2

An enclosing CoordinatorLayout can be used to achieve Material Design Scrolling Effects when
using inner layouts that support Nested Scrolling, such as NestedScrollView or RecyclerView.

For this example:

https://riptutorial.com/ 824
• is used in the Toolbar properties
app:layout_scrollFlags="scroll|enterAlways"
• app:layout_behavior="@string/appbar_scrolling_view_behavior" is used in the ViewPager
properties
• A RecyclerView is used in the ViewPager Fragments

Here is the layout xml file used in an Activity:

<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<android.support.design.widget.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="6dp">
<android.support.v7.widget.Toolbar
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/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:elevation="0dp"
app:layout_scrollFlags="scroll|enterAlways"
/>

<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
app:tabMode="fixed"
android:layout_below="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:elevation="0dp"
app:tabTextColor="#d3d3d3"
android:minHeight="?attr/actionBarSize"
/>

</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager
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"
/>

</android.support.design.widget.CoordinatorLayout>

https://riptutorial.com/ 825
Result:

View Weight

One of the most used attribute for LinearLayout is the weight of its child views. Weight defines how
much space a view will consume compared to other views within a LinearLayout.

Weight is used when you want to give specific screen space to one component compared to other.

Key Properties:

• weightSumis the overall sum of weights of all child views. If you don't specify the weightSum,
the system will calculate the sum of all the weights on its own.

• layout_weight specifies the amount of space out of the total weight sum the widget will
occupy.

Code:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"

https://riptutorial.com/ 826
android:orientation="horizontal"
android:weightSum="4">

<EditText
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Type Your Text Here" />

<Button
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Text1" />

<Button
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Text1" />

</LinearLayout>

The output is:

https://riptutorial.com/ 827
Now even if the size of the device is larger, the EditText will take 2/4 of the screen's space. Hence
the look of your app is seen consistent across all screens.

Note: Here the layout_width is kept 0dp as the widget space is divided horizontally. If the widgets
are to be aligned vertically layout_height will be set to 0dp. This is done to increase the efficiency of
the code because at runtime the system won't attempt to calculate the width or height respectively
as this is managed by the weight. If you instead used wrap_content the system would attempt to
calculate the width/height first before applying the weight attribute which causes another
calculation cycle.

Creating LinearLayout programmatically

Hierarchy

- LinearLayout(horizontal)
- ImageView

https://riptutorial.com/ 828
- LinearLayout(vertical)
- TextView
- TextView

Code

LinearLayout rootView = new LinearLayout(context);


rootView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
rootView.setOrientation(LinearLayout.HORIZONTAL);

// for imageview
ImageView imageView = new ImageView(context);
// for horizontal linearlayout
LinearLayout linearLayout2 = new LinearLayout(context);
linearLayout2.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
linearLayout2.setOrientation(LinearLayout.VERTICAL);

TextView tv1 = new TextView(context);


TextView tv2 = new TextView(context);
// add 2 textview to horizontal linearlayout
linearLayout2.addView(tv1);
linearLayout2.addView(tv2);

// finally, add imageview and horizontal linearlayout to vertical linearlayout (rootView)


rootView.addView(imageView);
rootView.addView(linearLayout2);

LayoutParams

Every single ViewGroup (e.g. LinearLayout, RelativeLayout, CoordinatorLayout, etc.) needs to store
information about its children's properties. About the way its children are being laid out in the
ViewGroup. This information is stored in objects of a wrapper class ViewGroup.LayoutParams.

To include parameters specific to a particular layout type, ViewGroups use subclasses of


ViewGroup.LayoutParams class.

E.g. for

• LinearLayout it's LinearLayout.LayoutParams


• RelativeLayout it's RelativeLayout.LayoutParams
• CoordinatorLayout it's CoordinatorLayout.LayoutParams
• ...

Most of ViewGroups reutilize the ability to set margins for their children, so they do not subclass
ViewGroup.LayoutParams directly, but they subclass ViewGroup.MarginLayoutParams instead (which itself
is a subclass of ViewGroup.LayoutParams).

LayoutParams in xml

LayoutParams objects are created based on the inflated layout xml file.

https://riptutorial.com/ 829
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="right"
android:gravity="bottom"
android:text="Example text"
android:textColor="@android:color/holo_green_dark"/>

<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/holo_green_dark"
android:scaleType="centerInside"
android:src="@drawable/example"/>

</LinearLayout>

All parameters that begin with layout_ specify how the enclosing layout should work. When the
layout is inflated, those parameters are wrapped in a proper LayoutParams object, that later will be
used by the Layout to properly position a particular View within the ViewGroup. Other attributes of a
View are directly View-related and are processed by the View itself.

For TextView:

• layout_width, layout_height and layout_gravity will be stored in a LinearLayout.LayoutParams


object and used by the LinearLayout
• gravity, text and textColor will be used by the TextView itself

For ImageView:

• layout_width, layout_height and layout_weight will be stored in a LinearLayout.LayoutParams


object and used by the LinearLayout
• background, scaleType and src will be used by the ImageView itself

Getting LayoutParams object

getLayoutParams is a View's method that allows to retrieve a current LayoutParams object.

Because the LayoutParams object is directly related to the enclosing ViewGroup, this method will
return a non-null value only when View is attached to the ViewGroup. You need to bare in mind that
this object might not be present at all times. Especially you should not depend on having it inside
View's constructor.

public class ExampleView extends View {

public ExampleView(Context context) {


super(context);

https://riptutorial.com/ 830
setupView(context);
}

public ExampleView(Context context, AttributeSet attrs) {


super(context, attrs);
setupView(context);
}

public ExampleView(Context context, AttributeSet attrs, int defStyle) {


super(context, attrs, defStyle);
setupView(context);
}

private void setupView(Context context) {


if (getLayoutParams().height == 50){ // DO NOT DO THIS!
// This might produce NullPointerException
doSomething();
}
}

//...
}

If you want to depend on having LayoutParams object, you should use onAttachedToWindow method
instead.

public class ExampleView extends View {

public ExampleView(Context context) {


super(context);
}

public ExampleView(Context context, AttributeSet attrs) {


super(context, attrs);
}

public ExampleView(Context context, AttributeSet attrs, int defStyle) {


super(context, attrs, defStyle);
}

@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (getLayoutParams().height == 50) { // getLayoutParams() will NOT return null here
doSomething();
}
}

//...
}

Casting LayoutParams object

You might need to use features that are specific to a particular ViewGroup (e.g. you might want to
programmatically change rules of a RelativeLayout). For that purpose you will need to know how to
properly cast the ViewGroup.LayoutParams object.

https://riptutorial.com/ 831
This might be a bit confusing when getting a LayoutParams object for a child View that actually is
another ViewGroup.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/outer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<FrameLayout
android:id="@+id/inner_layout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="right"/>

</LinearLayout>

IMPORTANT: The type of LayoutParams object is directly related to the type of the ENCLOSING
ViewGroup.

Incorrect casting:

FrameLayout innerLayout = (FrameLayout)findViewById(R.id.inner_layout);


FrameLayout.LayoutParams par = (FrameLayout.LayoutParams) innerLayout.getLayoutParams();
// INCORRECT! This will produce ClassCastException

Correct casting:

FrameLayout innerLayout = (FrameLayout)findViewById(R.id.inner_layout);


LinearLayout.LayoutParams par = (LinearLayout.LayoutParams) innerLayout.getLayoutParams();
// CORRECT! the enclosing layout is a LinearLayout

Read Layouts online: https://riptutorial.com/android/topic/94/layouts

https://riptutorial.com/ 832
Chapter 153: Leakcanary
Introduction
Leak Canary is an Android and Java library used to detect leak in the application

Remarks
You can see the example in link below

https://github.com/square/leakcanary

Examples
Implementing a Leak Canary in Android Application

In your build.gradle you need to add the below dependencies:

debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'

In your Application class you need to add the below code inside your onCreate():

LeakCanary.install(this);

That's all you need to do for LeakCanary, it will automatically show notifications when there is a
leak in your build.

Read Leakcanary online: https://riptutorial.com/android/topic/10041/leakcanary

https://riptutorial.com/ 833
Chapter 154: Library Dagger 2: Dependency
Injection in Applications
Introduction
Dagger 2, as explained on GitHub, is a compile-time evolution approach to dependency injection.
Taking the approach started in Dagger 1.x to its ultimate conclusion, Dagger 2.x eliminates all
reflection, and improves code clarity by removing the traditional ObjectGraph/Injector in favor of
user-specified @Component interfaces.

Remarks
1. Library setup in application(for maven, gradle,java projects)
2. Advantages of Dragger use
3. Important Links (for Documentation and demos)
4. How to integrate and use Dragger components

Dagger 2 API:
Dagger 2 exposes a number of special annotations:

@Module for the classes whose methods provide dependencies

@Provides for the methods within @Module classes

@Inject to request a dependency (a constructor, a field, or a method)

@Component is a bridge interface between modules and injection

Important Links:
GitHub: https://github.com/google/dagger

UserGuide(Google): https://google.github.io/dagger/users-guide.html

Videos: https://google.github.io/dagger/resources.html

Vogella Tutorial: http://www.vogella.com/tutorials/Dagger/article.html

Codepath Tutorial: https://github.com/codepath/android_guides/wiki/Dependency-Injection-with-


Dagger-2

https://riptutorial.com/ 834
Examples
Create @Module Class and @Singleton annotation for Object

import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;

@Module
public class VehicleModule {

@Provides @Singleton
Motor provideMotor(){
return new Motor();
}

@Provides @Singleton
Vehicle provideVehicle(){
return new Vehicle(new Motor());
}
}

Every provider (or method) must have the @Provides annotation and the class must have the
@Module annotation. The @Singleton annotation indicates that there will be only one instance of the
object.

Request Dependencies in Dependent Objects

Now that you have the providers for your different models, you need to request them. Just as
Vehicle needs Motor, you have to add the @Inject annotation in the Vehicle constructor as follows:

@Inject
public Vehicle(Motor motor){
this.motor = motor;
}

You can use the @Inject annotation to request dependencies in the constructor, fields, or methods.
In this example, I'm keeping the injection in the constructor.

Connecting @Modules with @Inject

The connection between the provider of dependencies, @Module, and the classes requesting them
through @Inject is made using @Component, which is an interface:

import javax.inject.Singleton;
import dagger.Component;

@Singleton
@Component(modules = {VehicleModule.class})
public interface VehicleComponent {
Vehicle provideVehicle();
}

https://riptutorial.com/ 835
For the @Component annotation, you have to specify which modules are going to be used. In this
example VehicleModule is used, which is defined in this example. If you need to use more modules,
then just add them using a comma as a separator.

Using @Component Interface to Obtain Objects

Now that you have every connection ready, you have to obtain an instance of this interface and
invoke its methods to obtain the object you need:

VehicleComponent component = Dagger_VehicleComponent.builder().vehicleModule(new


VehicleModule()).build();
vehicle = component.provideVehicle();
Toast.makeText(this, String.valueOf(vehicle.getSpeed()), Toast.LENGTH_SHORT).show();

When you try to create a new object of the interface with the @Component annotation, you have to do
it using the prefix Dagger_<NameOfTheComponentInterface>, in this case Dagger_VehicleComponent, and
then use the builder method to call every module within.

Read Library Dagger 2: Dependency Injection in Applications online:


https://riptutorial.com/android/topic/9079/library-dagger-2--dependency-injection-in-applications

https://riptutorial.com/ 836
Chapter 155: Lint Warnings
Remarks
The Lint tool checks your Android project source files for potential bugs and optimization
improvements for correctness, security, performance, usability, accessibility, and
internationalization. You can run Lint from the command-line or from Android Studio.

Official documentation:
https://developer.android.com/studio/write/lint.html

Examples
Using tools:ignore in xml files

The attribute tools:ignore can be used in xml files to dismiss lint warnings.

BUT dismissing lint warnings with this technique is most of the time the wrong way to
proceed.

A lint warning must be understood and fixed... it can be ignored if and only if you have a full
understanding of it's meaning and a strong reason to ignore it.

Here is a use case where it legitimate to ignore a lint warning:

• You are developing a system-app (signed with the device manufacturer key)
• Your app need to change the device date (or any other protected action)

Then you can do this in your manifest : (i.e. requesting the protected permission and ignoring the
lint warning because you know that in your case the permission will be granted)

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
...>
<uses-permission android:name="android.permission.SET_TIME"
tools:ignore="ProtectedPermissions"/>

Importing resources without "Deprecated" error

Using the Android API 23 or higher, very often such situation can be seen:

https://riptutorial.com/ 837
This situation is caused by the structural change of the Android API regarding getting the
resources. Now the function:

public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException

should be used. But the android.support.v4 library has another solution.

Add the following dependency to the build.gradle file:

com.android.support:support-v4:24.0.0

Then all methods from support library are available:

ContextCompat.getColor(context, R.color.colorPrimaryDark);
ContextCompat.getDrawable(context, R.drawable.btn_check);
ContextCompat.getColorStateList(context, R.color.colorPrimary);
DrawableCompat.setTint(drawable);
ContextCompat.getColor(context,R.color.colorPrimaryDark));

Moreover more methods from support library can be used:

ViewCompat.setElevation(textView, 1F);
ViewCompat.animate(textView);
TextViewCompat.setTextAppearance(textView, R.style.AppThemeTextStyle);
...

Configure LintOptions with gradle

You can configure lint by adding a lintOptions section in the build.gradle file:

android {

//.....

lintOptions {
// turn off checking the given issue id's
disable 'TypographyFractions','TypographyQuotes'

// turn on the given issue id's


enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'

// check *only* the given issue id's


check 'NewApi', 'InlinedApi'

// set to true to turn off analysis progress reporting by lint


quiet true

// if true, stop the gradle build if errors are found


abortOnError false

// if true, only report errors


ignoreWarnings true
}
}

https://riptutorial.com/ 838
You can run lint for a specific variant (see below), e.g. ./gradlew lintRelease, or for all variants (
./gradlew lint), in which case it produces a report which describes which specific variants a given
issue applies to.

Check here for the DSL reference for all available options.

How to configure the lint.xml file

You can specify your Lint checking preferences in the lint.xml file. If you are creating this file
manually, place it in the root directory of your Android project. If you are configuring Lint
preferences in Android Studio, the lint.xml file is automatically created and added to your Android
project for you.

Example:

<?xml version="1.0" encoding="UTF-8"?>


<lint>
<!-- list of issues to configure -->
</lint>

By setting the severity attribute value in the tag, you can disable Lint checking for an issue or
change the severity level for an issue.

The following example shows the contents of a lint.xml file.

<?xml version="1.0" encoding="UTF-8"?>


<lint>
<!-- Disable the given check in this project -->
<issue id="IconMissingDensityFolder" severity="ignore" />

<!-- Ignore the ObsoleteLayoutParam issue in the specified files -->


<issue id="ObsoleteLayoutParam">
<ignore path="res/layout/activation.xml" />
<ignore path="res/layout-xlarge/activation.xml" />
</issue>

<!-- Ignore the UselessLeaf issue in the specified file -->


<issue id="UselessLeaf">
<ignore path="res/layout/main.xml" />
</issue>

<!-- Change the severity of hardcoded strings to "error" -->


<issue id="HardcodedText" severity="error" />
</lint>

Configuring lint checking in Java and XML source files

You can disable Lint checking from your Java and XML source files.

Configuring lint checking in Java

https://riptutorial.com/ 839
To disable Lint checking specifically for a Java class or method in your Android project, add the
@SuppressLint annotation to that Java code.

Example:

@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

To disable checking for all Lint issues:

@SuppressLint("all")

Configuring lint checking in XML


You can use the tools:ignore attribute to disable Lint checking for specific sections of your XML
files.

For example:

tools:ignore="NewApi,StringFormatInvalid"

To suppress checking for all Lint issues in the XML element, use

tools:ignore="all"

Mark Suppress Warnings

It's good practice to mark some warnings in your code. For example, some deprecated methods is
need for your testing, or old support version. But Lint checking will mark that code with warnings.
For avoiding this problem, you need use annotation @SuppressWarnings.

For example, add ignoring to warnings to deprecated methods. You need to put warnings
description in annotation also:

@SuppressWarnings("deprecated");
public void setAnotherColor (int newColor) {
getApplicationContext().getResources().getColor(newColor)
}

Using this annotation you can ignore all warnings, including Lint, Android, and other. Using
Suppress Warnings, helps to understand code correctly!

Read Lint Warnings online: https://riptutorial.com/android/topic/129/lint-warnings

https://riptutorial.com/ 840
Chapter 156: ListView
Introduction
ListView is a viewgroup which groups several items from a data source like array or database and
displays them in a scroll-able list. Data are bound with listview using an Adapter class.

Remarks
ListView is a view group that displays a list of scrollable items.
The list items are automatically inserted to the list using an Adapter that pulls content from a source
such as an array or database query and converts each item result into a view that's placed into the
list.

When the content for your layout is dynamic or not pre-determined, you can use a layout that
subclasses AdapterView to populate the layout with views at runtime. A subclass of the AdapterView
class uses an Adapter to bind data to its layout.

Before using the ListView you should also checking the RecyclerView examples.

Examples
Filtering with CursorAdapter

// Get the reference to your ListView


ListView listResults = (ListView) findViewById(R.id.listResults);

// Set its adapter


listResults.setAdapter(adapter);

// Enable filtering in ListView


listResults.setTextFilterEnabled(true);

// Prepare your adapter for filtering


adapter.setFilterQueryProvider(new FilterQueryProvider() {
@Override
public Cursor runQuery(CharSequence constraint) {

// in real life, do something more secure than concatenation


// but it will depend on your schema
// This is the query that will run on filtering
String query = "SELECT _ID as _id, name FROM MYTABLE "
+ "where name like '%" + constraint + "%' "
+ "ORDER BY NAME ASC";
return db.rawQuery(query, null);
}
});

Let's say your query will run every time the user types in an EditText:

https://riptutorial.com/ 841
EditText queryText = (EditText) findViewById(R.id.textQuery);
queryText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count,
final int after) {

@Override
public void onTextChanged(final CharSequence s, final int start, final int before,
final int count) {
// This is the filter in action
adapter.getFilter().filter(s.toString());
// Don't forget to notify the adapter
adapter.notifyDataSetChanged();
}

@Override
public void afterTextChanged(final Editable s) {

}
});

Custom ArrayAdapter

By default the ArrayAdapter class creates a view for each array item by calling toString() on each
item and placing the contents in a TextView.

To create a complex view for each item (for example, if you want an ImageView for each array
item), extend the ArrayAdapter class and override the getView() method to return the type of View
you want for each item.

For example:

public class MyAdapter extends ArrayAdapter<YourClassData>{

private LayoutInflater inflater;

public MyAdapter (Context context, List<YourClassData> data){


super(context, 0, data);
inflater = LayoutInflater.from(context);
}

@Override
public long getItemId(int position)
{
//It is just an example
YourClassData data = (YourClassData) getItem(position);
return data.ID;
}

@Override
public View getView(int position, View view, ViewGroup parent)
{
ViewHolder viewHolder;
if (view == null) {
view = inflater.inflate(R.layout.custom_row_layout_design, null);

https://riptutorial.com/ 842
// Do some initialization

//Retrieve the view on the item layout and set the value.
viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) view.getTag();
}

//Retrieve your object


YourClassData data = (YourClassData) getItem(position);

viewHolder.txt.setTypeface(m_Font);
viewHolder.txt.setText(data.text);
viewHolder.img.setImageBitmap(BitmapFactory.decodeFile(data.imageAddr));

return view;

private class ViewHolder


{
private final TextView txt;
private final ImageView img;

private ViewHolder(View view)


{
txt = (TextView) view.findViewById(R.id.txt);
img = (ImageView) view.findViewById(R.id.img);
}
}
}

A basic ListView with an ArrayAdapter

By default the ArrayAdapter creates a view for each array item by calling toString() on each item
and placing the contents in a TextView.

Example:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,


android.R.layout.simple_list_item_1, myStringArray);

where android.R.layout.simple_list_item_1 is the layout that contains a TextView for each string in
the array.

Then simply call setAdapter() on your ListView:

ListView listView = (ListView) findViewById(R.id.listview);


listView.setAdapter(adapter);

To use something other than TextViews for the array display, for instance, ImageViews, or to have
some of data besides toString() results fill the views, override getView(int, View, ViewGroup) to
return the type of view you want. Check this example.

https://riptutorial.com/ 843
Read ListView online: https://riptutorial.com/android/topic/4226/listview

https://riptutorial.com/ 844
Chapter 157: Loader
Introduction
Loader is good choice for prevent memory leak if you want to load data in background when
oncreate method is called. For example when we execute Asynctask in oncreate method and we
rotate the screen so the activity will recreate which will execute another AsyncTask again, so
probably two Asyntask running in parallel together rather than like loader which will continue the
background process we executed before.

Parameters

Class Description

An abstract class associated with an Activity or Fragment


LoaderManager
for managing one or more Loader instances.

A callback interface for a client to interact with the


LoaderManager.LoaderCallbacks
LoaderManager.

An abstract class that performs asynchronous loading of


Loader
data.

Abstract loader that provides an AsyncTask to do the


AsyncTaskLoader
work.

A subclass of AsyncTaskLoader that queries the


CursorLoader
ContentResolver and returns a Cursor.

Remarks
Introduced in Android 3.0, loaders make it easy to asynchronously load data in an activity or
fragment. Loaders have these characteristics:

• They are available to every Activity and Fragment.


• They provide asynchronous loading of data.
• They monitor the source of their data and deliver new results when the content changes.
• They automatically reconnect to the last loader's cursor when being recreated after a
configuration change. Thus, they don't need to re-query their data.

When not to use Loaders


You shouldn’t use Loaders if you need the background tasks to complete. Android destroys
Loaders together with the Activities/Fragments they belong to. If you want to do some tasks, that

https://riptutorial.com/ 845
have to run until completion, do not use Loaders. You should use services for this kind of stuff
instead.

Examples
Basic AsyncTaskLoader

AsyncTaskLoader is an abstract Loader that provides an AsyncTask to do the work.

Here some basic implementation:

final class BasicLoader extends AsyncTaskLoader<String> {

public BasicLoader(Context context) {


super(context);
}

@Override
public String loadInBackground() {
// Some work, e.g. load something from internet
return "OK";
}

@Override
public void deliverResult(String data) {
if (isStarted()) {
// Deliver result if loader is currently started
super.deliverResult(data);
}
}

@Override
protected void onStartLoading() {
// Start loading
forceLoad();
}

@Override
protected void onStopLoading() {
cancelLoad();
}

@Override
protected void onReset() {
super.onReset();

// Ensure the loader is stopped


onStopLoading();
}
}

Typically Loader is initialized within the activity's onCreate() method, or within the fragment's
onActivityCreated(). Also usually activity or fragment implements LoaderManager.LoaderCallbacks
interface:

public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks<String> {

https://riptutorial.com/ 846
// Unique id for loader
private static final int LDR_BASIC_ID = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Initialize loader; Some data can be passed as second param instead of Bundle.Empty
getLoaderManager().initLoader(LDR_BASIC_ID, Bundle.EMPTY, this);
}

@Override
public Loader<String> onCreateLoader(int id, Bundle args) {
return new BasicLoader(this);
}

@Override
public void onLoadFinished(Loader<String> loader, String data) {
Toast.makeText(this, data, Toast.LENGTH_LONG).show();
}

@Override
public void onLoaderReset(Loader<String> loader) {
}
}

In this example, when loader completed, toast with result will be shown.

AsyncTaskLoader with cache

It's a good practice to cache loaded result to avoid multiple loading of same data.
To invalidate cache onContentChanged() should be called. If loader has been already started,
forceLoad() will be called, otherwise (if loader in stopped state) loader will be able to understand
content change with takeContentChanged() check.

Remark: onContentChanged() must be called from the process's main thread.

Javadocs says about takeContentChanged():

Take the current flag indicating whether the loader's content had changed while it was
stopped. If it had, true is returned and the flag is cleared.

public abstract class BaseLoader<T> extends AsyncTaskLoader<T> {

// Cached result saved here


private final AtomicReference<T> cache = new AtomicReference<>();

public BaseLoader(@NonNull final Context context) {


super(context);
}

@Override
public final void deliverResult(final T data) {
if (!isReset()) {

https://riptutorial.com/ 847
// Save loaded result
cache.set(data);
if (isStarted()) {
super.deliverResult(data);
}
}
}

@Override
protected final void onStartLoading() {
// Register observers
registerObserver();

final T cached = cache.get();


// Start new loading if content changed in background
// or if we never loaded any data
if (takeContentChanged() || cached == null) {
forceLoad();
} else {
deliverResult(cached);
}
}

@Override
public final void onStopLoading() {
cancelLoad();
}

@Override
protected final void onReset() {
super.onReset();
onStopLoading();
// Clear cache and remove observers
cache.set(null);
unregisterObserver();
}

/* virtual */
protected void registerObserver() {
// Register observers here, call onContentChanged() to invalidate cache
}

/* virtual */
protected void unregisterObserver() {
// Remove observers
}
}

Reloading

To invalidate your old data and restart existing loader you can use restartLoader() method:

private void reload() {


getLoaderManager().reastartLoader(LOADER_ID, Bundle.EMPTY, this);
}

Pass parameters using a Bundle

https://riptutorial.com/ 848
You can pass parameters by Bundle:

Bundle myBundle = new Bundle();


myBundle.putString(MY_KEY, myValue);

Get the value in onCreateLoader:

@Override
public Loader<String> onCreateLoader(int id, final Bundle args) {
final String myParam = args.getString(MY_KEY);
...
}

Read Loader online: https://riptutorial.com/android/topic/4390/loader

https://riptutorial.com/ 849
Chapter 158: Loading Bitmaps Effectively
Introduction
This Topic Mainly Concentrate on Loading the Bitmaps Effectively in Android Devices.

When it comes to loading a bitmap, the question comes where it is loaded from. Here we are
going to discuss about how to load the Bitmap from Resource with in the Android Device. i.e. eg
from Gallery.

We will go through this by example which are discussed below.

Syntax
• <uses-permission> -- > Tag Used for the Permission .
• android:name -- > An attribute used to give name for the permission we are going to request.
• android.permission.READ_EXTERNAL_STORAGE --> It is System permissions
• example "android.permission.CAMERA" or "android.permission.READ_CONTACTS"

Examples
Load the Image from Resource from Android Device. Using Intents.

Using Intents to Load the Image from Gallery.

1. Initially you need to have the permission

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

2. Use the Following Code to have the layout as designed follows.

https://riptutorial.com/ 850
https://riptutorial.com/ 851
https://riptutorial.com/android/topic/10902/loading-bitmaps-effectively

https://riptutorial.com/ 852
Chapter 159: Localization with resources in
Android
Examples
Currency

Currency currency = Currency.getInstance("USD");


NumberFormat format = NumberFormat.getCurrencyInstance();
format.setCurrency(currency);
format.format(10.00);

Adding translation to your Android app

You have to create a different strings.xml file for every new language.

1. Right-click on the res folder


2. Choose New → Values resource file
3. Select a locale from the available qualifiers
4. Click on the Next button (>>)
5. Select a language
6. Name the file strings.xml

strings.xml

<resources>
<string name="app_name">Testing Application</string>
<string name="hello">Hello World</string>
</resources>

strings.xml(hi)

<resources>
<string name="app_name">परीक्षण आवेदन</string>
<string name="hello">नमस्ते दुनिया</string>
</resources>

Setting the language programmatically:

public void setLocale(String locale) // Pass "en","hi", etc.


{
myLocale = new Locale(locale);
// Saving selected locale to session - SharedPreferences.
saveLocale(locale);
// Changing locale.
Locale.setDefault(myLocale);
android.content.res.Configuration config = new android.content.res.Configuration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

https://riptutorial.com/ 853
config.setLocale(myLocale);
} else {
config.locale = myLocale;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
getBaseContext().createConfigurationContext(config);
} else {
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
}
}

The function above will change the text fields which are referenced from strings.xml. For example,
assume that you have the following two text views:

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello"/>

Then, after changing the locale, the language strings having the ids app_name and hello will be
changed accordingly.

Type of resource directories under the "res" folder

When localizing different types of resources are required, each of which has its own home in the
android project structure. Following are the different directories that we can place under the \res
directory. The resource types placed in each of these directories are explained in the table below:

Directory Resource Type

animator/ XML files that define property animations.

XML files that define tween animations. (Property animations can also be saved
anim/ in this directory, but the animator/ directory is preferred for property animations to
distinguish between the two types.)

color/ XML files that define a state list of colors. See Color State List Resource

"Bitmap files (.png, .9.png, .jpg, .gif) or XML files that are compiled into the
drawable/ following drawable resource subtypes: : Bitmap files - Nine-Patches (re-sizable
bitmaps) - State lists - Shapes - Animation drawables - Other drawables - "

Drawable files for different launcher icon densities. For more information on
mipmap/ managing launcher icons with mipmap/ folders, see Managing Projects
Overview.

layout/ XML files that define a user interface layout. See Layout Resource.

https://riptutorial.com/ 854
Directory Resource Type

XML files that define application menus, such as an Options Menu, Context
menu/
Menu, or Sub Menu. See Menu Resource.

Arbitrary files to save in their raw form. To open these resources with a
raw/ raw InputStream, call Resources.openRawResource() with the resource ID,
which is R.raw.filename.

However, if you need access to original file names and file hierarchy, you might
consider saving some resources in the assets/ directory (instead ofres/raw/).
Files in assets/ are not given a resource ID, so you can read them only
using AssetManager.

XML files that contain simple values, such as strings, integers, and colors, as
values/
well as styles and themes

Arbitrary XML files that can be read at runtime by calling Resources.getXML().


xml/ Various XML configuration files must be saved here, such as a searchable
configuration.

Configuration types and qualifier names for each folder under the "res"
directory

Each resource directory under the res folder (listed in the example above) can have different
variations of the contained resources in similarly named directory suffixed with different qualifier-
values for each configuration-type.

Example of variations of `` directory with different qualifier values suffixed which are often seen in
our android projects:

• drawable/
• drawable-en/
• drawable-fr-rCA/
• drawable-en-port/
• drawable-en-notouch-12key/
• drawable-port-ldpi/
• drawable-port-notouch-12key/

Exhaustive list of all different configuration types and their


qualifier values for android resources:

Configuration Qualifier Values

MCC and MNC Examples:

mcc310

https://riptutorial.com/ 855
Configuration Qualifier Values

mcc310-mnc004

mcc208-mnc00

etc.

Language and region Examples:

en

fr

en-rUS

fr-rFR

fr-rCA

Layout Direction ldrtl

ldltr

smallestWidth swdp

Examples:

sw320dp

sw600dp

sw720dp

Available width wdp

w720dp

w1024dp

Available height hdp

h720dp

h1024dp

Screen size small

normal

large

https://riptutorial.com/ 856
Configuration Qualifier Values

xlarge

Screen aspect long

notlong

Round screen round

notround

Screen orientation port

land

UI mode car

desk

television

appliancewatch

Night mode night

notnight

Screen pixel density (dpi) ldpi

mdpi

hdpi

xhdpi

xxhdpi

xxxhdpi

nodpi

tvdpi

anydpi

Touchscreen type notouch

finger

Keyboard availability keysexposed

https://riptutorial.com/ 857
Configuration Qualifier Values

keyshidden

keyssoft

Primary text input method nokeys

qwerty

12key

Navigation key availability navexposed

navhidden

Primary non-touch navigation method nonav

dpad

trackball

wheel

Platform Version (API level) Examples:

v3

v4

v7

Change locale of android application programatically

In above examples you understand how to localize resources of application. Following example
explain how to change the application locale within application, not from device. In order to change
Application locale only, you can use below locale util.

import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager;
import android.view.ContextThemeWrapper;

import java.util.Locale;

/**
* Created by Umesh on 10/10/16.
*/
public class LocaleUtils {

https://riptutorial.com/ 858
private static Locale mLocale;

public static void setLocale(Locale locale){


mLocale = locale;
if(mLocale != null){
Locale.setDefault(mLocale);
}
}

public static void updateConfiguration(ContextThemeWrapper wrapper){


if(mLocale != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
Configuration configuration = new Configuration();
configuration.setLocale(mLocale);
wrapper.applyOverrideConfiguration(configuration);
}
}

public static void updateConfiguration(Application application, Configuration


configuration){
if(mLocale != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1){
Configuration config = new Configuration(configuration);
config.locale = mLocale;
Resources res = application.getBaseContext().getResources();
res.updateConfiguration(configuration, res.getDisplayMetrics());
}
}

public static void updateConfiguration(Context context, String language, String country){


Locale locale = new Locale(language,country);
setLocale(locale);
if(mLocale != null){
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
configuration.locale = mLocale;
res.updateConfiguration(configuration,res.getDisplayMetrics());
}
}

public static String getPrefLangCode(Context context) {


return
PreferenceManager.getDefaultSharedPreferences(context).getString("lang_code","en");
}

public static void setPrefLangCode(Context context, String mPrefLangCode) {

SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences(context).edit();
editor.putString("lang_code",mPrefLangCode);
editor.commit();
}

public static String getPrefCountryCode(Context context) {


return
PreferenceManager.getDefaultSharedPreferences(context).getString("country_code","US");
}

public static void setPrefCountryCode(Context context,String mPrefCountryCode) {

https://riptutorial.com/ 859
SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences(context).edit();
editor.putString("country_code",mPrefCountryCode);
editor.commit();
}
}

Initialize locale that user preferred, from Application class.

public class LocaleApp extends Application{

@Override
public void onCreate() {
super.onCreate();

LocaleUtils.setLocale(new Locale(LocaleUtils.getPrefLangCode(this),
LocaleUtils.getPrefCountryCode(this)));
LocaleUtils.updateConfiguration(this, getResources().getConfiguration());
}
}

You also need to create a base activity and extend this activity to all other activity so that you can
change locale of application only one place as follows :

public abstract class LocalizationActivity extends AppCompatActivity {

public LocalizationActivity() {
LocaleUtils.updateConfiguration(this);
}

// We only override onCreate


@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

Note : Always initialize locale in constructor.

Now you can use LocalizationActivity as follow.

public class MainActivity extends LocalizationActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

}
}

Note: When you change locale of application programmatically, need to restart your
activity to take the effect of locale change In order to work properly for this solution you

https://riptutorial.com/ 860
and use locale from shared preferences on app startup you android:name=".LocaleApp"
in you Manifest.xml.

Sometimes Lint checker prompt to create the release build. To solve such issue follow below
options.

First:

If you want to disable translation for some strings only then add following attribute to default
string.xml

<string name="developer" translatable="false">Developer Name</string>

Second:

Ignore all missing translation from resource file add following attribute It's the ignore attribute of
the tools namespace in your strings file, as follows:

<?xml version="1.0" encoding="utf-8"?>


<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation" >
http://stackoverflow.com/documentation/android/3345/localization-with-resources-in-android#
<!-- your strings here; no need now for the translatable attribute -->

</resources>

Third:

Another way to disable non-translatable string

http://tools.android.com/recent/non-translatablestrings

If you have a lot of resources that should not be translated, you can place them in a file named
donottranslate.xml and lint will consider all of them non-translatable resources.

Fourth:

You can also add locale in resource file

<resources
xmlns:tools="http://schemas.android.com/tools"
tools:locale="en" tools:ignore="MissingTranslation">

You can also disable missing translation check for lint from app/build.gradle

lintOptions {

disable 'MissingTranslation'
}

https://riptutorial.com/ 861
Read Localization with resources in Android online:
https://riptutorial.com/android/topic/3345/localization-with-resources-in-android

https://riptutorial.com/ 862
Chapter 160: Localized Date/Time in Android
Remarks
It is recommended to use methods of the DateUtils class in order to format dates which are locale
aware, i.e. which consider user preferences (e.g. 12h/24h clock time formats). These methods are
most appropriate for dates that are displayed to the user.

For fully customized date representations, it is recommended to use the SimpleDateFormat class,
as it allows to fully control all date elements.

Examples
Custom localized date format with DateUtils.formatDateTime()

DateUtils.formatDateTime() allows you to supply a time, and based on the flags you provide, it
creates a localized datetime string. The flags allow you to specify whether to include specific
elements (like the weekday).

Date date = new Date();


String localizedDate = DateUtils.formatDateTime(context, date.getTime(),
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY);

formatDateTime() automatically takes care about proper date formats.

Standard date/time formatting in Android

Format a date:

Date date = new Date();


DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
String localizedDate = df.format(date)

Format a date and time. Date is in short format, time is in long format:

Date date = new Date();


DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG);
String localizedDate = df.format(date)

Fully customized date/time

Date date = new Date();


df = new SimpleDateFormat("HH:mm", Locale.US);
String localizedDate = df.format(date)

Commonly used patterns:

https://riptutorial.com/ 863
• HH: hour (0-23)
• hh: hour (1-12)
• a: AM/PM marker
• mm: minute (0-59)
• ss: second
• dd: day in month (1-31)
• MM: month
• yyyy: year

Read Localized Date/Time in Android online: https://riptutorial.com/android/topic/6057/localized-


date-time-in-android

https://riptutorial.com/ 864
Chapter 161: Location
Introduction
Android Location APIs are used in a wide variety of apps for different purposes such as finding
user location, notifying when a user has left a general area (Geofencing), and help interpret user
activity (walking, running, driving, etc).

However, Android Location APIs are not the only means of acquiring user location. The following
will give examples of how to use Android's LocationManager and other common location libraries.

Remarks
For building Location aware apps in Android, there are two paths:

• Android's native open source LocationManager


• Google's FusedLocationProviderApi, which is part of Google Play Services

LocationManager
Pros

• More granular control


• Available in all devices
• Part of the Android framework

Cons

• Battery drain is an issue, if not managed properly


• Requires logic to switch location providers, if the device is unable to find a location (ex. poor
GPS inside a building)

Features

• NMEA Listener
• GPS Status Listener
• Listen to provider status changes (ex. GPS is turned off by user)
• List of providers to choose location source from

Providers

GPS

• Permissions Required:
○ ACCESS_FINE_LOCATION
• Accuracy: 10m - 100m

https://riptutorial.com/ 865
• Power Requirements: HIGH
• Availability: Worldwide (with clear view of the sky)
• NOTES:
○Location updates typically come in once every second, but in situations where GPS
has not been used for some time and A-GPS is unavailable, it make take several
minutes for a location to be received.
○In cases where clear view of the sky is obstructed, GPS points will not cluster very well
(location points "jump") and accuracy may be misleading in certain areas due to the "
Urban Canyon" effect.

Network

• Permissions Required:
○ ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION
• Accuracy: 100m - 1000m+
• Power Requirements: LOW - MEDIUM
• Availability: Within range of cell tower or wifi signal
• NOTES:
○ Location updates occur less frequently than GPS
○ Location updates typically do not cluster well (location points "jump") and accuracy can
range depending number of different factors (number of wifi signals, signal strength,
type of cell tower, etc.)

Passive

• Permissions Required:
○ ACCESS_FINE_LOCATION
• Accuracy: 10m - 1000m+
• Power Requirements: NONE
• Availability: Only when another app receives a location from either GPS or Network
• NOTES:
○ Don't rely on this to give you continuous updates. This listens passively to other apps
that make location requests, and passes those locations back.
○ Does not return FusedLocationProviderApi generated points, only the underlying
location points used to generate them.

FusedLocationProviderApi
Pros

• Offers less battery drain "out of the box"


• Handles poor GPS well
• Gets updates more regularly

Cons

https://riptutorial.com/ 866
• Less granular control over GPS
• May not be available on all devices or in certain countries
• Requires third party library dependency

Features

• Well managed use of location providers for optimal batter savings


• Typically generates more accurate points then Network Location Provider
• More frequent updates of library, allowing for more improvement
• No need to specify what type of provider to use

LocationRequest Priority Levels

PRIORITY_HIGH_ACCURACY

• Permissions Required:
○ ACCESS_FINE_LOCATION for more accurate location or ACCESS_COARSE_LOCATION for less
accurate location
• Accuracy: 10m - 100m
• Power Requirements: HIGH
• Availability: Wherever Google Play Services is available.
• NOTES:
○ If ACCESS_FINE_LOCATION is not used, this will not use GPS for generating location
updates, but will still find a fairly accurate point in the right conditions.
○ If ACCESS_FINE_LOCATION is used, it may or may not use GPS to generate location points,
depending on how accurate it can currently track the device given the environmental
conditions.
○ Although this may report more accurate location updates than the other settings, it is
still prone to the "Urban Canyon" effect.

PRIORITY_BALANCED_POWER_ACCURACY

• Permissions Required:
○ ACCESS_FINE_LOCATION for more accurate location or ACCESS_COARSE_LOCATION for less
accurate location
• Accuracy: 100m - 1000m+
• Power Requirements: MEDIUM
• Availability: Wherever Google Play Services is available.
• NOTES:
○ Same notes as PRIORITY_HIGH_ACCURACY
○ Although it is unlikely, this setting may still use GPS to generate a location.

PRIORITY_LOW_POWER

• Permissions Required:
○ ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION
• Accuracy: 100m - 1000m+
• Power Requirements: LOW

https://riptutorial.com/ 867
• Availability: Wherever Google Play Services is available.
• NOTES:
○Probably does not use GPS, but untested thus far.
○Updates are typically not very accurate
○Used generally to detect significant changes in location

PRIORITY_NO_POWER

• Permissions Required:
○ ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION
• Accuracy: 10m - 1000m+
• Power Requirements: NONE
• Availability: Wherever Google Play Services is available.
• NOTES:
○ Functions almost identically to LocationManager PASSIVE_PROVIDER
○ Reports back Google Play Services updates when received, where PASSIVE_PROVIDER
reports back underlying location updates used

TroubleShooting
OnLocationChanged() Never Called

Since this seems to be a common issue with getting Android Locations, I'll put down a quick
checklist of common fixes:

1. Check your manifest!

One of the most common issues is that the right permissions were never given. If you are
using GPS (with or without Network), use <uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"/>, else use <uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>. Google's FusedLocationApi
requires ACCESS_FINE_LOCATION.

2. (For Android 6+) Check runtime permissions!

Check for and request permissions! If you are never given permissions, you'll end up with
crashes, or worse (if you are catching all exceptions), you'll end up with no indication of
anything! It doesn't matter if the user grants you permission at the start of the app, always
check to see if you have permissions for all calls. The user can easily go to their settings and
revoke them.

3. Double check your code!

Are you sure you are passing in the right listener? Did you add that BroadcastReceiver or
IntentService to your manifest? Are you using PendingIntent.getService() on a

https://riptutorial.com/ 868
BroadcastReceiver class, or getBroadcast() on an IntentService class? Are you sure you are
not unregistering your listener somewhere else in your code immediately after requesting?

4. Check device settings!

Obviously, make sure you have location services turned on.

https://riptutorial.com/ 869
https://riptutorial.com/ 870
If you are using Network services, did you turn on "Scanning Always Available"? Do you
have your location mode set to "Best" ("High Accuracy") or "Battery Saving" ("Network
Only")?

https://riptutorial.com/ 871
https://riptutorial.com/ 872
If you are using GPS, did you turn on "Best" ("High Accuracy") or "Device only" in location
mode?

https://riptutorial.com/ 873
https://riptutorial.com/ 874
Yes, this is on here twice. Did you try using a LocationListener instead of a PendingIntent, or
vice-versa, to ensure you actually implemented LocationManager properly? Are you sure that
the location request isn't being removed in some part of the Activity or Service lifecycle that
you didn't expect to happen?

, or vice-versa, to ensure you actually implemented LocationManager properly? Are you sure
that the location request isn't being removed in some part of the Activity or Service lifecycle
that you didn't expect to happen?

6. Check your surroundings!

Are you testing GPS on the first floor of a building in the middle of San Francisco? Are you
testing Network locations in the middle of nowhere? Do you work in a secret underground
bunker void of all radio signals, wondering why your device isn't getting location? Always
double check your surroundings when trying to troubleshoot location problems!

There could be many other less obvious reasons why location isn't working, but before searching
out those esoteric fixes, just run through this quick checklist.

Examples
Fused location API

Example Using Activity w/ LocationRequest


/*
* This example is useful if you only want to receive updates in this
* activity only, and have no use for location anywhere else.
*/
public class LocationActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
LocationListener {

private GoogleApiClient mGoogleApiClient;


private LocationRequest mLocationRequest;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mGoogleApiClient = new GoogleApiClient.Builder(this)


.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();

mLocationRequest = new LocationRequest()


.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) //GPS quality location
points

https://riptutorial.com/ 875
.setInterval(2000) //At least once every 2 seconds
.setFastestInterval(1000); //At most once a second
}

@Override
protected void onStart(){
super.onStart();
mGoogleApiClient.connect();
}

@Override
protected void onResume(){
super.onResume();
//Permission check for Android 6.0+
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if(mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
}
}
}

@Override
protected void onPause(){
super.onPause();
//Permission check for Android 6.0+
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if(mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,
this);
}
}
}

@Override
protected void onStop(){
super.onStop();
mGoogleApiClient.disconnect();
}

@Override
public void onConnected(@Nullable Bundle bundle) {
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
}
}

@Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}

@Override

https://riptutorial.com/ 876
public void onLocationChanged(Location location) {
//Handle your location update code here
}
}

Example Using Service w/ PendingIntent and


BroadcastReceiver
ExampleActivity

Recommended reading: LocalBroadcastManager

/*
* This example is useful if you have many different classes that should be
* receiving location updates, but want more granular control over which ones
* listen to the updates.
*
* For example, this activity will stop getting updates when it is not visible, but a database
* class with a registered local receiver will continue to receive updates, until
"stopUpdates()" is called here.
*
*/
public class ExampleActivity extends AppCompatActivity {

private InternalLocationReceiver mInternalLocationReceiver;

@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);

//Create internal receiver object in this method only.


mInternalLocationReceiver = new InternalLocationReceiver(this);
}

@Override
protected void onResume(){
super.onResume();

//Register to receive updates in activity only when activity is visible


LocalBroadcastManager.getInstance(this).registerReceiver(mInternalLocationReceiver,
new IntentFilter("googleLocation"));
}

@Override
protected void onPause(){
super.onPause();

//Unregister to stop receiving updates in activity when it is not visible.


//NOTE: You will still receive updates even if this activity is killed.
LocalBroadcastManager.getInstance(this).unregisterReceiver(mInternalLocationReceiver);
}

//Helper method to get updates


private void requestUpdates(){
startService(new Intent(this, LocationService.class).putExtra("request", true));
}

https://riptutorial.com/ 877
//Helper method to stop updates
private void stopUpdates(){
startService(new Intent(this, LocationService.class).putExtra("remove", true));
}

/*
* Internal receiver used to get location updates for this activity.
*
* This receiver and any receiver registered with LocalBroadcastManager does
* not need to be registered in the Manifest.
*
*/
private static class InternalLocationReceiver extends BroadcastReceiver{

private ExampleActivity mActivity;

InternalLocationReceiver(ExampleActivity activity){
mActivity = activity;
}

@Override
public void onReceive(Context context, Intent intent) {
final ExampleActivity activity = mActivity;
if(activity != null) {
LocationResult result = intent.getParcelableExtra("result");
//Handle location update here
}
}
}
}

LocationService

NOTE: Don't forget to register this service in the Manifest!

public class LocationService extends Service implements


GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

private GoogleApiClient mGoogleApiClient;


private LocationRequest mLocationRequest;

@Override
public void onCreate(){
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();

mLocationRequest = new LocationRequest()


.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) //GPS quality location
points
.setInterval(2000) //At least once every 2 seconds
.setFastestInterval(1000); //At most once a second
}

@Override
public int onStartCommand(Intent intent, int flags, int startId){

https://riptutorial.com/ 878
super.onStartCommand(intent, flags, startId);
//Permission check for Android 6.0+
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if (intent.getBooleanExtra("request", false)) {
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, getPendingIntent());
} else {
mGoogleApiClient.connect();
}
}
else if(intent.getBooleanExtra("remove", false)){
stopSelf();
}
}

return START_STICKY;
}

@Override
public void onDestroy(){
super.onDestroy();
if(mGoogleApiClient.isConnected()){
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,
getPendingIntent());
mGoogleApiClient.disconnect();
}
}

private PendingIntent getPendingIntent(){

//Example for IntentService


//return PendingIntent.getService(this, 0, new Intent(this,
**YOUR_INTENT_SERVICE_CLASS_HERE**), PendingIntent.FLAG_UPDATE_CURRENT);

//Example for BroadcastReceiver


return PendingIntent.getBroadcast(this, 0, new Intent(this, LocationReceiver.class),
PendingIntent.FLAG_UPDATE_CURRENT);
}

@Override
public void onConnected(@Nullable Bundle bundle) {
//Permission check for Android 6.0+
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, getPendingIntent());
}
}

@Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

https://riptutorial.com/ 879
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

LocationReceiver

NOTE: Don't forget to register this receiver in the Manifest!

public class LocationReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
if(LocationResult.hasResult(intent)){
LocationResult locationResult = LocationResult.extractResult(intent);
LocalBroadcastManager.getInstance(context).sendBroadcast(new
Intent("googleLocation").putExtra("result", locationResult));
}
}
}

Requesting location updates using LocationManager

As always, you need to make sure you have the required permissions.

public class MainActivity extends AppCompatActivity implements LocationListener{

private LocationManager mLocationManager = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);

mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);


}

@Override
protected void onResume() {
super.onResume();

try {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
catch(SecurityException e){
// The app doesn't have the correct permissions
}
}

@Override
protected void onPause() {
try{
mLocationManager.removeUpdates(this);

https://riptutorial.com/ 880
}
catch (SecurityException e){
// The app doesn't have the correct permissions
}

super.onPause();
}

@Override
public void onLocationChanged(Location location) {
// We received a location update!
Log.i("onLocationChanged", location.toString());
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

@Override
public void onProviderEnabled(String provider) {

@Override
public void onProviderDisabled(String provider) {

}
}

Requesting location updates on a separate thread using LocationManager

As always, you need to make sure you have the required permissions.

public class MainActivity extends AppCompatActivity implements LocationListener{

private LocationManager mLocationManager = null;


HandlerThread mLocationHandlerThread = null;
Looper mLocationHandlerLooper = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);

mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);


mLocationHandlerThread = new HandlerThread("locationHandlerThread");
}

@Override
protected void onResume() {
super.onResume();

mLocationHandlerThread.start();

https://riptutorial.com/ 881
mLocationHandlerLooper = mLocationHandlerThread.getLooper();

try {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this,
mLocationHandlerLooper);
}
catch(SecurityException e){
// The app doesn't have the correct permissions
}
}

@Override
protected void onPause() {
try{
mLocationManager.removeUpdates(this);
}
catch (SecurityException e){
// The app doesn't have the correct permissions
}

mLocationHandlerLooper = null;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)


mLocationHandlerThread.quitSafely();
else
mLocationHandlerThread.quit();

mL