/******************************************************************************* * Copyright 2011 The Regents of the University of California * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package org.ohmage; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.graphics.Color; import android.net.Uri; import android.provider.MediaStore; import android.util.Log; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.util.Calendar; import java.util.List; public class Utilities { private static final String TAG = "Utilities"; public static class KVPair { public String key; public String value; public KVPair(String key, String value) { this.key = key; this.value = value; } } public static class KVLTriplet { public String key; public String value; public String label; public KVLTriplet(String key, String value, String label) { this.key = key; this.value = value; this.label = label; } } public static void delete(File f) throws IOException { if (f == null) return; if (f.isDirectory()) { for (File c : f.listFiles()) { delete(c); } } f.delete(); } public static String convertStreamToString(InputStream is) { /* * To convert the InputStream to String we use the * BufferedReader.readLine() method. We iterate until the BufferedReader * return null which means there's no more data to read. Each line will * appended to a StringBuilder and returned as String. */ BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return sb.toString(); } /** * Converts an array of numbers to an array of doubles that can be used by * the histogram and sparkline charts * * @param data * @return */ public static double[] toArray(List<? extends Number> data) { double[] ret = new double[data.size()]; for (int i = 0; i < ret.length; i++) ret[i] = data.get(i).doubleValue(); return ret; } public static BitmapFactory.Options decodeImageOptions(File f) throws IOException { // Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; FileInputStream fis = new FileInputStream(f); BitmapFactory.decodeStream(fis, null, o); fis.close(); return o; } /** * Decodes an image file in a memory efficient way * * @param f file to decode * @param maxSize length of the longer side * @return the bitmap object that has be resized * @throws IOException */ public static Bitmap decodeImage(File f, int maxSize) throws IOException { return decodeImage(f, decodeImageOptions(f), maxSize); } /** * Decodes an image file in a memory efficient way. use * {@link #decodeImage(File, int)} unless you already called * {@link #decodeImageOptions(File)} and have the image options avaliable. * * @param f file to decode * @param o options file from #{@link #decodeImageOptions(File)} * @param maxSize length of the longer side * @return the bitmap object that has be resized * @throws IOException */ public static Bitmap decodeImage(File f, Options o, int maxSize) throws IOException { Bitmap b = null; int scale = 1; if (o.outHeight > maxSize || o.outWidth > maxSize) { scale = (int) Math.pow( 2, (int) Math.round(Math.log(maxSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5))); } // Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; FileInputStream fis = new FileInputStream(f); b = BitmapFactory.decodeStream(fis, null, o2); fis.close(); return b; } /** * Resize the image at the file and save it back * * @param f * @param maxSize * @return true if the image was saved successfully */ public static boolean resizeImageFile(File f, int maxSize) { Bitmap b = null; try { Options o = decodeImageOptions(f); // If its already smaller, don't do anything if (o.outHeight < maxSize && o.outWidth < maxSize) return true; b = decodeImage(f, o, maxSize); if (b != null) { try { FileOutputStream out = null; try { out = new FileOutputStream(f); b.compress(Bitmap.CompressFormat.JPEG, 90, out); } finally { if (out != null) { out.close(); return true; } } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } catch (IOException e) { Log.e(TAG, "Image resize failed.", e); } finally { if (b != null) b.recycle(); } return false; } /** * Counts the numnber of bytes read in the inputstream * * @author cketcham */ public static class CountingInputStream extends FilterInputStream { private long mLength; public CountingInputStream(InputStream is) { super(is); mLength = 0; } @Override public int read() throws IOException { mLength++; return super.read(); } @Override public int read(byte[] buffer, int offset, int count) throws IOException { int c = super.read(buffer, offset, count); mLength += c; return c; } public long amountRead() { return mLength; } } /** * Darkens the color value * * @param color * @return */ public static int darkenColor(int color) { return changeColor(color, -60); } /** * Lightens color value * * @param color * @return */ public static int lightenColor(int color) { return changeColor(color, 15); } /** * Change the color by the specified amount * * @param color * @param amount * @return */ private static int changeColor(int color, int amount) { amount = fitToColor(Color.red(color), amount); amount = fitToColor(Color.green(color), amount); amount = fitToColor(Color.blue(color), amount); return Color.rgb(Color.red(color) + amount, Color.green(color) + amount, Color.blue(color) + amount); } /** * Makes sure that an adjustment by this amount for this part of the color * wont overflow (which will cause the overall color to change) * * @param color * @param change * @return */ private static int fitToColor(int color, int change) { if (color + change < 0 || color + change > 255) return 255 - color; return change; } /** * Calculates the grayscale value of the color * * @param color * @return the gray scale color */ public static int colorGrayscale(int color) { float[] hsv = new float[3]; Color.colorToHSV(color, hsv); hsv[0] = 0; hsv[1] = 0; return Color.HSVToColor(hsv); } /** * utility method for converting dp to pixels, since the setters only take * pixel values :\ * * @param dp value * @return */ public static int dpToPixels(int dp) { final float scale = OhmageApplication.getContext().getResources().getDisplayMetrics().density; return (int) (dp * scale + 0.5f); } /** * Clears the time component of a calendar object * * @param cal */ public static void clearTime(Calendar cal) { cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); } public static File fileForMediaStore(Uri uri) { String[] filePathColumn = { MediaStore.Images.Media.DATA }; Cursor cursor = OhmageApplication.getContext().getContentResolver() .query(uri, filePathColumn, null, null, null); cursor.moveToFirst(); int columnIndex = cursor.getColumnIndex(filePathColumn[0]); String filePath = cursor.getString(columnIndex); cursor.close(); return new File(filePath); } public static int moveMediaStoreFile(Uri uri, File file) { if (moveFile(fileForMediaStore(uri), file)) return OhmageApplication.getContext().getContentResolver().delete(uri, null, null); return -1; } public static boolean moveFile(File src, File dest) { if (!src.renameTo(dest)) { try { copy(src, dest); return src.delete(); } catch (IOException e) { e.printStackTrace(); return false; } } return true; } public static void copy(File src, File dst) throws IOException { InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dst); // Transfer bytes from in to out byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } in.close(); out.close(); } /** * Formats an object that might be null to be displayed * * @param disp * @return ? if it is null, the object otherwise */ public static String getHtmlSafeDisplayString(Object disp) { return (disp == null) ? "?" : disp.toString().replace("&", "&").replace("<", "<") .replace(">", ">"); } /** * Executes the network requests on a separate thread. * * @param runnable The runnable instance containing network mOperations to * be executed. */ public static Thread performOnBackgroundThread(final Runnable runnable) { final Thread t = new Thread() { @Override public void run() { try { runnable.run(); } finally { } } }; t.start(); return t; } }