Download image and save it to sdcard(phone storage) without any library in Android

In this post, we are going to download image from server to your phone’s local storage. Here we are not using any third party library but use “HttpURLConnection” from java.net package. So let’s get started.

download and save image sdcard without library
download and save image sdcard without library

First we will create progress dialog to display the progress of image being downloaded. In this dialog we will show percentage and total as well as remaining size of the image being downloaded, so the user will get the idea of how much time remaining and how big is the image.

So here is the code for the ProgressDialog.

ProgressDialog pd = new ProgressDialog(DownloadImageActivity.this);
pd.setMessage("Downloading image, please wait ...");
pd.setIndeterminate(true);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setCancelable(false);
pd.setProgressNumberFormat("%1d KB/%2d KB");

Here first we set the message “Downloading image, please wait …”, then we set the indeterminate flag to true because we do not know the size of the image at first. Then comes the progress style, it will be ProgressDialog.STYLE_HORIZONTAL. It will display the horizontal progress bar. The we set the cancelable flag to false so that user can not cancel the dialog while image is downloading. Then we set the progress number format, which will display the total size of the image and remaining size of the image. Here we display the data in kilobyte(KB) so we use the format “%1d KB/%2d KB”.

Now we will create the AsyncTask which will download the image. Here we use HttpURLConnection which is from java.net package and does not require any third party library to download image.

private class DownloadImage extends AsyncTask<String, Integer, String> {

  private Context c;

  private DownloadImage(Context c) {
    this.c = c;
  }

  @Override
  protected String doInBackground(String... sUrl) {
    InputStream is = null;
    OutputStream os = null;
    HttpURLConnection con = null;
    int length;
    try {
      URL url = new URL(sUrl[0]);
      con = (HttpURLConnection) url.openConnection();
      con.connect();

      if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
        return "HTTP CODE: " + con.getResponseCode() + " " + con.getResponseMessage();
      }

      length = con.getContentLength();

      pd.setMax(length / (1000));

      is = con.getInputStream();
      os = new FileOutputStream(Environment.getExternalStorageDirectory() + File.separator + "a-computer-engineer.jpg");

      byte data[] = new byte[4096];
      long total = 0;
      int count;
      while ((count = is.read(data)) != -1) {
        if (isCancelled()) {
          is.close();
          return null;
        }
        total += count;
        if (length > 0) {
          publishProgress((int) total);
        }
        os.write(data, 0, count);
      }
    } catch (Exception e) {
      return e.toString();
    } finally {
      try {
        if (os != null)
          os.close();
        if (is != null)
          is.close();
      } catch (IOException ioe) {
      }

      if (con != null)
        con.disconnect();
    }
    return null;
  }

  @Override
  protected void onPreExecute() {
    super.onPreExecute();
    pd.show();
  }

  @Override
  protected void onProgressUpdate(Integer... progress) {
    super.onProgressUpdate(progress);
    pd.setIndeterminate(false);
    pd.setProgress(progress[0] / 1000);
  }

  @Override
  protected void onPostExecute(String result) {
    pd.dismiss();
    if (result != null) {
      Toast.makeText(c, "Download error: " + result, Toast.LENGTH_LONG).show();
    } else {
      Toast.makeText(c, "Image downloaded successfully!", Toast.LENGTH_SHORT).show();
      Bitmap b = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory() + File.separator + "a-computer-engineer.jpg");
      iv.setImageBitmap(b);
    }
  }
}

Here we open the connection of the image url and then get the input stream and content length of the image. Then we create file on our device’s storage and then write the data to its output stream. Here we also calculate how much image is downloaded and how much is remaining and update the same in the progress dialog.

We use “publishProgress” in doInBackground that invokes the method “onProgressUpdate” with the progress value and in that method we will update the progress dialog. Here we get the content length of the image using “getContentLength()” method of HttpURLConnection class which provides data in bytes. Then we divide it with 1000 to get the image size in KB. And then we start reading the data from input stream and put a counter to calculate how much data is downloaded and update it in the UI.

At the end we displayed the toast with the success message. Please make sure that you have gain the storage permission before executing the above AsyncTask.

Here is the full code for above functionality.

public class DownloadImageActivity extends AppCompatActivity {

  private ProgressDialog pd;
  private ImageView iv;

