Showing posts with label Android. Show all posts
Showing posts with label Android. Show all posts

Saturday, 16 June 2018

Say No More To TextWatcher Callback


As Android Developer, we have used TextWatcher callback to listen any of the changes in the EditText.


Something like this :
editText.addTextChangedListener(object : TextWatcher {

override fun afterTextChanged(p0: Editable?) {

}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {

}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {

}
})

Data Binding Implementation


In Your xml Layout use OnTextChanged property

android:onTextChanged="@{model.onPasswordTextChanged}"


And call the view model user defined method to handle text changes in EditText. Full Snippet is below :


<EditText
android:id="@+id/password_et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/username_et"
android:layout_marginTop="10dp"
android:hint="Password"
android:onTextChanged="@{model.onPasswordTextChanged}"
android:inputType="textPassword" />


ViewModel User defined method can be like this (implement as per your implementation):


fun onPasswordTextChanged(s: CharSequence,start: Int,before : Int,
count :Int){
    //TODO write your implementation here ...
}



Now no more of TextWatcher callback in your View(Activity/Fragment), Instead use data binding to avoid boilerplate code.

Use MVVM, implement user defined method’s in ViewModel to handle OnTextChanged in xml.

Hope to see more of this implementation in future :-)

Cheers!!

Monday, 11 June 2018

Architecture Components In Android

What are Architecture Components? 


A Set Libraries from Google which will help Developer’s Design Applications :

1. Testable

2. Maintainable

3. Robust

Moreover, Handling UI part of the applications I.e Activity/Fragment Lifecycle and managing persistence stage. Introducing concept’s Like ViewModel to easily handle UI data when there are orientation changes.
There are various things to learn in Architecture Components as it makes Life easy for the Developer.Let’s Dig deep into these components and understand functionality of Each Component included here.


1. ViewModel

 Responsibility to Manage/Store UI (Activity/Fragment) related DATA, So that data is persist whenever there are configuration changes like Screen Orientation. ViewModel should not contains UI (Activity/Fragment) references.

Note : We do not need worry about Memory Leaks as ViewModel is LIFECYCLE aware.


2. LiveData 

As name is depicting, this will deal with Live data changes. This component hold’s value which can be observed by UI for changes or Can also be observed by ViewModel again depends upon your requirement.

Note : It help’s controlling crashes as it is LIFECYCLE aware I.e if UI (Activity/Fragment) is Alive to observe changes or Not.

There is LifeCycle Owner, In Android activity is Lifecycle owner. So whenever a activity changes states i.e pause, stop etc it is responsibility of the LiveData to decide whether to send data from observer or not.

Usage Of LiveData Types :


 1. LiveData : 

is very useful as using this we can listen to every change made to Room database I.e on every Sql query executed.

2. MutableLiveData : 

Is wrapping a data type inside LiveData. This must be used whenever you want to communicate between ViewModel and Activity. Good thing about this type is there no leak as it does not required any context.

3. MediatorLiveData : 

This is used to listen Other LiveData types and connects Repository to UI (Activity/Fragment) via ViewModel.

Room

Room Persistence Lib The Room persistence library provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.

Learn more about Room from Below Link :

https://developer.android.com/training/data-storage/room/

Source Codehttps://github.com/CammyKamal/ArchComponentsKotlin

Cheers!!

Thursday, 3 August 2017

Android Text with Custom color Outline

I was working on some sample Android App where i tried adding a small utility i.e adding a custom border to text within app with a custom color. Some times we get requirement's in apps where we need to implement such text's in views. So here's a small and useful code snippet to implement something like this (for Android Devs).

Override onDraw method for custom Textview
@Override
public void onDraw(Canvas canvas)
{
    int textColor = getTextColors().getDefaultColor();
    setTextColor(Color.BLACK);
    getPaint().setStrokeWidth(10);
    getPaint().setStyle(Paint.Style.STROKE);
    super.onDraw(canvas);
    setTextColor(textColor);
    getPaint().setStrokeWidth(0);
    getPaint().setStyle(Paint.Style.FILL);
    super.onDraw(canvas);
}


Cheers!!

Thursday, 27 July 2017

Loading custom headers on every page load inside a web view

Sometimes we have a requirement to send custom headers while opening a webview and also pass same headers whenever user navigates to another webpage within the webview. So here's how we can achieve that :


private class MyWebViewClient extends WebViewClient {
       @Override
       public void onPageStarted(WebView webView, String url, Bitmap favicon) {
           super.onPageStarted(webView, url, favicon);
       }

       @Override
       public void onPageFinished(WebView view, String url) {
           super.onPageFinished(view, url);
       }

