Convert pixel to dp or dip and dp to pixel in Android

If we need to set dimension of any view from the java file, it will use pixel as default unit. Where as in XML file we use dp or dip(density independent pixel). So 100 dp is not equal to 100 pixel.

Screenshot_20160623-151106
200dp = 525pixel in this case

Android uses density factor to provide support to different devices with different screensize. So the conversion works as explained below.

First we will check the conversion of dp to pixel. Here dp is density independent and pixel is dependent on density. So if we need to find pixel from give dp, we need to multiply it with the density of the device.

So the equation will be like this

pixel = dp * (density of the device);

Here is the function to convert dp to pixel.

public static float dpTopixel(Context c, float dp) {
  float density = c.getResources().getDisplayMetrics().density;
  float pixel = dp * density;
  return pixel;
}

Now we will convert pixel to dp. Here we need to divide the pixel with the density of the device so the result will become independent of density(dp).

So the equation will be like this

dp = pixel / (density of the device);

Here is the function to convert pixel to dp.

public static float pixelTodp(Context c, float pixel) {
  float density = c.getResources().getDisplayMetrics().density;
  float dp = pixel / density;
  return dp;
}

Now if you want to use this value as width or height in any of your view’s LayoutParams, it will ask you for Integer(int) value and above functions will return you Float(float) value. So you have to do following thing to convert it to Integer(int).

int width = (int) dpTopixel(MainActivity.this, 200);

Please comment if you find any mistake or want to give feedback.

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

Resize image during decode from file to Bitmap in android

java.lang.OutOfMemoryError is the nightmare for any android developer. During image operation we may get this out of memory exception any time because our app uses all the memory allocated by android system to that app so it will give you out of memory error.

We encounter this error when we try to decode larger image using its path of sdcard to Bitmap. So we can skip this error by decoding image to smaller size.

We can avoid this problem or better to say restrict it to a level by creating Bitmap of required size and not the actual size.

Images taken from camera now a days are of more than 3000 and 4000 in resolution. So if we want to display them in GridView or ListView, we have to sample them down so it won’t create OOM or does not hang the UI.

For that we will use sample size to BitmapFactory.Options while decoding the image. It will load your image in smaller size compare to the original image and save your memory.

Google suggest that sample size should be in power of 2 so the below code contains the logic of creating sample size according to the maximum size you provide and then it will load your image with the resolution near to that maximum size.

Here is the direct function I create that you can use in your project by providing the file path of your image. You can find out how get the file path of any image from this article: Pick image from gallery before and after Kitkat version in Android

