Monday, 16 January 2017

Custom SeekBar (Discrete SeekBar) in android

SeekBar is very good user Interface to present to set any value between from minimum to maximum range. But the things is that how can we satisfy to users to give or show them with best user interface experience because this time is only Material time . So in this article I am talking about to custom seek bar implementation.

If we talk about Material Design seek bar, I found one library that suitable to provides Discrete Seek bar. This library is providing amazing  user interface for custom seek bar.
Here is the DiscreteSeekBar link. Please give full credit to him that made our life easy.

In this article I am focusing four different ways that we can use this discrete seek bar in our projects. For example below here

1. Normal Seek bar
2. Multiple of 100 (ex 100, 200, 300..etc) to select from 0 to 10000.
3. Multiple of 100 from range 500 to 10000 in between.
4. Interval kind of multiple of 100 from 500 to 1000 (exp 500, 600..etc)and then after multiple of 1000 from 1000 to 100000 (exp. 1000, 2000, 3000...etc)

Here is uploaded video that show this all four type implemented. Please check this video once.



Lets create an android project to implement this.



MainActivity.java

    
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar;

import butterknife.BindView;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.title_normal)
    TextView titleNormal;
    @BindView(R.id.discrete_normal)
    DiscreteSeekBar discreteNormal;
    @BindView(R.id.title_multiple)
    TextView titleMultiple;
    @BindView(R.id.discrete_multiple)
    DiscreteSeekBar discreteMultiple;
    @BindView(R.id.title_range_multiple)
    TextView titleRangeMultiple;
    @BindView(R.id.discrete_multiple_range)
    DiscreteSeekBar discreteMultipleRange;
    @BindView(R.id.title_interval_range_multiple)
    TextView titleIntervalRangeMultiple;
    @BindView(R.id.discrete_interval_multiple_range)
    DiscreteSeekBar discreteIntervalMultipleRange;

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

        initSeekBar(); // normal seek bar bar 0 to 100
        initMultipleOfSeekBar();   // multiple of 100 form 0 to 10000
        initMultipleRangeOfSeekBar();  // multiple of 100 form 500 to 10000
        initIntervalMultipleRangeOfSeekBar();   // multiple of 100 form 500 to 1000 and after multiple of 1000 from 1000 to 10000

    }

    private void initIntervalMultipleRangeOfSeekBar() {
        discreteIntervalMultipleRange.setMin(0);
        discreteIntervalMultipleRange.setMax(14);
        discreteIntervalMultipleRange.setNumericTransformer(new DiscreteSeekBar.NumericTransformer() {
            @Override
            public int transform(int value) {
                if (value <= 5) {
                    return (value * 100) + 500;
                }else {
                    return (value - 4) * 1000;
                }
            }
        });

        discreteIntervalMultipleRange.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() {
            @Override
            public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) {
                if (fromUser) {
                    int updatedValue = 0;
                    if (value <= 5) {
                         updatedValue = (value * 100) + 500;
                    }else{
                         updatedValue = (value - 4) * 1000;
                    }
                    titleIntervalRangeMultiple.setText("Interval Multiple Range SeekBar- Value: " + updatedValue);
                }
            }

            @Override
            public void onStartTrackingTouch(DiscreteSeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(DiscreteSeekBar seekBar) {

            }
        });
    }

    private void initMultipleRangeOfSeekBar() {

        discreteMultipleRange.setMin(0);
        discreteMultipleRange.setMax(95);
        discreteMultipleRange.setNumericTransformer(new DiscreteSeekBar.NumericTransformer() {
            @Override
            public int transform(int value) {
                return (value * 100) + 500;
            }
        });

        discreteMultipleRange.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() {
            @Override
            public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) {
                if (fromUser) {
                    int updatedValue = (value * 100) + 500;
                    titleRangeMultiple.setText("Multiple Range SeekBar- Value: " + updatedValue);
                }
            }

            @Override
            public void onStartTrackingTouch(DiscreteSeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(DiscreteSeekBar seekBar) {

            }
        });
    }

    private void initMultipleOfSeekBar() {
        discreteMultiple.setMin(0);
        discreteMultiple.setMax(100);  //result should be in multiple of 100
        discreteMultiple.setNumericTransformer(new DiscreteSeekBar.NumericTransformer() {
            @Override
            public int transform(int value) {
                return value * 100;
            }
        });

        discreteMultiple.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() {
            @Override
            public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) {
                titleMultiple.setText("Multiple SeekBar- Value: " + value * 100);
            }

            @Override
            public void onStartTrackingTouch(DiscreteSeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(DiscreteSeekBar seekBar) {

            }
        });
    }

    private void initSeekBar() {
        discreteNormal.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() {
            @Override
            public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) {
                titleNormal.setText("Normal SeekBar- Value: " + value);
            }

            @Override
            public void onStartTrackingTouch(DiscreteSeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(DiscreteSeekBar seekBar) {

            }
        });
    }
}