       @Override
       public void onLoadResource(WebView view, String url) {
       }

       // api less then 24
       @SuppressWarnings("deprecation")
       @Override
       public boolean shouldOverrideUrlLoading(WebView view, String url) {
           return view.load(url,yourheaders);
       }

       // api greater than 24
       @TargetApi(Build.VERSION_CODES.N)
       @Override
       public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
           return view.load(request.getUrl(),yourheaders);
   }

   }

Thursday, 25 May 2017

How to add a common header across all activities using Parent-Child Relationship

This blog post demonstrates how to add a common header layout in all our Android Activities using simple Parent-Child Relationship.

Note : you can add Fragments as well in the container i am using in the parent class to have one activity and multiple fragments as per your app architecture.

My use case was to implement a common header in an existing project with 50+ activities which shows a to line header with a message whether a user is online or offline without changing to much in the existing code.  


1. BaseActivity.java


package kamal.com.headtest;

import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class BaseActivity extends AppCompatActivity {

    private TextView tvHeader,tvClose;
    private FrameLayout activityContainer;
    private RelativeLayout rlHeaderView;

    @Override
    public void setContentView(int layoutResID) {
        LinearLayout llparentView = (LinearLayout) getLayoutInflater().inflate(R.layout.activity_main, null);
        initViews(llparentView);
        getLayoutInflater().inflate(layoutResID, activityContainer, true);
        super.setContentView(llparentView);
    }

    /**
     *  Initialize BaseActivity Views
     * @param view : parent use to initialize child views
     */
    private void initViews(View view){
        tvHeader=(TextView)view.findViewById(R.id.headertext);
        tvClose=(TextView)view.findViewById(R.id.closebtn);
        activityContainer = (FrameLayout) view.findViewById(R.id.activity_content);
        rlHeaderView=(RelativeLayout)view.findViewById(R.id.headerviewrl);
        tvClose.setOnClickListener(closeBtnListener);
    }


    /**
     *  anonymous onclicklistener to handle a click event for Close button in header.
     */
    private View.OnClickListener closeBtnListener=new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            finish();
        }
    };

    /**
     *  Method to be overiden by child classes if need to hide header view
     * @param show : true or false as to handle visibility of the header
     */
    public void showHeader(boolean show){
        rlHeaderView.setVisibility(show ? View.VISIBLE : View.GONE);
    }

    /**
     *  Method to be overiden by child classes if need to hide header view
     * @param value : of the header
     */
    public void setHeaderText(String value){
        tvHeader.setText(value);
    }
}


2. ChildActivity.java

package kamal.com.headtest;
import android.os.Bundle;
import android.support.annotation.Nullable;

public class ChildActivity extends BaseActivity{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.childlayout);
        showHeader(true);;
    }
}

3. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parent_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/headerviewrl"
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:layout_height="?actionBarSize">

        <TextView
            android:id="@+id/headertext"
            android:layout_width="wrap_content"
            android:layout_height="?actionBarSize"
            android:layout_centerHorizontal="true"
            android:gravity="center"
            android:padding="10dp"
            android:textSize="20sp"
            android:textStyle="bold"
            android:text="My Header View" />

        <TextView
            android:id="@+id/closebtn"
            android:layout_width="wrap_content"
            android:layout_height="?actionBarSize"
            android:gravity="center"
            android:padding="10dp"
            android:textSize="30sp"
            android:textStyle="bold"
            android:layout_alignParentRight="true"
            android:text="X" />

    </RelativeLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="#000000"
        />

    <FrameLayout
        android:id="@+id/activity_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>


4. childlayout.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="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:layout_marginTop="10dp"
        android:layout_centerHorizontal="true"
        android:text="Testing child" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:layout_marginTop="10dp"
        android:layout_centerHorizontal="true"
        android:text="Testing child" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:layout_marginTop="10dp"
        android:layout_centerHorizontal="true"
        android:text="Testing child" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:layout_marginTop="10dp"
        android:layout_centerHorizontal="true"
        android:text="Testing child" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:layout_marginTop="10dp"
        android:layout_centerHorizontal="true"
        android:text="Testing child" />

</LinearLayout>


5. manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kamal.com.headtest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".ChildActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>



Output:





Cheers :-)

Thursday, 2 March 2017

FCM Android Integration


  FCM has replaced GCM for push Notifications in android.So we will be discussing how to    
  integrate FCM in android app and handle push notifications.

  Below are the steps to start

 1. Create a project on Firebase console.




2. Select Firebase for android apps.

3. Register app by entering the app application id and SHA1 finferprint.

