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

Pick image from gallery before and after KITKAT version in Android

In the android application, we need to pick any image from our gallery. For that android provides some in-built intent action that can fetch us image from gallery. After Android Kitkat, Google made few changes so that we can pick image from different applications.

Screenshot_2016-04-25-00-20-37

The following code will open Default Picker app for KitKat, Lollipop, Marshmallow and Android N users and Gallery app for before Kitkat users to pick image.

Update:
The previous code sometimes failed to get image from external sdcard, Google Drive or sometime from internal storage too. So I did some research and integrate few answers from Stackoverflow and come up with a new solution which able to pick image from every things from that Default Picker App after Kitkat devices displayed in the image.

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
  intent.addCategory(Intent.CATEGORY_OPENABLE);
  intent.setType("image/*");
  startActivityForResult(Intent.createChooser(intent, "Select Picture"), 1);
} else {
  Intent intent = new Intent();
  intent.setType("image/*");
  intent.setAction(Intent.ACTION_GET_CONTENT);
  startActivityForResult(Intent.createChooser(intent, "Select Picture"), 1);
}

Now after selecting image, we need to handle it properly to display it to ImageView or we need to get it’s path if we want to do any other operation on it. Here is the code for onActivityResult.

@TargetApi(19)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (data != null && data.getData() != null && resultCode == RESULT_OK) {
    boolean isImageFromGoogleDrive = false;
    Uri uri = data.getData();

    if (isKitKat && DocumentsContract.isDocumentUri(TestActivity.this, uri)) {
      if ("com.android.externalstorage.documents".equals(uri.getAuthority())) {
        String docId = DocumentsContract.getDocumentId(uri);
        String[] split = docId.split(":");
        String type = split[0];

        if ("primary".equalsIgnoreCase(type)) {
          imgPath = Environment.getExternalStorageDirectory() + "/" + split[1];
        }
        else {
          Pattern DIR_SEPORATOR = Pattern.compile("/");
          Set<String> rv = new HashSet<>();
          String rawExternalStorage = System.getenv("EXTERNAL_STORAGE");
          String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
          String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET");
          if(TextUtils.isEmpty(rawEmulatedStorageTarget))
          {
            if(TextUtils.isEmpty(rawExternalStorage))
            {
              rv.add("/storage/sdcard0");
            }
            else
            {
              rv.add(rawExternalStorage);
            }
          }
          else
          {
            String rawUserId;
            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
            {
              rawUserId = "";
            }
            else
            {
              String path = Environment.getExternalStorageDirectory().getAbsolutePath();
              String[] folders = DIR_SEPORATOR.split(path);
              String lastFolder = folders[folders.length - 1];
              boolean isDigit = false;
              try
              {
                Integer.valueOf(lastFolder);
                isDigit = true;
              }
              catch(NumberFormatException ignored)
              {
              }
              rawUserId = isDigit ? lastFolder : "";
            }
            if(TextUtils.isEmpty(rawUserId))
            {
              rv.add(rawEmulatedStorageTarget);
            }
            else
            {
              rv.add(rawEmulatedStorageTarget + File.separator + rawUserId);
            }
          }
          if(!TextUtils.isEmpty(rawSecondaryStoragesStr))
          {
            String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
            Collections.addAll(rv, rawSecondaryStorages);
          }
          String[] temp = rv.toArray(new String[rv.size()]);
          for (int i = 0; i < temp.length; i++)   {
            File tempf = new File(temp[i] + "/" + split[1]);
            if(tempf.exists()) {
              imgPath = temp[i] + "/" + split[1];
            }
          }
        }
      }
      else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
        String id = DocumentsContract.getDocumentId(uri);
        Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

        Cursor cursor = null;
        String column = "_data";
        String[] projection = { column };
        try {
          cursor = TestActivity.this.getContentResolver().query(contentUri, projection, null, null,
null);
          if (cursor != null && cursor.moveToFirst()) {
            int column_index = cursor.getColumnIndexOrThrow(column);
            imgPath = cursor.getString(column_index);
          }
        } finally {
          if (cursor != null)
            cursor.close();
        }
      }
      else if("com.android.providers.media.documents".equals(uri.getAuthority())) {
        String docId = DocumentsContract.getDocumentId(uri);
        String[] split = docId.split(":");
        String type = split[0];

        Uri contentUri = null;
        if ("image".equals(type)) {
          contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        } else if ("video".equals(type)) {
          contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
        } else if ("audio".equals(type)) {
          contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        }

        String selection = "_id=?";
        String[] selectionArgs = new String[]{ split[1] };

        Cursor cursor = null;
        String column = "_data";
        String[] projection = { column };

        try {
          cursor = TestActivity.this.getContentResolver().query(contentUri, projection, selection, selectionArgs, null);
          if (cursor != null && cursor.moveToFirst()) {
            int column_index = cursor.getColumnIndexOrThrow(column);
            imgPath = cursor.getString(column_index);
          }
        } finally {
          if (cursor != null)
            cursor.close();
        }
      }
      else if("com.google.android.apps.docs.storage".equals(uri.getAuthority()))   {
        isImageFromGoogleDrive = true;
      }
    }
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
      Cursor cursor = null;
      String column = "_data";
      String[] projection = { column };

      try {
        cursor = TestActivity.this.getContentResolver().query(uri, projection, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
          int column_index = cursor.getColumnIndexOrThrow(column);
          imgPath = cursor.getString(column_index);
        }
      }
      finally {
        if (cursor != null)
          cursor.close();
      }
    }
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
      imgPath = uri.getPath();
    }

    if(isImageFromGoogleDrive)  {
      try {
        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
        img.setImageBitmap(bitmap);
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }
    else    {
      File f = new File(imgPath);
      BitmapFactory.Options bmOptions = new BitmapFactory.Options();
      Bitmap bitmap = BitmapFactory.decodeFile(f.getAbsolutePath(),bmOptions);
      img.setImageBitmap(bitmap);
    }
  }
  super.onActivityResult(requestCode, resultCode, data);
}

Here, images from Google Drive may not be on our device so we directly us InputStream of that image from the Google Drive and show it in the ImageView without getting it’s path. You can save it in your storage if you need to use it for any further requirement.

Please comments below if you find any mistake or having problem in implementing this code.

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