activity_main.xml

 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    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.sunil.customseekbarandroid.MainActivity">

    <RelativeLayout
        android:id="@+id/relative_normal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

       <TextView
            android:text="Normal SeekBar"
            android:id="@+id/title_normal"
            android:gravity="center"
            android:textSize="15sp"
            android:layout_marginBottom="20dp"
            android:textColor="@color/colorPrimary"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <org.adw.library.widgets.discreteseekbar.DiscreteSeekBar
            android:layout_below="@+id/title_normal"
            android:id="@+id/discrete_normal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:dsb_min="0"
            app:dsb_max="100"
            app:dsb_value="0"
            />

        <RelativeLayout
            android:layout_below="@+id/discrete_normal"
            android:layout_marginBottom="20dp"
            android:layout_width="match_parent"
            android:padding="5dp"
            android:layout_height="wrap_content">

           <TextView
                android:text="Min:1"
                android:gravity="left"
                android:textSize="12sp"
                android:layout_marginLeft="10dp"
                android:textColor="@color/colorPrimary"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

           <TextView
                android:text="Max:100"
                android:gravity="right"
                android:textSize="12sp"
                android:layout_marginRight="10dp"
                android:textColor="@color/colorPrimary"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />


        </RelativeLayout>

    </RelativeLayout>

   <RelativeLayout
        android:id="@+id/multiple_seekbar"
        android:layout_below="@+id/relative_normal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:text="Multiple of SeekBar"
            android:id="@+id/title_multiple"
            android:gravity="center"
            android:textSize="15sp"
            android:layout_marginBottom="20dp"
            android:textColor="@color/colorPrimary"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

       <org.adw.library.widgets.discreteseekbar.DiscreteSeekBar
            android:layout_below="@+id/title_multiple"
            android:id="@+id/discrete_multiple"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:dsb_min="0"
            app:dsb_max="100"
            app:dsb_value="0"
            />

       <RelativeLayout
            android:layout_below="@+id/discrete_multiple"
            android:layout_marginBottom="20dp"
            android:layout_width="match_parent"
            android:padding="5dp"
            android:layout_height="wrap_content">

           <TextView
                android:text="Min:0"
                android:gravity="left"
                android:textSize="12sp"
                android:layout_marginLeft="10dp"
                android:textColor="@color/colorPrimary"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

           <TextView
                android:text="Max:10000"
                android:gravity="right"
                android:textSize="12sp"
                android:layout_marginRight="10dp"
                android:textColor="@color/colorPrimary"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />


        </RelativeLayout>

   </RelativeLayout>

    <RelativeLayout
        android:id="@+id/multiple_range_seekbar"
        android:layout_below="@+id/multiple_seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

      <TextView
            android:text="Multiple Range of SeekBar"
            android:id="@+id/title_range_multiple"
            android:gravity="center"
            android:textSize="15sp"
            android:layout_marginBottom="20dp"
            android:textColor="@color/colorPrimary"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <org.adw.library.widgets.discreteseekbar.DiscreteSeekBar
            android:layout_below="@+id/title_range_multiple"
            android:id="@+id/discrete_multiple_range"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:dsb_min="0"
            app:dsb_max="100"
            app:dsb_value="0"
            />

        <RelativeLayout
            android:layout_below="@+id/discrete_multiple_range"
            android:layout_marginBottom="20dp"
            android:layout_width="match_parent"
            android:padding="5dp"
            android:layout_height="wrap_content">

           <TextView
                android:text="Min:500"
                android:gravity="left"
                android:textSize="12sp"
                android:layout_marginLeft="10dp"
                android:textColor="@color/colorPrimary"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <TextView
                android:text="Max:10000"
                android:gravity="right"
                android:textSize="12sp"
                android:layout_marginRight="10dp"
                android:textColor="@color/colorPrimary"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />


        </RelativeLayout>

   </RelativeLayout>

    <RelativeLayout
        android:id="@+id/interval_multiple_range_seekbar"
        android:layout_below="@+id/multiple_range_seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:text="Interval Multiple Range of SeekBar"
            android:id="@+id/title_interval_range_multiple"
            android:gravity="center"
            android:textSize="15sp"
            android:layout_marginBottom="20dp"
            android:textColor="@color/colorPrimary"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <org.adw.library.widgets.discreteseekbar.DiscreteSeekBar
            android:layout_below="@+id/title_interval_range_multiple"
            android:id="@+id/discrete_interval_multiple_range"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:dsb_min="0"
            app:dsb_max="100"
            app:dsb_value="0"
            />

        <RelativeLayout
            android:layout_below="@+id/discrete_interval_multiple_range"
            android:layout_marginBottom="20dp"
            android:layout_width="match_parent"
            android:padding="5dp"
            android:layout_height="wrap_content">

           <TextView
                android:text="Min:500"
                android:gravity="left"
                android:textSize="12sp"
                android:layout_marginLeft="10dp"
                android:textColor="@color/colorPrimary"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

           <TextView
                android:text="Max:10000"
                android:gravity="right"
                android:textSize="12sp"
                android:layout_marginRight="10dp"
                android:textColor="@color/colorPrimary"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />


       </RelativeLayout>

    </RelativeLayout>