4. Download the config json file and place in your app folder.


Place downloaded json to your app directory




5. Finally Add Firebase sdk  .



 App level gradle :

 // Add this line to gradle dependencies.
  classpath 'com.google.gms:google-services:3.0.0'

Below is the app level Gradle file:      

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

buildscript {

    repositories {
        jcenter()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.2'
        // Add this line
        classpath 'com.google.gms:google-services:3.0.0'
       }
}



allprojects {
    repositories {
        jcenter()
    }
}


Add FirebaseMessaging dependencies to your module level gradle file
compile 'com.google.firebase:firebase-messaging:10.2.0'

Below is the module Gradle file :

apply plugin: 'com.android.application'
android {
    compileSdkVersion 25
    buildToolsVersion "25.0.0"
    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:25.0.0'
    compile 'com.google.firebase:firebase-messaging:10.2.0'
    compile 'com.google.android.gms:play-services:10.2.0'
}

Now add below services to your app so as to get the required device token .


1. MyFirebaseInstanceIDService 

import android.util.Log;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;

/**
 * Created by kamal on 3/3/2017.
 */

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

    private static final String TAG = "MyFirebaseIIDService";

    @Override
    public void onTokenRefresh() {
        //Getting registration token for the device
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.d(TAG, "Refreshed token: " + refreshedToken);
    }

    private void sendRegistrationToServer(String token) {
    }

}


Create MyFirebaseMessagingService to handle the notifications.

2.  MyFirebaseMessagingService 


import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;


/**
 * Created by kamal on 3/3/2017.

 */


public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.e(TAG, "From: " + remoteMessage.getFrom());
        Log.e(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
        handleNotification(remoteMessage.getNotification().getBody());
    }



    private void handleNotification(String message) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
                PendingIntent.FLAG_ONE_SHOT);

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Firebase Push Notification")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0, notificationBuilder.build());
    }

}


Finally add these services to manifest.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="">
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".LocationClass">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".MainActivity"
            android:windowSoftInputMode="stateAlwaysHidden"
            />

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

    </application>

</manifest>

Now you can test the notifications by going to Notifcations tab in the firebase project dashboard.
And send push notifications to devices.


Output :



Cheers!!




Tuesday, 28 February 2017

Android Google Maps with Current Location Demo Part 2

In this article i'll continue google maps into your android application and adding current location using Google Api Client with Location listener using Fuse Api.

Here i'll be handling Android runtime permission to enable Fine location permission for Fetching current location of users running 6.0 or above.

Location dialog will also be available to prompt user to enable location services so that fuse api can fetch the user's current location.

1. Add latest google play services dependency to your module gradle for eg :

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  compile 'com.android.support:appcompat-v7:25.0.0' 
  compile 'com.google.android.gms:play-services:10.2.0'
}


2. Add Api keys and google play services version to the manifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kamal.com.androidv2mapsdemo">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">        <activity android:name=".MapsActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--Defining Map Configs here. Including Google play services version and Map Key-->
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="Your Api key" />
    </application>

</manifest>

3. Add a container to add map on runtime in Xml layout.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_maps"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- The map fragments will go here -->
    <RelativeLayout
        android:id="@+id/map_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></RelativeLayout>

</RelativeLayout>

4. MapsActivity to inflate map.
 import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallbacks;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStates;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;