  private DownloadImage di;

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

    iv = findViewById(R.id.iv);

    pd = new ProgressDialog(DownloadImageActivity.this);
    pd.setMessage("Downloading image, please wait ...");
    pd.setIndeterminate(true);
    pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    pd.setCancelable(false);
    pd.setProgressNumberFormat("%1d KB/%2d KB");

    di = new DownloadImage(DownloadImageActivity.this);
    di.execute("https://images.unsplash.com/photo-1536998533868-95cde0d71742?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=69a455127db97a5cc05e2d3c9c9ef245&auto=format&fit=crop&w=4000&q=80");

    pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
      @Override
      public void onCancel(DialogInterface dialog) {
        di.cancel(true);
      }
    });
  }

  private class DownloadImage extends AsyncTask<String, Integer, String> {

    private Context c;

    private DownloadImage(Context c) {
      this.c = c;
    }

    @Override
    protected String doInBackground(String... sUrl) {
      InputStream is = null;
      OutputStream os = null;
      HttpURLConnection con = null;
      int length;
      try {
        URL url = new URL(sUrl[0]);
        con = (HttpURLConnection) url.openConnection();
        con.connect();

        if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
          return "HTTP CODE: " + con.getResponseCode() + " " + con.getResponseMessage();
        }

        length = con.getContentLength();

        pd.setMax(length / (1000));

        is = con.getInputStream();
        os = new FileOutputStream(Environment.getExternalStorageDirectory() + File.separator + "a-computer-engineer.jpg");

        byte data[] = new byte[4096];
        long total = 0;
        int count;
        while ((count = is.read(data)) != -1) {
          if (isCancelled()) {
            is.close();
            return null;
          }
          total += count;
          if (length > 0) {
            publishProgress((int) total);
          }
          os.write(data, 0, count);
        }
      } catch (Exception e) {
        return e.toString();
      } finally {
        try {
          if (os != null)
            os.close();
          if (is != null)
            is.close();
        } catch (IOException ioe) {
        }

        if (con != null)
          con.disconnect();
      }
      return null;
    }

    @Override
    protected void onPreExecute() {
      super.onPreExecute();
      pd.show();
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
      super.onProgressUpdate(progress);
      pd.setIndeterminate(false);
      pd.setProgress(progress[0] / 1000);
    }

    @Override
    protected void onPostExecute(String result) {
      pd.dismiss();
      if (result != null) {
        Toast.makeText(c, "Download error: " + result, Toast.LENGTH_LONG).show();
      } else {
        Toast.makeText(c, "Image downloaded successfully!", Toast.LENGTH_SHORT).show();
        Bitmap b = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory() + File.separator + "a-computer-engineer.jpg");
        iv.setImageBitmap(b);
      }
    }
  }
}

If you find any problem or doubt, please mention in comments. Do not forget to share!

Download Source Code: https://github.com/dakshbhatt21/a-computer-engineer

Advertisements

Create PDF and save to the sdcard in Android

Create PDF file and save it to sdcard in Android
Create PDF file and save it to sdcard in Android

In this article, we will create PDF file of the current view and then save it to the sdcard(internal storage) as pdf file. Here we use PdfDocument (https://developer.android.com/reference/android/graphics/pdf/PdfDocument) which added from API 19(Android KitKat). So you can use it above KitKat version of Android.

First of all we will create Bitmap of the view which we want to save on the PDF file. So for that we need to get the heigh and width of the view, so here we do all the operation in the ‘onWindowFocusChanged’ method instead of ‘onCreate’ method. So the basic structure of the file will look like this.

private RelativeLayout rlContainer;

private int width, height;

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

  rlContainer = findViewById(R.id.rl_container);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
  super.onWindowFocusChanged(hasFocus);

  width = rlContainer.getWidth();
  height = rlContainer.getHeight();
}

Here we have on RelativeLayout which contains all the elements we need to print on the PDF file. So we will initialise it in onCreate and then get its width and height in onWindowFocusChanged. If you try to get the width and height in onCreate, it will be 0 because at that time the view did not rendered on the screen. So we will use the above method for that.

Now we will create a Bitmap of that relative layout using following code. Later we will draw this Bitmap on PDF file using Canvas of the PDF file.

Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c1 = new Canvas(b);
rlContainer.draw(c1);