</RelativeLayout>

Thanks for reading this post.

Friday, 13 January 2017

Fast Splash Screen in Android


In this tutorial I am focusing about Splash screen. Splash screen is majorly used in any app. But most importantly How we can make splash screen to load fast. I have seen some of app like Flip-cart,  they used this kind of splash screen.

So I thought it good to share with all of you. In earlier we used to set the layout on Activity. In  this case I found that it takes little bit time to load. In between while loading the splash It shows back background for a while of time. So I think it makes wrong impression for user to show a black background for a while.

Here is uploaded video to check how fast loading splash. Please check this.


Lets make a fast loading splash screen without setting any layout on Activity. We can achieve this by using style. We can set the style on activity Manifest.

splash_background.xml

    
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@color/colorPrimary" />

    <item>
        <bitmap android:src="@drawable/ic_stars_red_500_48dp"
            android:gravity="center" />

    </item>

</layer-list>

style.xml

    
<style name="Splash" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="android:windowBackground">@drawable/splash_background</item>
</style>

MainApplication.java

    
public class MainApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        SystemClock.sleep(1500);
    }
}

AndroidManifest.xml

    
   <activity android:name=".SplashActivity"
            android:theme="@style/Splash">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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


Thanks for reading this article. 

Tuesday, 10 January 2017

Create PDF file of current screen and share in Android

In this tutorial I am focusing about to create the pdf file of current screen. To implements this so many external library available to create the pdf file and stored in sd card. Android also provide the component to create pdf. I will gone through and found API level 19 does that.

Today in this article I will implement to create the pdf file of current screen and stored into sd card. PdfDocument class will help to create pdf .This class enables generating a PDF document from native Android content. You create a new document and then for every page you want to add you start a page, write content to the page, and finish the page. After you are done with all pages, you write the document to an output stream and close the document. After a document is closed you should not use it anymore. Note that pages are created one by one, i.e. you can have only a single page to which you are writing at any given time. This class is not thread safe.

Here is uploaded video that helps you to understand. Please check once.


Lets create an android studio project to implement this.

MainActivity.java

    
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.pdf.PdfDocument;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView mTextView;
    private Button btnCreatePdf;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView)findViewById(R.id.textview);
        btnCreatePdf = (Button)findViewById(R.id.create_pdf);
        mTextView.setText(getString(R.string.dummy_text_content));
        btnCreatePdf.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.create_pdf){

            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (ContextCompat.checkSelfPermission(this,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                    // Permission already granted
                    createPdfFle();
                } else {
                    //Request Location Permission
                    checkWritePermission();
                }
            }
            else {
                createPdfFle();
            }

        }
    }

    private void createPdfFle(){
        new Thread() {
            public void run() {
                // Get the directory for the app's private pictures directory.
                final File file = new File(Environment.getExternalStorageDirectory(), "PdfTest.pdf");

                if (file.exists ()) {
                    file.delete ();
                }

                FileOutputStream out = null;
                try {
                    out = new FileOutputStream(file);

                    PdfDocument document = new PdfDocument();
                    Point windowSize = new Point();
                    getWindowManager().getDefaultDisplay().getSize(windowSize);
                    PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(windowSize.x, windowSize.y, 1).create();
                    PdfDocument.Page page = document.startPage(pageInfo);
                    View content = getWindow().getDecorView();
                    content.draw(page.getCanvas());
                    document.finishPage(page);
                    document.writeTo(out);
                    document.close();
                    out.flush();

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "File created: "+file.getAbsolutePath(), Toast.LENGTH_LONG).show();
                        }
                    });
                } catch (Exception e) {
                    Log.d("TAG_PDF", "File was not created: "+e.getMessage());
                } finally {
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    public static final int MY_PERMISSIONS_REQUEST_WRITE = 99;
    private void checkWritePermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

                // 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("Write Storage Permission Needed")
                        .setMessage("This app needs the Write Storage permission, please accept to use to write functionality")
                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                //Prompt the user once explanation has been shown
                                ActivityCompat.requestPermissions(MainActivity.this,
                                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                        MY_PERMISSIONS_REQUEST_WRITE );
                            }
                        })
                        .create()
                        .show();


            } else {
                // No explanation needed, we can request the permission.
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        MY_PERMISSIONS_REQUEST_WRITE );
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_WRITE: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission was granted, yay! Do the
                    // location-related task you need to do.
                    if (ContextCompat.checkSelfPermission(this,
                            Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                        createPdfFle();
                    }

                } else {

                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                    Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
                }
                return;
            }
        }
    }

    private void sharePdfFile(){
        String emailAddress[] = {getString(R.string.email)}; // email: test@gmail.com

        Uri uri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "PdfTest.pdf"));
        Intent emailIntent = new Intent(Intent.ACTION_SEND);
        emailIntent.putExtra(Intent.EXTRA_EMAIL, emailAddress);
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Share Pdf");
        emailIntent.putExtra(Intent.EXTRA_TEXT, "Hi, Please get pdf");
        emailIntent.setType("application/pdf");
        emailIntent.putExtra(Intent.EXTRA_STREAM, uri);

        startActivity(Intent.createChooser(emailIntent, "Send email using:"));
    }

    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle presses on the action bar items
        switch (item.getItemId()) {
            case R.id.share_pdf:
                sharePdfFile();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

}