public class MapsActivity extends AppCompatActivity implements
        OnMapReadyCallback , GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    private GoogleMap googleMap;
    private SupportMapFragment fragment;
    private GoogleApiClient mGoogleApiClient;

    /**
     * The desired interval for location updates. Inexact. Updates may be more or less frequent.
     */
    public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
    /**
     * The fastest rate for active location updates. Exact. Updates will never be more frequent
     * than this value.
     */
    public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
            UPDATE_INTERVAL_IN_MILLISECONDS / 2;
    /**
     * Stores parameters for requests to the FusedLocationProviderApi.
     */
    protected LocationRequest mLocationRequest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        setupDynamicMapFragment();
        if(checkGooglePlayServicesAvailable())
        initializeMap();
    }

    private void setupDynamicMapFragment() {
        FragmentManager fm = this.getSupportFragmentManager();
        fragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
        if (fragment == null) {
            fragment = SupportMapFragment.newInstance();
            fm.beginTransaction().replace(R.id.map_container, fragment).commit();
        }
    }


    /**
     * function to load map. If map is not created it will create it for you
     */
    private void initializeMap() {
        if (googleMap == null) {
            fragment.getMapAsync(this);
        }
    }


    @Override
    public void onMapReady(GoogleMap googleMap) {
        this.googleMap=googleMap;
        if (googleMap != null) {
            googleMap.getUiSettings().setMapToolbarEnabled(false);
            if (Build.VERSION.SDK_INT < 23) {
                googleMap.setMyLocationEnabled(true);
                buildGoogleApiClient();
            }else{
                checkFineLocationPermission();
            }
        }
    }


    protected synchronized void buildGoogleApiClient() {
        Toast.makeText(this,"buildGoogleApiClient", Toast.LENGTH_SHORT).show();
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }

    /**
     * Check whether Google Play Services are available.
     *
     * If not, then display dialog allowing user to update Google Play Services
     *
     * @return true if available, or false if not
     */
    private boolean checkGooglePlayServicesAvailable( )
    {
        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
        final int status = googleAPI.isGooglePlayServicesAvailable(this);
        if (status == ConnectionResult.SUCCESS)
        {
            return true;
        }
        Log.e("", "Google Play Services not available: " + GooglePlayServicesUtil.getErrorString(status));

        if (googleAPI.isUserResolvableError(status))
        {
            final Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(status, this, 1);
            if (errorDialog != null)
            {
                errorDialog.show();
            }
        }
        return false;
    }


    @Override
    public void onConnected(@Nullable Bundle bundle) {
        Toast.makeText(this,"onConnected",Toast.LENGTH_SHORT).show();
        //mLocationRequest.setSmallestDisplacement(0.1F); //1/10 meter
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(5000); //5 seconds
        mLocationRequest.setFastestInterval(3000); //3 seconds
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(mLocationRequest);
        PendingResult<LocationSettingsResult> result =
                LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient,
                        builder.build());
        result.setResultCallback(new ResultCallbacks<LocationSettingsResult>() {
            @Override
            public void onSuccess(@NonNull LocationSettingsResult result) {
                final Status status = result.getStatus();
                final LocationSettingsStates s= result.getLocationSettingsStates();
                switch (status.getStatusCode()) {
                    case LocationSettingsStatusCodes.SUCCESS:
                        // All location settings are satisfied. The client can
                        // initialize location requests here.
                        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, MapsActivity.this);
                        break;
                    case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                        // Location settings are not satisfied, but this can be fixed
                        // by showing the user a dialog.
                        try {
                            // Show the dialog by calling startResolutionForResult(),
                            // and check the result in onActivityResult().
                            status.startResolutionForResult(
                                    MapsActivity.this,
                                    100);
                        } catch (IntentSender.SendIntentException e) {
                            // Ignore the error.
                        }
                        break;
                    case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                        // Location settings are not satisfied. However, we have no way
                        // to fix the settings so we won't show the dialog.
                        break;
                }
            }


            @Override
            public void onFailure(@NonNull Status status) {
                Log.e("","");
                try {
                    status.startResolutionForResult(MapsActivity.this, 100);
                } catch (IntentSender.SendIntentException e) {
                    e.printStackTrace();
                }
            }
        }) ;
    }



    @Override
    public void onConnectionSuspended(int i) {
    }

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

    }


    @Override
    public void onLocationChanged(Location location) {
        //Place current location marker
        LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
        markerOptions.title("Current Position");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
        googleMap.addMarker(markerOptions);

        //move map camera
        googleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        googleMap.animateCamera(CameraUpdateFactory.zoomTo(5));


        //stop location updates
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }

    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode==100 ){
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        }
    }


    /**
     *   Write external Permission check
     */
    private void checkFineLocationPermission(){
        if ((ContextCompat.checkSelfPermission(this,  android.Manifest.permission.ACCESS_FINE_LOCATION))
                != PackageManager.PERMISSION_GRANTED) {
            // This condition checks whether user has earlier denied the permission or not just by clicking on deny in the permission dialog.
            //Remember not on the never ask check box then deny in the permission dialog
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    android.Manifest.permission.ACCESS_FINE_LOCATION)) {
                /**
                 * Show an explanation to user why this permission in needed by us. Here using alert dialog to show the permission use.
                 */
                new AlertDialog.Builder(this)
                        .setTitle("Permission Required")
                        .setMessage("This permission was denied earlier by you. This permission is required to use card.")
                        .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                                ActivityCompat.requestPermissions(MapsActivity.this,
                                        new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                                        4);
                            }
                        })
                        .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        })
                        .setIcon(android.R.drawable.ic_dialog_alert)
                        .show();
            } else {
                //Just ask for the permission for first time. This block will come into play when user is trying to use feature which requires permission grant.
                //So for the first time user will be into this else block. So just ask for the permission you need by showing default permission dialog
                ActivityCompat.requestPermissions(MapsActivity.this,
                        new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, 4);
            }
        }else {
            // If permission is already granted by user then we will be into this else block. So do whatever is required here
            //            Toast.makeText(this,"Permission Already granted",Toast.LENGTH_LONG).show();
            googleMap.setMyLocationEnabled(true);
            buildGoogleApiClient();
        }
    }



    /**
     *  This method will be invoked when user allows or deny's a permission from the permission dialog so take actions accordingly.
     * @param requestCode : returns requestCode
     * @param permissions : returns permissions
     * @param grantResults : returns grantResults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 4:
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    googleMap.setMyLocationEnabled(true);
                    buildGoogleApiClient();
                } else {
                    String permission = permissions[0];
                    boolean showRationale = ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
                    if (!showRationale) {
                        //We will be in this block when User has ticked the never show dialog and denied the permission from the permission dialog
                        //Here we can not request the permission again if user has denied the permission with never ask option enabled.
                        //Only way is to show a imfo dialog and ask user to grant the permission from settings.
                        Toast.makeText(this, "Write Storage Permission Denied with never show options." +
                                        "Please manually enable the permission and re-start the app to use this feature.",
                                Toast.LENGTH_LONG).show();
                    } else {
                        Toast.makeText(this, "Write Storage Permission Denied", Toast.LENGTH_LONG).show();
                    }
                }
                break;
            default:
        }
    }

}
Now you can see users current location on google maps.


Download the full source code from : Android Google Maps Demo Link

Cheers!!

Monday, 27 February 2017

Android Google Map Demo part 1

In this article i'll be discussing how to easily integrate maps into your android application. So to start firstly you would need to setup your android app as normally we do. Before starting please create your project on Google web console and obtain required Api keys for Google Maps using SHA1 fingerprint of you System,

1. Add latest Google Play Services Dependency to your module gradle for eg :

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  compile 'com.android.support:appcompat-v7:25.0.0' 
  compile 'com.google.android.gms:play-services:10.2.0'
}


2. Add Api Keys and Google Play Services Version to the manifest file.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kamal.com.androidv2mapsdemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MapsActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--Defining Map Configs here. Including Google play services version and Map Key-->
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="Your Api key" />
    </application>

</manifest>


3. Add a container to add map on runtime in Xml layout.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_maps"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- The map fragments will go here -->
    <RelativeLayout
        android:id="@+id/map_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></RelativeLayout>

</RelativeLayout>


4. MapsActivity to inflate map.

package kamal.com.androidv2mapsdemo;

import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;

public class MapsActivity extends AppCompatActivity implements
        OnMapReadyCallback {
    private GoogleMap googleMap;
    private SupportMapFragment fragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        setupDynamicMapFragment();
        if(checkGooglePlayServicesAvailable())
        initializeMap();
    }


    private void setupDynamicMapFragment() {
        FragmentManager fm = this.getSupportFragmentManager();
        fragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
        if (fragment == null) {
            fragment = SupportMapFragment.newInstance();
            fm.beginTransaction().replace(R.id.map_container, fragment).commit();
        }
    }


    /**
     * function to load map. If map is not created it will create it for you
     */
    private void initializeMap() {
        if (googleMap == null) {
            fragment.getMapAsync(this);
        }
    }


    @Override
    public void onMapReady(GoogleMap googleMap) {
        this.googleMap=googleMap;
        if (googleMap != null) {
            googleMap.getUiSettings().setMapToolbarEnabled(false);
        }
    }


    /**
     * Check whether Google Play Services are available.
     *
     * If not, then display dialog allowing user to update Google Play Services
     *
     * @return true if available, or false if not
     */
    private boolean checkGooglePlayServicesAvailable( )
    {
        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
        final int status = googleAPI.isGooglePlayServicesAvailable(this);
        if (status == ConnectionResult.SUCCESS)
        {
            return true;
        }

        Log.e("", "Google Play Services not available: " + GooglePlayServicesUtil.getErrorString(status));

        if (googleAPI.isUserResolvableError(status))
        {
            final Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(status, this, 1);
            if (errorDialog != null)
            {
                errorDialog.show();
            }
        }

        return false;
    }

}