Now we initialise PdfDocument and create pages in that PDF file. For that we use PdfDocument.Page class. If we have 5 pages in our PDF file then we have to create 5 object of PdfDocument.Page and add them to PdfDocument. Then we fetch the canvas of the PDF page and draw our Bitmap on it. Please check the code below.

PdfDocument pd = new PdfDocument();

PdfDocument.PageInfo pi = new PdfDocument.PageInfo.Builder(width, height, 1).create();
PdfDocument.Page p = pd.startPage(pi);
Canvas c = p.getCanvas();
c.drawBitmap(b, 0, 0, new Paint());
pd.finishPage(p);

pd.close();

Here we can iterate the code from line 3 to line 7 to add more pages to the PDF files. After that we need to close the PdfDocument. This will draw our bitmap to the PDF file. Now to write this PdfDocument to the file on sdcard(internal storage), we need to create a File and write PdfDocument to its OutputStream. But make sure that you write this code before closing the PdfDocument pd.close(). Here is the code for that.

try {
  //make sure you have asked for storage permission before this
  File f = new File(Environment.getExternalStorageDirectory() + File.separator + "a-computer-engineer-pdf-test.pdf");
  pd.writeTo(new FileOutputStream(f));
} catch (FileNotFoundException fnfe) {
  fnfe.printStackTrace();
} catch (IOException ioe) {
  ioe.printStackTrace();
}

pd.close();

Please make sure that before running above code, you have the storage permission granted by user otherwise you will get error. Please check for the runtime Android permission for that. Now your PDF file is saved at your provided location on your sdcard(internal storage).

Here is the full code.

private RelativeLayout rlContainer;

private int width, height;

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

  rlContainer = findViewById(R.id.rl_container);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
  super.onWindowFocusChanged(hasFocus);

  width = rlContainer.getWidth();
  height = rlContainer.getHeight();

  Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
  Canvas c1 = new Canvas(b);
  rlContainer.draw(c1);

  PdfDocument pd = new PdfDocument();

  PdfDocument.PageInfo pi = new PdfDocument.PageInfo.Builder(width, height, 1).create();
  PdfDocument.Page p = pd.startPage(pi);
  Canvas c = p.getCanvas();
  c.drawBitmap(b, 0, 0, new Paint());
  pd.finishPage(p);

  try {
    //make sure you have asked for storage permission before this
    File f = new File(Environment.getExternalStorageDirectory() + File.separator + "a-computer-engineer-pdf-test.pdf");
    pd.writeTo(new FileOutputStream(f));
  } catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
  } catch (IOException ioe) {
    ioe.printStackTrace();
  }

  pd.close();
}

If you find any problem or doubt, please mention in comments. Do not forget to share!

Download Source Code: https://github.com/dakshbhatt21/a-computer-engineer

Draw line using finger on Canvas in Android

Draw line on canvas using finger
Draw line on canvas using finger

Draw line on canvas using your finger is very much important task if you are going to develop any kind of drawing app or image editing app. So in this tutorial we are going to see how one can draw on canvas using touch methods.

(Those who want to just copy paste the whole class can scroll at the end!)

First of all we create a custom view which contains the canvas and all its touch methods which performs the draw activity.

This is the class which we are going to use in XML layout. You can use it in XML like this . Here we are going to add all the initialization in the second constructor as we are going to use it in the XML file. But it is advisable if you use a common method and add it to every constructor.

public class DrawLineCanvas extends View {

  public DrawLineCanvas(Context context) {
    super(context);
  }

  public DrawLineCanvas(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public DrawLineCanvas(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

}

Now we add few methods in the above class, each method has different purpose of its own.

This method will give us the width and height of the view that is inflated. So if we give “match_parent” in the XML file then we can get the full width and height of the view and create bitmap and canvas of that size so that we can draw on whole visible area of the screen except toolbar and status bar.

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
}

Now this method will identify the touch event and draw on the bitmap accordingly. We consider three different events here. One is when user touch the screen, second when the user move his/her finger on the screen and the last one when the user lift the finger from the screen.

@Override
public boolean onTouchEvent(MotionEvent event) {

  switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      break;
    case MotionEvent.ACTION_MOVE:
      break;
    case MotionEvent.ACTION_UP:
      break;
    default:
      return false;
  }