activity_main.xml

    
<?xml version="1.0" encoding="utf-8"?>
<ScrollView  xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:fillViewport="true"
    android:layout_height="match_parent">
<RelativeLayout
    android:id="@+id/activity_main"
    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.sunil.pdf.createpdfandroidapp.MainActivity">

   <TextView
        android:id="@+id/textview"
        android:layout_width="match_parent"
        android:layout_marginBottom="50dp"
        android:layout_height="match_parent"
        android:text="Hello World!" />

    <RelativeLayout
        android:id="@+id/button_container"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/create_pdf"
            android:text="Create PDF"
            android:textColor="#fff"
            android:background="@color/colorPrimary"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
   
    </RelativeLayout>
</RelativeLayout>
</ScrollView>

Thanks for reading this post. I hope it will help you.


Monday, 2 January 2017

Show Current location on MapBox in android

In my last article I have explained how to show current location on Google Map. If you have not seen before. I would recommend to check this post Show current location on Google Map.

In this article I am focusing about to show the current location on MapBox. MapBox is customized map into native application on multiple platforms. It makes map very style and animated as you want like.

Today in this article I am trying to integrate to show current location on map box. Here is uploaded video to show the current location on  Google Map and MapBox. Please check once.


Lets create an android project on android studio to implements to show current location on MapBox.

build.gradle app level

    
       compile ('com.mapbox.mapboxsdk:mapbox-android-sdk:4.2.1@aar'){
        transitive=true
    }

