1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.cooliris.media; 18 19 import java.io.DataInputStream; 20 import java.io.DataOutputStream; 21 import java.io.File; 22 import java.io.FileInputStream; 23 import java.io.FileOutputStream; 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.io.OutputStream; 27 import java.util.List; 28 29 import android.content.ActivityNotFoundException; 30 import android.content.ContentResolver; 31 import android.content.ContentUris; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.database.Cursor; 35 import android.graphics.Bitmap; 36 import android.graphics.BitmapFactory; 37 import android.net.Uri; 38 import android.provider.MediaStore; 39 import android.widget.Toast; 40 41 import com.cooliris.app.App; 42 import com.cooliris.app.Res; 43 44 public class Utils { 45 private static final int UNCONSTRAINED = -1; 46 47 public static void playVideo(final Context context, final MediaItem item) { 48 // this is a video 49 App.get(context).getHandler().post(new Runnable() { 50 public void run() { 51 try { 52 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(item.mContentUri)); 53 intent.setDataAndType(Uri.parse(item.mContentUri), item.mMimeType); 54 context.startActivity(intent); 55 } catch (ActivityNotFoundException e) { 56 Toast.makeText(context, context.getResources().getString(Res.string.video_err), Toast.LENGTH_SHORT).show(); 57 } 58 } 59 }); 60 } 61 62 public static final void writeUTF(DataOutputStream dos, String string) throws IOException { 63 if (string == null) { 64 dos.writeUTF(new String()); 65 } else { 66 dos.writeUTF(string); 67 } 68 } 69 70 public static final String readUTF(DataInputStream dis) throws IOException { 71 String retVal = dis.readUTF(); 72 if (retVal.length() == 0) 73 return null; 74 return retVal; 75 } 76 77 public static final Bitmap resizeBitmap(Bitmap bitmap, int maxSize) { 78 int srcWidth = bitmap.getWidth(); 79 int srcHeight = bitmap.getHeight(); 80 int width = maxSize; 81 int height = maxSize; 82 boolean needsResize = false; 83 if (srcWidth > srcHeight) { 84 if (srcWidth > maxSize) { 85 needsResize = true; 86 height = ((maxSize * srcHeight) / srcWidth); 87 } 88 } else { 89 if (srcHeight > maxSize) { 90 needsResize = true; 91 width = ((maxSize * srcWidth) / srcHeight); 92 } 93 } 94 if (needsResize) { 95 Bitmap retVal = Bitmap.createScaledBitmap(bitmap, width, height, true); 96 return retVal; 97 } else { 98 return bitmap; 99 } 100 } 101 102 private static final long POLY64REV = 0x95AC9329AC4BC9B5L; 103 private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL; 104 105 private static boolean init = false; 106 private static long[] CRCTable = new long[256]; 107 108 /** 109 * A function thats returns a 64-bit crc for string 110 * 111 * @param in 112 * : input string 113 * @return 64-bit crc value 114 */ 115 public static final long Crc64Long(String in) { 116 if (in == null || in.length() == 0) { 117 return 0; 118 } 119 // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c 120 long crc = INITIALCRC, part; 121 if (!init) { 122 for (int i = 0; i < 256; i++) { 123 part = i; 124 for (int j = 0; j < 8; j++) { 125 int value = ((int) part & 1); 126 if (value != 0) 127 part = (part >> 1) ^ POLY64REV; 128 else 129 part >>= 1; 130 } 131 CRCTable[i] = part; 132 } 133 init = true; 134 } 135 int length = in.length(); 136 for (int k = 0; k < length; ++k) { 137 char c = in.charAt(k); 138 crc = CRCTable[(((int) crc) ^ c) & 0xff] ^ (crc >> 8); 139 } 140 return crc; 141 } 142 143 /** 144 * A function that returns a human readable hex string of a Crx64 145 * 146 * @param in 147 * : input string 148 * @return hex string of the 64-bit CRC value 149 */ 150 public static final String Crc64(String in) { 151 if (in == null) 152 return null; 153 long crc = Crc64Long(in); 154 /* 155 * The output is done in two parts to avoid problems with 156 * architecture-dependent word order 157 */ 158 int low = ((int) crc) & 0xffffffff; 159 int high = ((int) (crc >> 32)) & 0xffffffff; 160 String outVal = Integer.toHexString(high) + Integer.toHexString(low); 161 return outVal; 162 } 163 164 public static long getBucketIdFromUri(final ContentResolver cr, final Uri uri) { 165 if (uri.getScheme().equals("file")) { 166 String string = "/"; 167 List<String> paths = uri.getPathSegments(); 168 int numPaths = paths.size(); 169 for (int i = 0; i < numPaths - 1; ++i) { 170 string += paths.get(i); 171 if (i != numPaths - 2) 172 string += "/"; 173 } 174 return LocalDataSource.getBucketId(string); 175 } else { 176 Cursor cursor = null; 177 try { 178 long id = ContentUris.parseId(uri); 179 cursor = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 180 new String[] { MediaStore.Images.ImageColumns.BUCKET_ID }, MediaStore.Images.ImageColumns._ID + "=" + id, 181 null, null); 182 if (cursor != null) { 183 if (cursor.moveToFirst()) { 184 long setVal = cursor.getLong(0); 185 cursor.close(); 186 return setVal; 187 } 188 } 189 cursor = cr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, 190 new String[] { MediaStore.Video.VideoColumns.BUCKET_ID }, MediaStore.Images.ImageColumns._ID + "=" + id, 191 null, null); 192 if (cursor != null) { 193 if (cursor.moveToFirst()) { 194 long setVal = cursor.getLong(0); 195 cursor.close(); 196 return setVal; 197 } 198 } 199 } catch (Exception e) { 200 ; 201 } 202 return Shared.INVALID; 203 } 204 } 205 206 public static String getBucketNameFromUri(final ContentResolver cr, final Uri uri) { 207 final long bucketId = getBucketIdFromUri(cr, uri); 208 if (bucketId != Shared.INVALID) { 209 try { 210 Cursor cursor = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 211 new String[] { MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME }, 212 MediaStore.Images.ImageColumns.BUCKET_ID + "='" + bucketId + "'", null, null); 213 if (cursor != null) { 214 if (cursor.moveToFirst()) { 215 String setName = cursor.getString(0); 216 cursor.close(); 217 return setName; 218 } 219 } 220 cursor = cr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, 221 new String[] { MediaStore.Video.VideoColumns.BUCKET_DISPLAY_NAME }, MediaStore.Video.VideoColumns.BUCKET_ID 222 + "='" + bucketId + "'", null, null); 223 if (cursor != null) { 224 if (cursor.moveToFirst()) { 225 String setName = cursor.getString(0); 226 cursor.close(); 227 return setName; 228 } 229 } 230 } catch (Exception e) { 231 ; 232 } 233 } 234 return ""; 235 } 236 237 // Copies src file to dst file. 238 // If the dst file does not exist, it is created 239 public static void Copy(File src, File dst) throws IOException { 240 InputStream in = new FileInputStream(src); 241 OutputStream out = new FileOutputStream(dst); 242 copyStream(in, out); 243 } 244 245 public static void copyStream(InputStream in, OutputStream out) throws IOException { 246 // Transfer bytes from in to out 247 byte[] buf = new byte[1024]; 248 int len; 249 while ((len = in.read(buf)) > 0) { 250 out.write(buf, 0, len); 251 } 252 in.close(); 253 out.close(); 254 } 255 256 /* 257 * Compute the sample size as a function of minSideLength 258 * and maxNumOfPixels. 259 * minSideLength is used to specify that minimal width or height of a 260 * bitmap. 261 * maxNumOfPixels is used to specify the maximal size in pixels that is 262 * tolerable in terms of memory usage. 263 * 264 * The function returns a sample size based on the constraints. 265 * Both size and minSideLength can be passed in as IImage.UNCONSTRAINED, 266 * which indicates no care of the corresponding constraint. 267 * The functions prefers returning a sample size that 268 * generates a smaller bitmap, unless minSideLength = IImage.UNCONSTRAINED. 269 * 270 * Also, the function rounds up the sample size to a power of 2 or multiple 271 * of 8 because BitmapFactory only honors sample size this way. 272 * For example, BitmapFactory downsamples an image by 2 even though the 273 * request is 3. So we round up the sample size to avoid OOM. 274 */ 275 public static int computeSampleSize(BitmapFactory.Options options, 276 int minSideLength, int maxNumOfPixels) { 277 int initialSize = computeInitialSampleSize(options, minSideLength, 278 maxNumOfPixels); 279 280 int roundedSize; 281 if (initialSize <= 8 ) { 282 roundedSize = 1; 283 while (roundedSize < initialSize) { 284 roundedSize <<= 1; 285 } 286 } else { 287 roundedSize = (initialSize + 7) / 8 * 8; 288 } 289 290 return roundedSize; 291 } 292 293 public static int computeInitialSampleSize(BitmapFactory.Options options, 294 int minSideLength, int maxNumOfPixels) { 295 double w = options.outWidth; 296 double h = options.outHeight; 297 298 int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : 299 (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); 300 int upperBound = (minSideLength == UNCONSTRAINED) ? 128 : 301 (int) Math.min(Math.floor(w / minSideLength), 302 Math.floor(h / minSideLength)); 303 304 if (upperBound < lowerBound) { 305 // return the larger one when there is no overlapping zone. 306 return lowerBound; 307 } 308 309 if ((maxNumOfPixels == UNCONSTRAINED) && 310 (minSideLength == UNCONSTRAINED)) { 311 return 1; 312 } else if (minSideLength == UNCONSTRAINED) { 313 return lowerBound; 314 } else { 315 return upperBound; 316 } 317 } 318 319 } 320