  invalidate();
  return true;
}

Here “invalidate()” calls the below method so it will draw on the canvas.

The below method will draw the path(which we drew using finger) on the canvas. We will call this method every time we touch or drag finger on the screen.

@Override
protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
}

Now we initialise all the needed things to get started.

private Canvas c;

private Paint pLine, pBg;
private Path touchPath;

private Bitmap b;

public DrawLineCanvas(Context context, AttributeSet attrs) {
  super(context, attrs);

  pBg = new Paint();
  pBg.setColor(Color.WHITE);

  pLine = new Paint();
  pLine.setColor(Color.GREEN);
  pLine.setAntiAlias(true);
  pLine.setStyle(Paint.Style.STROKE);
  pLine.setStrokeWidth(12);

  touchPath = new Path();
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  c = new Canvas(b);
}

Here Canvas is used to save the drawing when we lift the finger and started drawing again. Paint is for line that is being drawn and the background on which the line is being drawn. It includes the line size, color, stroke, etc. Path is for saving the path that we create by moving our finger on the screen. So when we lift the finger we will draw this path to our canvas and it will be drawn on the screen. And lastly the Bitmap is used to initialise our canvas with the size we are getting from the view inflated in the XML using method onSizeChanged().

Now comes the drawing part, now we will identify the touch event and save it to the “touchPath” we initialised so that we can draw it to the canvas once we lift the finger. On every action event, we also calls the “invalidate()” method so that your current moving path will be drawn on the canvas.

@Override
public boolean onTouchEvent(MotionEvent event) {

  float touchX = event.getX();
  float touchY = event.getY();
  switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      touchPath.moveTo(touchX, touchY);
      break;
    case MotionEvent.ACTION_MOVE:
      touchPath.lineTo(touchX, touchY);
      break;
    case MotionEvent.ACTION_UP:
      touchPath.lineTo(touchX, touchY);
      c.drawPath(touchPath, pLine);
      touchPath = new Path();
      break;
    default:
      return false;
  }

  invalidate();
  return true;
}

Here in “ACTION_UP” event we draw the path “touchPath” to the Canvas c and reset the path so you can start new line when you again start drawing something.

Now finally the “onDraw()” method which will draw everything on canvas and you can see your drawing on screen!

@Override
protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);

  canvas.drawBitmap(b, 0, 0, pBg);
  canvas.drawPath(touchPath, pLine);
}

The complete class looks like this.

public class DrawLineCanvas extends View {

  private Canvas c;

  private Paint pLine, pBg;
  private Path touchPath;

  private Bitmap b;

  public DrawLineCanvas(Context context) {
    super(context);
  }

  public DrawLineCanvas(Context context, AttributeSet attrs) {
    super(context, attrs);

    pBg = new Paint();
    pBg.setColor(Color.WHITE);

    pLine = new Paint();
    pLine.setColor(Color.GREEN);
    pLine.setAntiAlias(true);
    pLine.setStyle(Paint.Style.STROKE);
    pLine.setStrokeWidth(12);

    touchPath = new Path();
  }

  public DrawLineCanvas(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    c = new Canvas(b);
  }
  
  @Override
  public boolean onTouchEvent(MotionEvent event) {

    float touchX = event.getX();
    float touchY = event.getY();
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
        touchPath.moveTo(touchX, touchY);
        break;
      case MotionEvent.ACTION_MOVE:
        touchPath.lineTo(touchX, touchY);
        break;
      case MotionEvent.ACTION_UP:
        touchPath.lineTo(touchX, touchY);
        c.drawPath(touchPath, pLine);
        touchPath = new Path();
        break;
      default:
        return false;
    }

    invalidate();
    return true;
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.drawBitmap(b, 0, 0, pBg);
    canvas.drawPath(touchPath, pLine);
  }
}

To save this canvas as image on your sdcard, please check my other post here: https://acomputerengineer.wordpress.com/2015/01/13/how-to-draw-canvas-on-imageview-and-save-canvas-as-bitmap-and-store-in-sdcard-in-android/

For source code, please checkout my Github repo here: https://github.com/dakshbhatt21/a-computer-engineer

Display List in AlertDialog in Android(Simple List, Radio Button List, Check Box List)