MapBoxLocationActivity.java

    
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
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.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.mapbox.mapboxsdk.MapboxAccountManager;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by sunil on 1/1/17.
 */

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

    @BindView(R.id.mapview)
    MapView mMapView;

    private GoogleApiClient mGoogleApiClient;
    private LatLng mLatLng;
    private MarkerOptions mMarker;
    private MapboxMap mMapBoxMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MapboxAccountManager.start(this, getString(R.string.access_token));
        setContentView(R.layout.activity_mapbox_location);
        ButterKnife.bind(this);

        setsupActionBar();

        mMapView.onCreate(savedInstanceState);
        mMapView.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(MapboxMap mapboxMap) {
                mMapBoxMap = mapboxMap;
                if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if (ContextCompat.checkSelfPermission(MapBoxLocationActivity.this,
                            Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                        //Location Permission already granted
                        buildGoogleApiClient();
                    } else {
                        //Request Location Permission
                        checkLocationPermission();
                    }
                }
                else {
                    buildGoogleApiClient();
                }
            }
        });
    }


    // Add the mapView lifecycle to the activity's lifecycle methods
    @Override
    public void onResume() {
        super.onResume();
        mMapView.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        mMapView.onPause();
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mMapView.onLowMemory();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mMapView.onDestroy();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mMapView.onSaveInstanceState(outState);
    }



    private void setsupActionBar() {
        ActionBar actionBar = getSupportActionBar();
        actionBar.setDisplayShowHomeEnabled(true);
        getSupportActionBar().setHomeAsUpIndicator(getResources().getDrawable(R.drawable.navigate_back));
    }

    private synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }

    private LocationRequest createLocationRequest() {
        LocationRequest mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10000);
        mLocationRequest.setFastestInterval(5000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        return mLocationRequest;
    }


    private void updateCamera() {
        mMapView.setCameraDistance(10);
        CameraPosition position = new CameraPosition.Builder()
                .target(mLatLng) // Sets the new camera position
                .zoom(15) // Sets the zoom
                .bearing(180) // Rotate the camera
                .tilt(30) // Set the camera tilt
                .build(); // Creates a CameraPosition from the builder

        mMapBoxMap.animateCamera(CameraUpdateFactory
                .newCameraPosition(position), 7000);
    }

    private void updateMarker() {
        mMapBoxMap.clear();
        mMarker = new MarkerOptions()
                .position(mLatLng)
                .title("Location")
                .snippet("Welcome to you");
        mMapBoxMap.addMarker(mMarker);
    }

    private void addMarker() {
        mMarker = new MarkerOptions()
                .position(mLatLng)
                .title("Location")
                .snippet("Welcome to you");
        mMapBoxMap.addMarker(mMarker);
    }


    @Override
    public void onConnected(@Nullable Bundle bundle) {
        LocationRequest mLocationRequest = createLocationRequest();
        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 onLocationChanged(Location location) {
        mLatLng = new LatLng(location.getLatitude(), location.getLongitude());
        updateCamera();
        if (mMarker != null) {
            updateMarker();
        }else{
            addMarker();
        }
    }

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

    }


    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(MapBoxLocationActivity.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) {

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

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

    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle presses on the action bar items
        switch (item.getItemId()) {
            case R.id.share_locations:

                Intent i = new Intent(android.content.Intent.ACTION_SEND);
                String location = mLatLng.getLatitude()+ "," + mLatLng.getLongitude();
                i.setType("text/plain");
                i.putExtra(Intent.EXTRA_SUBJECT, "Current Location");
                i.putExtra(Intent.EXTRA_TEXT, " http://maps.google.com/maps?q=loc:" + location);

                try {
                    startActivity(Intent.createChooser(i, "Share Location"));
                } catch (android.content.ActivityNotFoundException ex) {
                    Toast.makeText(this, "Not found any app", Toast.LENGTH_LONG).show();
                }
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
}

activity_mapbox_location.xml

    
<?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"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.mapbox.mapboxsdk.maps.MapView
        android:id="@+id/mapview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

AndroidManifest.xml

    
    <uses-permission android:name="android.permission.INTERNET">
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION">
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE">

add this line inside the application tag in manifest file.It will handle the marshmallow permission.
    
   <service android:name="com.mapbox.mapboxsdk.telemetry.TelemetryService" />


Thanks for reading this post. I hope it helps you to understand.

Sunday, 1 January 2017

Show current Location on Google Map in android

Google Map is very strong and powerful to show map in world wide. It is majorly used in the app for showing anything near by you.  In this article I am focusing about the to show the current location of the user on Google Map. And if the user want to share his/her current location then they can share with any fiends with any installed app.

So Lets focus on how to integrate the google map in android studio project. First of all you need to go to Google Console to get the API key.  API key for debug purpose you can get the debug key but at the time of app launch you need to get the release key with any SHA1 finger print. Then need to enable the Google map v2 for android feature. Add your API key in AndroidManifest File.

For the current location We can used the Fused location by Google API client. It is very fast and give accurate result. Here is uploaded video that helps to before used source code. Please check it once.



Lets create android project to show the current location on Google Map.

build.gradle app level

    
      compile 'com.google.android.gms:play-services-maps:9.8.0'
      compile 'com.google.android.gms:play-services-location:9.8.0'
      compile "com.jakewharton:butterknife:8.1.0"
      apt 'com.jakewharton:butterknife-compiler:8.0.1'


GoogleMapLocationActivity.java

    
mport android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
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.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;


import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
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.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by sunil on 12/31/16.
 */

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

    MapFragment mapFragment;

    private GoogleApiClient mGoogleApiClient;
    private GoogleMap mGoogleMap;
    private boolean mRequestingLocationUpdates = false;
    private LatLng mLatLng;
    private PolylineOptions mPolylineOptions;
    private Marker mCurrLocationMarker;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_googlemap_location);
        ButterKnife.bind(this);

        mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
        setsupActionBar();


    }


    @Override
    public void onPause() {
        super.onPause();
        //stop location updates when Activity is no longer active
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
    }


    private void setsupActionBar() {
        ActionBar actionBar = getSupportActionBar();
        actionBar.setDisplayShowHomeEnabled(true);
        getSupportActionBar().setHomeAsUpIndicator(getResources().getDrawable(R.drawable.navigate_back));
    }

    private synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        LocationRequest mLocationRequest = createLocationRequest();
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
            initializePolyline();
        }
    }


    @Override
    public void onConnectionSuspended(int i) {

    }

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

    }


    private LocationRequest createLocationRequest() {
        LocationRequest mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10000);
        mLocationRequest.setFastestInterval(5000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        return mLocationRequest;
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mGoogleMap = googleMap;
        //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);
        }


    }

    @Override
    public void onLocationChanged(Location location) {
        mLatLng = new LatLng(location.getLatitude(), location.getLongitude());
        updateCamera();
        addMarker(mLatLng);
    }

    private void updateCamera() {
        mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mLatLng, 16));
        updatePolyline();
    }

    private void initializePolyline() {
        mGoogleMap.clear();
        mPolylineOptions = new PolylineOptions();
        mPolylineOptions.color(Color.BLUE).width(10);
        mGoogleMap.addPolyline(mPolylineOptions);

    }

    private void updatePolyline() {
        mPolylineOptions.add(mLatLng);
        mGoogleMap.clear();
        mGoogleMap.addPolyline(mPolylineOptions);
    }
    private void addMarker(LatLng latLng){
        if (mCurrLocationMarker != null) {
            mCurrLocationMarker.remove();
        }
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
        markerOptions.title("Current Position");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
        mCurrLocationMarker = mGoogleMap.addMarker(markerOptions);

    }


    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle presses on the action bar items
        switch (item.getItemId()) {
            case R.id.share_locations:

                Intent i = new Intent(android.content.Intent.ACTION_SEND);
                String location = mLatLng.latitude + "," + mLatLng.longitude;
                i.setType("text/plain");
                i.putExtra(Intent.EXTRA_SUBJECT, "Current Location");
                i.putExtra(Intent.EXTRA_TEXT, " http://maps.google.com/maps?q=loc:" + location);

                try {
                    startActivity(Intent.createChooser(i, "Share Location"));
                } catch (android.content.ActivityNotFoundException ex) {
                    Toast.makeText(this, "Not found any app", Toast.LENGTH_LONG).show();
                }

                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    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(GoogleMapLocationActivity.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) {

                    // 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_googlemap_location.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
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="com.google.android.gms.maps.MapFragment"/>

</LinearLayout>



Thanks for reading this post. I hope this will help to you understand.

Sunday, 25 December 2016

Retrofit 2.1 with RxAndroid

Retrofit is very known library to handle the network operation in Android. It is very powerful library to work with network related API call. It used OkHttp request in networking operation.

Earlier we used Async Task was having some drawback that retrofit has covered all. Here are the some drawback points in async Task.

1. Handling multiple request.
2. Cacheing data
3. Error handling

These all taking cared in Retrofit. But if talk about RxAndroid (Reactive Android) which works on based on Observable and Subscription. It makes our life very easy and make Retrofit very powerful if we used together. Rx Team and Retrofit team are doing a great job together.  Rx Java is ocean to work with Java that will not enough one day to understand. But day by day It attracting the Android developers that works very pathetic way with Android. Thats why It will be going used many and more places in the upcoming feature.

Thanks to both team to makes our life easy and networking operation makes more easy and stable to used this to make awesome apps.

Here is uploaded video that gives to understand to retrofit api call in android. Please check once to view before source code.

Lets create an android project to implement this.

build.gradle app level

    
     compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'io.reactivex:rxandroid:1.2.0'
    compile 'io.reactivex:rxjava:1.1.8'
    compile "com.jakewharton:butterknife:8.1.0"
    apt 'com.jakewharton:butterknife-compiler:8.0.1'
    compile 'org.greenrobot:eventbus:3.0.0'
    compile "com.android.support:recyclerview-v7:24.2.0"
    compile "com.android.support:cardview-v7:24.2.0"

APIService.java

    
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.sunil.rxjavaretrofitandroid.Friends;

import java.security.cert.CertificateException;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import rx.Observable;

/**
 * Created by sunil on 12/25/16.
 */

public interface APIService {

    static final String BASE_URL = "https://demo4532688.mockable.io/";

    @GET("getmyfriends")
    Observable getMyFriends();

    class Creator {

        private static OkHttpClient okHttpClient1 = getUnsafeOkHttpClient();

        public static APIService newApiClient() {

            Gson gson = new GsonBuilder()
                    .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
                    .create();
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(okHttpClient1)
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
            return retrofit.create(APIService.class);
        }

        private static OkHttpClient getUnsafeOkHttpClient() {
            try {
                // Create a trust manager that does not validate certificate chains
                final TrustManager[] trustAllCerts = new TrustManager[]{
                        new X509TrustManager() {
                            @Override
                            public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                            }

                            @Override
                            public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                            }

                            @Override
                            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                                return new java.security.cert.X509Certificate[]{};
                            }
                        }
                };

                // Install the all-trusting trust manager
                final SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
                // Create an ssl socket factory with our all-trusting manager
                final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
                OkHttpClient.Builder builder = new OkHttpClient.Builder();
//                builder.addInterceptor(logging);

                builder.sslSocketFactory(sslSocketFactory);
                builder.hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });

                OkHttpClient okHttpClient = builder.
                        connectTimeout(60, TimeUnit.SECONDS)
                        .readTimeout(60, TimeUnit.SECONDS)
                        .writeTimeout(60, TimeUnit.SECONDS)
                        .addInterceptor(new MyOkHttpInterceptor()).build();
                return okHttpClient;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

MyOkHttpInterceptor.java

    
import android.util.Log;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;

/**
 * Created by sunil on 12/25/16.
 */

public class MyOkHttpInterceptor implements Interceptor {
    private final String TAG = MyOkHttpInterceptor.class.getSimpleName();
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        String body = "NA";
        if(chain.request().body()!=null){
            body =  bodyToString(chain.request().body());
        }

        String myString = request.url() + " ->" + request.headers().toString()+"\n Params  --->"+body+"\n";

        Log.d(TAG, myString);
        return chain.proceed(request);
    }

    private  String bodyToString(final RequestBody request){
        try {
            final RequestBody copy = request;
            final Buffer buffer = new Buffer();
            copy.writeTo(buffer);
            return buffer.readUtf8();
        }
        catch (final IOException e) {
            return "did not work";
        }
    }

}