That's it, We are done with Google maps for this article. You can see your google maps now.



Cheers!!

Tuesday, 12 July 2016

Opening Android App When Particular link/Host with Scheme is opened in Browser.

Opening Android Application when particular "Host" is opened in Android mobile browser or particular Link is opened Also named as Mobile DeepLinking.

We need to define host & scheme in the intent filters of the activity, which we need to open when link or host is opened.


Below is the code for opening app when particular Host is opened.

 <activity


            android:name=".ActivityName">
<intent-filter>

                <action android:name="android.intent.action.GALLERY" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />
<data
                    android:host="http"
                    android:scheme="abc.com" /> 
</intent-filter>

</activity>

Below is the code for opening app when we are trying particular Link  in browser.


 <activity

        android:name=".ActivityName">
        <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="abc.com"
                  android:pathPrefix="/images/" />
            <data android:scheme="https"
                  android:host="abc.com"
                  android:pathPrefix="/images/" />
        </intent-filter>
   </activity>
 
   
Cheers!!   

Thursday, 7 July 2016

Firebase (via Assistant) Crash Reporting In Android Studio 2.2 Preview

Hi Guys, Today i'll be discussing how to use Firebase which is present as a Assistant in Android Studio 2.2.1 Preview.

As we know Firebase is a Cloud Services Provider which was acquired by Google back in 2014 in order to help developer build better real-time apps.