You don’t need to create custom view to display list in your AlertDialog. AlertDialog has the ability to display different kind of lists itself. Here we will see the 3 different types of methods to display the list in AlertDialog.

1. Simple List
Here we will display simple list in the AlertDialog. Here we need to provide the array of String to the AlertDialog and that’s it, it will handle the rest. We can also add Ok/Cancel button to the list but we won’t need it in the simple list.
We can use this list dialog in place of dropdown list(spinner).

First we declare the String array and then we create the AlertDialog.

String[] listItems = {"one", "two", "three", "four", "five"};

AlertDialog.Builder builder = new AlertDialog.Builder(ListAlertDialogActivity.this);
builder.setTitle("Choose item");

builder.setItems(listItems, new DialogInterface.OnClickListener() {
  @Override
  public void onClick(DialogInterface dialog, int which) {
    Toast.makeText(ListAlertDialogActivity.this, "Position: " + which + " Value: " + listItems[which], Toast.LENGTH_LONG).show();
  }
});

AlertDialog dialog = builder.create();
dialog.show();

The above code will display the list in the dialog like this.

Simple List in AlertDialog
Simple List in AlertDialog

2. Radio Button List
Now we will display list with Radio Button in the AlertDialog. You can use such list when you want to select only 1 item from the list of items. This is similar to the first one in the functionality but the visual representation is different. Here we will add positive button(OK/Done) to confirm the selection once the user select his/her option via Radio Button. Here we use the same String array as previous one.
We can use this list dialog in place of dropdown list(spinner).

String[] listItems = {"one", "two", "three", "four", "five"};

AlertDialog.Builder builder = new AlertDialog.Builder(ListAlertDialogActivity.this);
builder.setTitle("Choose item");

int checkedItem = 0; //this will checked the item when user open the dialog
builder.setSingleChoiceItems(listItems, checkedItem, new DialogInterface.OnClickListener() {
  @Override
  public void onClick(DialogInterface dialog, int which) {
    Toast.makeText(ListAlertDialogActivity.this, "Position: " + which + " Value: " + listItems[which], Toast.LENGTH_LONG).show();
  }
});

builder.setPositiveButton("Done", new DialogInterface.OnClickListener() {
  @Override
  public void onClick(DialogInterface dialog, int which) {
    dialog.dismiss();
  }
});

AlertDialog dialog = builder.create();
dialog.show();

The above code will display the list in the dialog with radio button like this.

Radio Button List in AlertDialog
Radio Button List in AlertDialog

3. Check Box List
This list is very important as we are going to select multiple items from the list using checkbox. We can use this list in many project where you want to select multiple items. Here we need to add confirmation button(OK/Done) after user selects all the items he/she wants. Here we use the same String array as previous one.
We can also call this a multi-select list or multi select dropdown list.

String[] listItems = {"one", "two", "three", "four", "five"};

AlertDialog.Builder builder = new AlertDialog.Builder(ListAlertDialogActivity.this);
builder.setTitle("Choose items");

boolean[] checkedItems = new boolean[]{true, false, true, false, true}; //this will checked the items when user open the dialog
builder.setMultiChoiceItems(listItems, checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
  @Override
  public void onClick(DialogInterface dialog, int which, boolean isChecked) {
    Toast.makeText(ListAlertDialogActivity.this, "Position: " + which + " Value: " + listItems[which] + " State: " + (isChecked ? "checked" : "unchecked"), Toast.LENGTH_LONG).show();
  }
});

builder.setPositiveButton("Done", new DialogInterface.OnClickListener() {
  @Override
  public void onClick(DialogInterface dialog, int which) {
    dialog.dismiss();
  }
});

AlertDialog dialog = builder.create();
dialog.show();

The above code will display the list in the dialog with radio button like this.

Check Box List in AlertDialog
Check Box List in AlertDialog

You can find the source code for this on my github repo: https://github.com/dakshbhatt21/a-computer-engineer

Display image grid in RecyclerView in Android

Display image grid in Android is now very easy to do with this tutorial. We use RecyclerView for this tutorial using GridLayoutManager.

Images Grid in Android
Images Grid in Android

First of all we will create layout for this post.