APIManager.java

    
import android.content.Context;
import com.sunil.rxjavaretrofitandroid.Friends;
import com.sunil.rxjavaretrofitandroid.event.FriendsEvent;
import org.greenrobot.eventbus.EventBus;
import java.io.IOException;
import retrofit2.adapter.rxjava.HttpException;
import rx.Observable;
import rx.Observer;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * Created by kuliza-195 on 12/25/16.
 */

public class APIManager {

    private APIService mAPIService;

    public APIManager(Context context) {
        mAPIService = getAPIServiceEndPoint();

    }

    public APIService getAPIServiceEndPoint() {
        if (mAPIService == null) {
            mAPIService = APIService.Creator.newApiClient();
        }
        return mAPIService;
    }


    public void getFriends() {

        Observable friendResponseObservable = mAPIService.getMyFriends()
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread());

        friendResponseObservable.subscribe(new Observer() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                //handle error
                if (e instanceof HttpException) {
                    // We had non-2XX http error
                }
                if (e instanceof IOException) {
                    // A network or conversion error happened
                }

                // We don't know what happened. We need to simply convert to an unknown error
            }

            @Override
            public void onNext(Friends response) {
                //handle response
                EventBus.getDefault().post(new FriendsEvent(response));
            }
        });


    }

}

MainActivity.java

    
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.sunil.rxjavaretrofitandroid.adapter.FriendsAdapter;
import com.sunil.rxjavaretrofitandroid.api.APIManager;
import com.sunil.rxjavaretrofitandroid.event.FriendsEvent;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;