Now Firebase will be available as Assistant in Android Studio upcoming version which will help us easliy integrate following :

1. Analytics
2. Cloud Messaging
3. Authenication
4. Real time Database
5. Storage
6. Crash Reporting etc..

Now using Assistant present in Android Studio to use/integrate one the above services is quite easy and fast.

Here i'll be going through the steps to integrate Crash Reporting via Firebase in one of my demo app.

By Crash Reporting you can track all the crashes that occurs in your app and rectify once to get the report via Firebase.

So here are the steps :

1. Go to Tools and select Firebase.





2. You will see the Assistant opened in the right side in a tab named Assistant.

3. Now Scroll down and click on Crash Reporting






4. Click on Setup Firebase Crash reporting







5. Now  This will ask to to connect to Firebase.

6. Once you click on Connect it will take you to Browser and ask you to login via Google Account and will ask for permission.





7. After that Successful login you will be re-directed to Firebase Console and you can come back to Android Studio where it shows connected.





Note : This will automatically create your project inside google web console. Where make sure your Firebase Api is Enable for the project in case if you face
crash reporting problems.

8. Now you need to create a new Firebase project or select the existing Firebase Google project in which we wish to integrate Firebase.






Here you can create a new Firebase project.

After you select/create Firebase project and connect then it shows progress in Assistant like this :





Now once you are connected Assistance show you as connected as well.




After this we are all done setting up Firebase project and connection. Now Lets come to Coding part which is also a small part to do.

9. Now you need to add following Classpath into your buildscript dependencies

buildscript {
    // ...
    dependencies {
        // ...
        classpath 'com.google.gms:google-services:3.0.0'
    }
}

10. After that you need to add following dependencies in your app level build.gradle

android {

    // ...

}

dependencies {

    // ..

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

}

// ADD THIS AT THE BOTTOM

apply plugin: 'com.google.gms.google-services'

Note : Make sure you are using the latest version of Firebase and Google play services here 11. Add following dependencies to app level build.gradle as well
    compile 'com.google.android.gms:play-services:9.2.0'
12. Now all is done. You can following code lines to track crashes
FirebaseCrash.logcat(Log.ERROR, TAG, "NPE caught");
FirebaseCrash.report(ex);
This Lines will send crash reports to cloud. And you can login to console and check the crash reports easliy there.

Note : Every crash is visible on console only after 20-25 minutes after it is reported.


In one of my demos i've created arithmetic exception to check the Firebase something like this :


try { int i = 10 / 0; }catch (Exception e){ FirebaseCrash.logcat(Log.ERROR, "Crash", "NPE caught"); FirebaseCrash.report(e); }


Which reported the Crash to console which was available to check after 20-25 minutes.
Once Crash occurs Firebase service starts and sends the crash details up to cloud.

You can find the below log in you logcat when Firebase service runs successfully.


Logcat Details which ensures Firebase Sent the Report successfully :