<?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:layout_width="match_parent" 
  android:layout_height="match_parent" 
  tools:context=".ImageGridActivity">

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

  </android.support.v7.widget.RecyclerView>

</RelativeLayout>

Now we create adapter which holds the ImageView which will go in the grid.

public class ImageGridAdapter extends RecyclerView.Adapter<ImageGridAdapter.GridItemViewHolder> {

  private List<String> imageList;

  private Context c;

  public class GridItemViewHolder extends RecyclerView.ViewHolder {
    SquareImageView siv;

    public GridItemViewHolder(View view) {
      super(view);
      siv = view.findViewById(R.id.siv);
    }
  }

  public ImageGridAdapter(Context c, List imageList) {
    this.c = c;
    this.imageList = imageList;
  }

  @Override
  public GridItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_grid, parent, false);

    return new GridItemViewHolder(itemView);
  }

  @Override
  public void onBindViewHolder(GridItemViewHolder holder, int position) {
    final String path = imageList.get(position);

    Picasso.get()
        .load(path)
        .resize(250, 250)
        .centerCrop()
        .into(holder.siv);

    holder.siv.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //handle click event on image
        }
    });
  }

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

}

Here I used Picasso library to display image, if you want to integrate it in your project then please check their web page: http://square.github.io/picasso/

Now we will go for the layout we used in above adapter. It just hold single ImageView.

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

  <com.acomputerengineer.CustomView.SquareImageView 
    android:id="@+id/siv" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" />

</RelativeLayout>

In above code, you must be thinking what is SquareImageView, right? It is the custom view which keeps ImageView square in the grid. The code for it is given below.

public class SquareImageView extends AppCompatImageView {
  public SquareImageView(Context context) {
    super(context);
  }

  public SquareImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int width = getMeasuredWidth();
    setMeasuredDimension(width, width);
  }
}

Now we set the above adapter to the RecyclerView so that our Images will be displayed in the grid manner. Here we use images from Flickr public domain. In RecyclerView, we used StaggeredGridLayoutManager which tell the RecyclerView to use the grid like layout with the number of columns provided.

RecyclerView rv = findViewById(R.id.rv);

StaggeredGridLayoutManager sglm = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
rv.setLayoutManager(sglm);

List<String> imageList = new ArrayList<>();
imageList.add("https://farm5.staticflickr.com/4403/36538794702_83fd8b63b7_c.jpg");
imageList.add("https://farm5.staticflickr.com/4354/35684440714_434610d1d6_c.jpg");
imageList.add("https://farm5.staticflickr.com/4301/35690634410_f5d0e312cb_c.jpg");
imageList.add("https://farm4.staticflickr.com/3854/32890526884_7dc068fedd_c.jpg");
imageList.add("https://farm8.staticflickr.com/7787/18143831616_a239c78056_c.jpg");
imageList.add("https://farm9.staticflickr.com/8745/16657401480_57653ac8b0_c.jpg");
imageList.add("https://farm3.staticflickr.com/2917/14144166232_44613c53c7_c.jpg");
imageList.add("https://farm8.staticflickr.com/7453/13960410788_3dd02b7a02_c.jpg");
imageList.add("https://farm1.staticflickr.com/920/29297133218_de38a7e4c8_c.jpg");
imageList.add("https://farm2.staticflickr.com/1788/42989123072_6720c9608d_c.jpg");
imageList.add("https://farm1.staticflickr.com/888/29062858008_89851766c9_c.jpg");
imageList.add("https://farm2.staticflickr.com/1731/27940806257_8067196b41_c.jpg");
imageList.add("https://farm1.staticflickr.com/884/42745897912_ff65398e38_c.jpg");
imageList.add("https://farm2.staticflickr.com/1829/27971893037_1858467f9a_c.jpg");
imageList.add("https://farm2.staticflickr.com/1822/41996470025_414452d7a0_c.jpg");
imageList.add("https://farm2.staticflickr.com/1793/42937679651_3094ebb2b9_c.jpg");
imageList.add("https://farm1.staticflickr.com/892/42078661914_b940d96992_c.jpg");
ImageGridAdapter iga = new ImageGridAdapter(ImageGridActivity.this, imageList);
rv.setAdapter(iga);

You can find the source code for this on my github repo: https://github.com/dakshbhatt21/a-computer-engineer