import butterknife.BindView;
import butterknife.ButterKnife;
import rx.Subscription;

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.recyclerView1)
    RecyclerView mRecyclerView;
    @BindView(R.id.progressbar)
    ProgressBar progressbar;

    private APIManager mAPIManager;
    private Subscription mSubscription;

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

        setActionBarWithBackButton();

        progressbar.setVisibility(View.GONE);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mAPIManager = new APIManager(this);

        loadFriends();
    }

    protected void setActionBarWithBackButton() {
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeAsUpIndicator(getResources().getDrawable(R.drawable.navigate_back));
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
        }

    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mSubscription != null)
            mSubscription.unsubscribe();
        EventBus.getDefault().unregister(this);
    }

    public void loadFriends() {
        // use loader
        progressbar.setVisibility(View.VISIBLE);
        mAPIManager.getFriends();
    }

    @Subscribe
    public void OnEvent(FriendsEvent response) {
        // cancel loader
        progressbar.setVisibility(View.GONE);
        if (response.getFriends() != null) {
            if (response.getFriends().getUser().size() < 1) {
                Toast.makeText(this, "No Data available", Toast.LENGTH_LONG).show();
            } else {
                showFriends(response.getFriends());
            }
        }
    }

    public void showFriends(Friends friends) {
        FriendsAdapter adapter = new FriendsAdapter(friends.getUser());
        mRecyclerView.setAdapter(adapter);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                break;
        }
        return true;
    }
}


activity_main.xml

    
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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: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.sunil.rxjavaretrofitandroid.MainActivity">


    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </android.support.v7.widget.RecyclerView>

    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

FriendsAdapter.java

    
    public class FriendsAdapter  extends RecyclerView.Adapter{

    private List mListFriends;

    public FriendsAdapter(List friendsList){
        mListFriends = friendsList;
    }

    @Override
    public FriendsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_friends, parent, false);
        return new FriendsViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(FriendsViewHolder holder, int position) {
        Friends.User friends = mListFriends.get(position);
        holder.nameTextView.setText(friends.getName());
        holder.emailTextView.setText(friends.getEmail());
    }

    @Override
    public int getItemCount() {
        return mListFriends.size();
    }

    class FriendsViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.name)
        TextView nameTextView;
        @BindView(R.id.email)
        TextView emailTextView;

        public FriendsViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}

Thanks for reading this post. I hope it will help you. Please give your valuable comment below.

Friday, 23 December 2016

NavigationView Drawer Expandable menu Item in ANdroid


NavigationView Drawer is very common used today building any app. It provides to show Menu with navigation feature. NavigationView introduces in design support library to gives better navigation for users.  IN many of app you have seen with custom view on top of header view that contain the user information and below on header with menu items listed. Users can select any item to navigate view accordingly.

In this article I am focusing something different for navigation view without menu item. Most of the app that can see they used expandable menu with submenu. User can expand menu items and click on submenu items to navigate view. If you want to show app version information in footer, then you can add with footer in NavigationView.

Here is uploaded video that helps to understand what I am talking. Please this video.


Lets create an android project to implements this feature.

build.gradle app level

    
    compile 'com.android.support:recyclerview-v7:25.0.0'
    compile 'com.android.support:cardview-v7:25.0.0'
    compile 'com.android.support:design:25.0.0'
    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'
    compile 'com.thoughtbot:expandablerecyclerview:1.0'
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'de.hdodenhof:circleimageview:2.0.0'

MainActivity.java

    
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.widget.FrameLayout;