private Bitmap decodeFile(String imgPath)
{
  Bitmap b = null;
  int max_size = 1000;
  File f = new File(imgPath);
  try {
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;
    FileInputStream fis = new FileInputStream(f);
    BitmapFactory.decodeStream(fis, null, o);
    fis.close();
    int scale = 1;
    if (o.outHeight > max_size || o.outWidth > max_size)
    {
      scale = (int) Math.pow(2, (int) Math.ceil(Math.log(max_size / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
    }
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize = scale;
    fis = new FileInputStream(f);
    b = BitmapFactory.decodeStream(fis, null, o2);
    fis.close();
  }
  catch (Exception e)
  {
  }
  return b;
}

Share your views in comments!

Add “Rate This App” button to your Android App

Many time in out Android app, we need to open our page on Google Play Store within the app. And it is also helpful to encourage people to rate our application. So we can put a button or dialog in our app that user can use to rate our app on Google Play Store.

For that first we check that if the user device has the play store installed in their device or not. Because many device and tablets does not have play store app in their device. So we will use try catch here so if the Play Store is not available we can open the app in browser from catch part.

try {
  startActivity(new Intent(Intent.ACTION_VIEW, 
      Uri.parse("market://details?id=" + getPackageName())));
} 
catch (android.content.ActivityNotFoundException anfe) {
  startActivity(new Intent(Intent.ACTION_VIEW, 
      Uri.parse("http://play.google.com/store/apps/details?id=" + getPackageName())));
}

Now if the device has the play store, we will directly open our app in play store app. If the play store are not found in the device it will open in browser. If you have more than one browser, it will prompt you to choose one.

startActivity(new Intent(Intent.ACTION_VIEW, 
      Uri.parse("http://play.google.com/store/apps/details?id=" + getPackageName())));

Here is the full code that you can use in your button onClick event.

btnRateApp.setOnClickListener(new OnClickListener() {
  @Override
  public void onClick(View v) {
    try {
      startActivity(new Intent(Intent.ACTION_VIEW, 
        Uri.parse("market://details?id=" + getPackageName())));
    } 
    catch (android.content.ActivityNotFoundException anfe) {
      startActivity(new Intent(Intent.ACTION_VIEW, 
        Uri.parse("http://play.google.com/store/apps/details?id=" + getPackageName())));
    }
  }
});

I also make a function that you can include in your file and call it from any onClick event of button, make sure you pass the package name as argument.

public void rateApp(String packageName) {
  try {
    startActivity(new Intent(Intent.ACTION_VIEW, 
      Uri.parse("market://details?id=" + packageName)));
  } 
  catch (android.content.ActivityNotFoundException anfe) {
    startActivity(new Intent(Intent.ACTION_VIEW, 
      Uri.parse("http://play.google.com/store/apps/details?id=" + packageName)));
  }
}

Get name of the month from the number of the month Java

Many times we need to use month name to display date in well formed manner. I encounter this issue while developing Android application that use Android datepicker. It returns me the number of the month between 0 to 11 [I thought it would be 1-12]. But for display I need the name of the month.

For that I found one Java class that can convert integer number to name [I am too lazy to write an array that can do the work for me]. And the class DateFormatSymbols can convert it the following way. I just made a method so everyone[like me !!!] can copy-paste it to their project.

public String getMonthForInt(int num) {
    String month = "wrong";
    DateFormatSymbols dfs = new DateFormatSymbols();
    String[] months = dfs.getMonths();
    if (num >= 0 && num <= 11 ) {
        month = months[num];
    }
    return month.toLowerCase();
}

Validation in Java/Android

Many time during my Android development, I need to verify email address, username, password or any specific requirements. Most of times it needs when I am building registration form or login form. So I made the function that takes first argument as string on which validation is needed and pattern [Regular Expression] that decides first argument is valid or invalid.

Here I use two main java class

Here Pattern class compile the regular expression and then Matcher class perform match operation against given String using compiled pattern. Here is the function for that.

	public Boolean validate(String text, String regex)	{
		Pattern pattern;	
		Matcher matcher;
		pattern = Pattern.compile(regex);
    	matcher = pattern.matcher(text);
    	if(matcher.matches())	{
    		return true;
    	}
    	else	{
    		return false;
    	}
	}

Here you can see that the function validate validates the String text against the regex using Pattern and Matcher class. I attached the example of email validation below, but you can use any validation by just providing their regular expression.

Download example of email validation with comments here : https://www.mediafire.com/view/vgw8pdf5db9ygzu/Validation.java

References :

Set the wallpaper from code in Android

During android application you may need to set wallpaper using code, then you have to use following method.

public void setStream (InputStream data)

For that you need to include the following permission to your menifest file.

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

I’ve made the method that will directly set the wallpaper image specified in argument.

public void setWallpaper(String pathToImage)    {
    try {
        WallpaperManager wpm = WallpaperManager.getInstance(getApplicationContext());
	    InputStream ins = new URL("file://" + pathToImage).openStream();
	    wpm.setStream(ins);
	    Toast.makeText(getApplicationContext(), "Wallpaper has been set", Toast.LENGTH_SHORT).show();            
    } 
    catch (MalformedURLException e) {
        e.printStackTrace();
    } 
    catch (IOException e) {
        e.printStackTrace();
    }     
}

Here we have to specify “file://” which specify the protocol which we use here. We can also use http, ftp, etc. Otherwise it throws “java.net.MalformedURLException: Protocol not found: ” exception.