Please let me know if you find any issue in the above code or have any difficulty in implementing that.

Facebook login and retrieve profile data in Android

Add Facebook dependency in your app level gradle file.

compile 'com.facebook.android:facebook-android-sdk:[4,5)'

Always check https://developers.facebook.com/ for the latest version of their Android SDK.

Now add following things in your manifest file.

Add this meta-data and activity declaration inside your application tag.

<meta-data
  android:name="com.facebook.sdk.ApplicationId"
  android:value="@string/facebook_app_id" />
<activity
  android:name="com.facebook.FacebookActivity"
  android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
  android:label="@string/app_name" />
<activity
  android:name="com.facebook.CustomTabActivity"
  android:exported="true">
  <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="@string/fb_login_protocol_scheme" />
  </intent-filter>
</activity>

Please add 2 strings ‘facebook_app_id’ and ‘fb_login_protocol_scheme’ from your Facebook app. You will already have ‘app_name’ string created in your project by Android Studio.

Now add this 2 line in your Application class(the class extending Application).

FacebookSdk.sdkInitialize(getApplicationContext());
AppEventsLogger.activateApp(this);

Now we add one button in our layout which will do login/logout functionality.

<Button
  android:id="@+id/btn"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="Login" />

Here is the coding for the java file, i.e. MainActivity.java

public class MainActivity extends AppCompatActivity {
  private Button btn;
  private CallbackManager callbackManager;
  private AccessTokenTracker accessTokenTracker;
  private AccessToken accessToken;

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

    FacebookSdk.sdkInitialize(this.getApplicationContext());

    btn = (Button) findViewById(R.id.btn);

    callbackManager = CallbackManager.Factory.create();

    accessTokenTracker = new AccessTokenTracker() {
      @Override
      protected void onCurrentAccessTokenChanged(AccessToken oldAccessToken, AccessToken currentAccessToken) {
        accessToken = currentAccessToken;
        if (accessToken == null) {
          btn.setText("LOGIN");
        }
        else {
          btn.setText("LOGOUT");
          GraphRequest request = GraphRequest.newMeRequest(accessToken,
            new GraphRequest.GraphJSONObjectCallback() {
              @Override
              public void onCompleted(JSONObject object, GraphResponse response  {
                if (null != object) {
                  //your json object here, access user data here
                  Log.e("test", "json: " + object.toString());
                }
                else {
                  Log.e("test", "json: null");
                }
              }
            });
            Bundle parameters = new Bundle();
            parameters.putString("fields",  "id,birthday,first_name,gender,last_name,location,name,locale,timezone,updated_time,verified,email,hometown");
            request.setParameters(parameters);
            request.setAccessToken(accessToken);
            request.executeAsync();
          }
        }
      };

      accessToken = AccessToken.getCurrentAccessToken();
      if (null != accessToken) {
        btn.setText("LOGOUT");
      } else {
        btn.setText("LOGIN");
      }

      btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
          if ("LOGOUT".equals(btn.getText().toString())) {
            LoginManager.getInstance().logOut();
          } else {
          LoginManager.getInstance().logInWithReadPermissions(MainActivity1.this, Arrays.asList("public_profile", "email", "user_birthday", "user_hometown", "user_location"));
          }
        }
      });
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    callbackManager.onActivityResult(requestCode, resultCode, data);
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    accessTokenTracker.stopTracking();
  }
}

Draw circle shape in Canvas in Android

Draw circle shape in canvas is very easy thing to do if you are familiar with Canvas in Android. Please checkout this tutorial if you don’t know about how to create basic Canvas, display it to ImageView and save it as Bitmap.

Here we draw one canvas of 500×500 resolution and draw circle shape in the middle of the canvas.

The below line will draw circle shape in canvas.

canvas.drawCircle(x, y, radius, paint);

Here we pass x and y as the center coordinats of the circle. radius represents the radius of the circle being drawn. And paint is the Paint for drawing circle.

Now we will write the full code to draw circle in canvas.

Paint pBackground = new Paint();
pBackground.setColor(Color.WHITE);
canvas.drawRect(0, 0, 512, 512, pBackground);
Paint pCircle = new Paint();
pCircle.setColor(Color.BLACK);
canvas.drawCircle(256, 256, 256, pCircle);