import java.util.ArrayList;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity implements RecyclerAdapter.ItemClickChild{

    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;
    @BindView(R.id.nav_view)
    NavigationView navView;
    @BindView(R.id.drawer_layout)
    DrawerLayout drawerLayout;

    String names[] = Constant.name;
    String subNames[] = Constant.subName;

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

    @BindView(R.id.frame)
    FrameLayout frame;

    TitleFragment fragment;


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

        setSupportActionBar(toolbar);
        final ActionBar actionar = getSupportActionBar();
        actionar.setDisplayHomeAsUpEnabled(true);
        actionar.setHomeAsUpIndicator(R.drawable.ic_menu);

        List list = getList();
        RecyclerAdapter adapter = new RecyclerAdapter(this, list, this);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
        recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
        recyclerView.setAdapter(adapter);

        setFragment();
    }

    private void setFragment() {
        fragment = new TitleFragment();
        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.frame, fragment, "TitleFragment").commit();
    }

    private List getList() {
        List list = new ArrayList<>();
        for (int i = 0; i < names.length; i++) {
            List subTitles = new ArrayList<>();
            for (int j = 0; j < subNames.length; j++) {
                SubTitle subTitle = new SubTitle(subNames[j]);
                subTitles.add(subTitle);
            }
            TitleMenu model = new TitleMenu(names[i], subTitles, null);
            list.add(model);
        }
        return list;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            drawerLayout.openDrawer(GravityCompat.START);
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onChildClick(int position) {
        String name = subNames[position];
        drawerLayout.closeDrawers();
        fragment.setTitle(name);
    }
}

activity_main.xml

    
     <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:fitsSystemWindows="true">

   <include layout="@layout/layout_toolabr"
        android:id="@+id/toolbar_container"/>

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

   <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:layout_gravity="start"
        android:fitsSystemWindows="true">

         <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

             <include layout="@layout/nav_header"
                android:id="@+id/header"/>

          <android.support.v7.widget.RecyclerView
                android:layout_below="@+id/header"
                android:id="@+id/recyclerView"
                android:layout_marginBottom="25dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
             </android.support.v7.widget.RecyclerView>

      </RelativeLayout>

       <TextView
            android:padding="5dp"
            android:id="@+id/footer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="copyright @ sunil gupta"
            android:gravity="center"
            android:textColor="@color/red_icon_color"
            android:layout_gravity="bottom"/>

   </android.support.design.widget.NavigationView>
 </android.support.v4.widget.DrawerLayout>

RecyclerAdapter.java

    
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.thoughtbot.expandablerecyclerview.ExpandableRecyclerViewAdapter;
import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;

import java.util.List;

/**
 * Created by sunil on 12/23/16.
 */

public class RecyclerAdapter extends ExpandableRecyclerViewAdapter {

    private Context context;
    private ItemClickChild mListener;
    public RecyclerAdapter(Context context, List groups, Activity activity) {
        super(groups);
        this.context = context;
        mListener = (ItemClickChild) activity;
    }

    @Override
    public TitleViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item_title, parent, false);
        return new TitleViewHolder(view);
    }

    @Override
    public SubTitleViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_subtitle, parent, false);
        return new SubTitleViewHolder(view);
    }

    @Override
    public void onBindChildViewHolder(SubTitleViewHolder holder, int flatPosition,
                                      ExpandableGroup group, final int childIndex) {

        final SubTitle subTitle = ((TitleMenu) group).getItems().get(childIndex);
        holder.setSubTitletName(subTitle.getName());
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mListener.onChildClick(childIndex);
            }
        });
    }

    @Override
    public void onBindGroupViewHolder(TitleViewHolder holder, int flatPosition, ExpandableGroup group) {
        holder.setGenreTitle(context, group);
    }

    public interface ItemClickChild{
        void onChildClick(int position);
    }
}

TitleFragment.java

    
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.graphics.ColorUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by sunil on 12/24/16.
 */

public class TitleFragment extends Fragment {

    View rootView;

    @BindView(R.id.title_name)
    TextView titleName;

    @BindView(R.id.main_content)
    LinearLayout mainContent;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_title, container, false);
        ButterKnife.bind(this, rootView);
        return rootView;
    }

    public void setTitle(String title) {
        titleName.setText(title);
        if (title.equalsIgnoreCase("google")){
            mainContent.setBackgroundColor(getResources().getColor(R.color.red_icon_color));
        } else if (title.equalsIgnoreCase("Motorola")){
            mainContent.setBackgroundColor(getResources().getColor(R.color.green_icon_color));
        } else if (title.equalsIgnoreCase("Samsung")){
            mainContent.setBackgroundColor(getResources().getColor(R.color.yellow_icon_color));
        } else if (title.equalsIgnoreCase("Lenevo")){
            mainContent.setBackgroundColor(getResources().getColor(R.color.blue_icon_color));
        }

    }
}

fragment_title.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"
    android:id="@+id/main_content"
    android:gravity="center">

  <TextView
        android:gravity="center"
        android:text="Title"
        android:textStyle="bold"
        android:id="@+id/title_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

 </LinearLayout>

Thanks for reading this post. I hope it will help you.