D/FirebaseCrashApiImpl: throwable java.lang.ArithmeticException: divide by zero
I/FirebaseCrashReceiverServiceImpl: FirebaseCrashReceiverServiceImpl created by
ClassLoader com.google.android.chimera.container.internal.DelegateLastPathClassLoader
[DexPathList[[zip file "/data/user/0/com.google.android.gms/app_chimera/m/00000005/
DynamiteModulesC_GmsCore_prodmnc_xxhdpi_release.apk"],nativeLibraryDirectories=
[/data/user/0/com.google.android.gms/app_chimera/m/00000005/n/armeabi-v7a,
/data/user/0/com.google.android.gms/app_chimera/m/00000005/n/armeabi,
/vendor/lib, /system/lib]]]  com.youpackage:background_crash D/FirebaseCrashReceiverServiceImpl: onCreate
com.youpackage:background_crash I/DynamiteModule: Considering local module com.google.android.gms.flags:0 and remote module com.google.android.gms.flags:1
com.youpackage:background_crash I/DynamiteModule: Selected remote version of com.google.android.gms.flags, version >= 1
com.youpackage:background_crash D/FirebaseCrashReceiverServiceImpl: Saving crash
com.youpackage:background_crash I/FirebaseCrashSenderServiceImpl: FirebaseCrashSenderServiceImpl created by ClassLoader com.google.android.chimera.container.internal.DelegateLastPathClassLoader[DexPathList[[zip file "/data/user/0/com.google.android.gms/app_chimera/m/00000005/DynamiteModulesC_GmsCore_prodmnc_xxhdpi_release.apk"],nativeLibraryDirectories=[/data/user/0/com.google.android.gms/app_chimera/m/00000005/n/armeabi-v7a, /data/user/0/com.google.android.gms/app_chimera/m/00000005/n/armeabi, /vendor/lib, /system/lib]]]


D/FirebaseCrashSenderServiceImpl: Response code: 200
D/FirebaseCrashSenderServiceImpl: Report sent


You can check the Crash reports on Console by logging into https://console.firebase.google.com in crash reports will look like this








Cheers!!

References :
https://firebase.google.com/docs/android

Monday, 21 March 2016

Method to add events from your Android App to default Calendar application



Please pass required parameters to the below method in order add events to default Calendar in android . 

Add Calendar and Accounts permission to manifest. And Also ask for Calendar Runtime permission for 6.0.

 Accounts permission is normal permission so Runtime implementation for same is not required.

 1. Manifest File

<uses-permission android:name="android.permission.GET_ACCOUNTS"/> <uses-permission android:name="android.permission.READ_CALENDAR"/> <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
2. Methods to add event to Calendar (Modify as per need)

//here you can pass a model class which will contains all your values instead of many parameters

private void addEventToCalendar(Activity activity,String title,String startDateStr,String startTime, String endDateStr,String endTime,String eventDescription) { //Getting google accounts linked here Account[] accounts = AccountManager.get(activity).getAccountsByType( "com.google"); String accountName=""; for (Account acc : accounts) { Log.d(">>>>>>>", "Name: " + acc.name + "-----Type: " + acc.type); accountName = acc.name; } //Getting required calendar ID here long calID = getCalendarId(activity,accountName); long startMillis = 0; long endMillis = 0; Date startDate = null; //Converting date/time as per need try { startDate = new SimpleDateFormat("yyyy-MM-dd hh:mmaa", Locale.ENGLISH).parse(startDateStr+" "+startTime); } catch (ParseException e1) { e1.printStackTrace(); } startMillis = startDate.getTime(); Date endDate = null; try { endDate = new SimpleDateFormat("yyyy-MM-dd hh:mmaa", Locale.ENGLISH).parse(endDateStr+" "+endTime); } catch (ParseException e) { e.printStackTrace(); } endMillis = endDate.getTime(); //Creating content values which will be used to enter data from a query into calendar content resolver ContentResolver cr = activity.getContentResolver(); ContentValues values = new ContentValues(); values.put(CalendarContract.Events.DTSTART, startMillis); values.put(CalendarContract.Events.DTEND, endMillis); values.put(CalendarContract.Events.TITLE, title); values.put(CalendarContract.Events.DESCRIPTION,eventDescription); values.put(CalendarContract.Events.CALENDAR_ID, calID); values.put(CalendarContract.Events.EVENT_TIMEZONE, Calendar.getInstance().getTimeZone().getDisplayName()); try { // Executing query to enter event into the calendar here Uri uri = cr.insert(CalendarContract.Events.CONTENT_URI, values); } catch(Exception e) { e.printStackTrace(); } } private static long getCalendarId(Activity activity,String MY_ACCOUNT_NAME) { String[] projection = new String[] { BaseColumns._ID }; String selection = CalendarContract.Calendars.ACCOUNT_NAME + " = ?"; String[] selArgs = new String[] { MY_ACCOUNT_NAME }; Cursor cursor = activity.getContentResolver().query( CalendarContract.Calendars.CONTENT_URI, projection, selection, selArgs, null); if (cursor.moveToFirst()) { return cursor.getLong(0); } return -1; }


References : http://developer.android.com/index.html

Thursday, 31 December 2015

What are Normal permissions in Android?

There are two types of permissions:-

1. Normal permissions 
2. Runtime Permissions

We are familiar with Runtime permissions, here we will be discussing about Normal Permissions.
Normal permissions are the permissions which are automatically granted during install time. We need not to check these in our code(i.e runtime).And these are the permissions which user can not revoke from app settings as well.
We simply declare these permissions in the Android Manifest.xml and it will work nomally as did earlier.
.
Below is the list of permissions :-

android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.READ_SYNC_SETTINGS
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER

Sunday, 6 December 2015

Download/Upload files using Dropbox Api Android

This tutorial is about Downloading/Uploading files from/to Dropbox using DropboxApi Android.


Firstly create your App key and App Secret key to use this api from below link.
Dropbox App Console : https://www.dropbox.com/developers-v1/apps

Include the below jars files from the downloaded Dropbox Sdk :
1. dropbox-android-sdk-1.6.3.jar
2. json_simple-1.1.jar

1. MainActivity.java

public class MainActivity extends AppCompatActivity {

        //path of the file to be uploaded here    
String path= Environment.getExternalStorageDirectory()
            .getAbsolutePath() + "/photo.jpg";
    final static private String APP_KEY = "";
    final static private String APP_SECRET = "";
    private DropboxAPI<AndroidAuthSession> mDBApi;
    DropboxAPI.Entry response;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /**
         *   i am using this mode . you can use the Async task to upload and download file
         */
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
        setContentView(R.layout.activity_main);
        //Generate dropbox session from the generated keys
        AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
        AndroidAuthSession session = new AndroidAuthSession(appKeys);
        mDBApi = new DropboxAPI<AndroidAuthSession>(session);
        //Check if user has already authorized the dropbox app for you..
        if(!getAccessToken().equalsIgnoreCase("")){
            mDBApi.getSession().setOAuth2AccessToken(getAccessToken());
        }else{
            //if not authorized. i.e for the first time then
            mDBApi = new DropboxAPI<AndroidAuthSession>(session);
            mDBApi.getSession().startOAuth2Authentication(MainActivity.this);
        }

        ((Button) findViewById(R.id.uploaddata)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                uploadFile(path);
            }
        });

        ((Button) findViewById(R.id.downloadfile)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                downloadFile(Environment.getExternalStorageDirectory()
                        .getAbsolutePath());
            }
        });
    }

    protected void onResume() {
        super.onResume();
        //if first time and save the Access Token here
        if(getAccessToken().equalsIgnoreCase("")) {
            if (mDBApi.getSession().authenticationSuccessful()) {
                try {
                    // Required to complete auth, sets the access token on the session
                    mDBApi.getSession().finishAuthentication();
                    String accessToken = mDBApi.getSession().getOAuth2AccessToken();
                    saveAccessToken(accessToken);
                } catch (IllegalStateException e) {
                    Log.i("Error", "Error authenticating", e);
                }
            }
        }
    }

    private void saveAccessToken(String accessToken){
        SharedPreferences sharedPreferences=getSharedPreferences("Prefs", Context.MODE_PRIVATE);
        sharedPreferences.edit().putString("accessToken", accessToken).commit();
    }

    private String getAccessToken(){
        SharedPreferences sharedPreferences=getSharedPreferences("Prefs", Context.MODE_PRIVATE);
        return sharedPreferences.getString("accessToken","");
    }

    public void uploadFile(String file_path) {
        File file = new File(file_path);
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try {
            response = mDBApi.putFile("/photo.jpg", inputStream,
                    file.length(), null, null);
            if(response.rev!=null){
                Toast.makeText(this,"File Uploaded successfully..",Toast.LENGTH_LONG).show();
            }
            Log.i("Success", "The uploaded file's rev is: " + response.rev);
        } catch (DropboxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void downloadFile(String file_path) {
       //Path where you want to stored the downloaded file form dropbox
        File file = new File(file_path+"/testphoto.jpg");
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        DropboxAPI.DropboxFileInfo info = null;
        try {
            info = mDBApi.getFile("/photo.jpg", null, outputStream, null);
            if(info.getMetadata().rev!=null){
                Toast.makeText(this,"File Downloaded successfully..",Toast.LENGTH_LONG).show();
            }
            Log.i("Success", "The file's rev is: "
                    + info.getMetadata().rev);
        } catch (DropboxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

2. Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.kamal.dropboxdemoapi" >
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.dropbox.client2.android.AuthActivity"
            android:launchMode="singleTask"
            android:configChanges="orientation|keyboard">
            <intent-filter>
                <!-- Change this to be db- followed by your app key -->
                <data android:scheme="db-Your App key here" />
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.BROWSABLE"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            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>


Find the source from  Github : https://github.com/CammyKamal/BlogTutorials/tree/master/DropBoxDemoApi