View Javadoc
1   /*
2    * Copyright (C) 2003-2014 eXo Platform SAS.
3    *
4    * This is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU Lesser General Public License as
6    * published by the Free Software Foundation; either version 3 of
7    * the License, or (at your option) any later version.
8    *
9    * This software is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this software; if not, write to the Free
16   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18   */
19  package org.exoplatform.utils;
20  
21  import java.io.ByteArrayOutputStream;
22  import java.io.File;
23  import java.io.FileNotFoundException;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.OutputStream;
28  import java.util.Calendar;
29  
30  import org.apache.http.HttpEntity;
31  import org.apache.http.HttpResponse;
32  import org.apache.http.client.ClientProtocolException;
33  import org.apache.http.client.methods.HttpGet;
34  import org.apache.http.impl.client.DefaultHttpClient;
35  import org.apache.http.params.BasicHttpParams;
36  import org.apache.http.params.HttpConnectionParams;
37  import org.apache.http.params.HttpParams;
38  
39  import org.exoplatform.R;
40  import org.exoplatform.utils.image.FileCache;
41  
42  import android.app.Activity;
43  import android.app.AlertDialog;
44  import android.content.Context;
45  import android.content.Intent;
46  import android.database.Cursor;
47  import android.graphics.Bitmap;
48  import android.graphics.Bitmap.CompressFormat;
49  import android.graphics.Bitmap.Config;
50  import android.graphics.BitmapFactory;
51  import android.graphics.Canvas;
52  import android.graphics.Matrix;
53  import android.graphics.Paint;
54  import android.graphics.PorterDuff.Mode;
55  import android.graphics.PorterDuffXfermode;
56  import android.graphics.RadialGradient;
57  import android.graphics.Rect;
58  import android.graphics.RectF;
59  import android.net.Uri;
60  import android.os.Environment;
61  import android.provider.MediaStore;
62  import android.provider.MediaStore.MediaColumns;
63  import android.text.format.DateFormat;
64  import android.util.DisplayMetrics;
65  
66  public class PhotoUtils {
67  
68    private static final String   dotSign        = ".";
69  
70    private static final int      IMAGE_WIDTH    = 1024;
71  
72    private static final int      IMAGE_HEIGH    = 860;
73  
74    private static final int      IMAGE_QUALITY  = 100;
75  
76    private static final String   TEMP_FILE_NAME = "tempfile";
77  
78    private static final String   MOBILE_IMAGE   = "MobileImage_";
79    
80    public static String getParentImagePath(Context context) {
81      FileCache cache = new FileCache(context, ExoConstants.DOCUMENT_FILE_CACHE);
82      return cache.getCachePath();
83    }
84    
85    /**
86     * Take a photo and store it into /sdcard/eXo/DocumentCache
87     * 
88     * @param caller the activity requesting an image capture
89     * @return the path to the captured image
90     */
91    public static String startImageCapture(Activity caller) {
92      if (caller == null)
93        throw new IllegalArgumentException("Activity requesting to capture an image cannot be null");
94      
95      String imagePath = String.format("%s/%s", getParentImagePath(caller), getImageFileName());
96      if (ExoDocumentUtils.didRequestPermission(caller, ExoConstants.REQUEST_TAKE_PICTURE_WITH_CAMERA)) {
97        return "";
98      }
99      Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
100     intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(imagePath)));
101     caller.startActivityForResult(intent, ExoConstants.REQUEST_TAKE_PICTURE_WITH_CAMERA);
102     return imagePath;
103   }
104   
105   /**
106    * Send a pick photo intent on behalf of the given activity.<br/>
107    * The result is passed to the calling activity via onActivityResult with the requestCode  {@link ExoConstants.REQUEST_ADD_PHOTO}.
108    * 
109    * @param caller the activity requesting a photo
110    */
111   public static void pickPhotoForActivity(Activity caller) {
112     if (caller == null)
113       throw new IllegalArgumentException("Activity requesting to pick photo cannot be null");
114     
115     if (ExoDocumentUtils.didRequestPermission(caller, ExoConstants.REQUEST_PICK_IMAGE_FROM_GALLERY)) {
116       return;
117     }
118     
119     Intent intent = new Intent(Intent.ACTION_PICK,
120                                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
121     intent.setType(ExoConstants.PHOTO_ALBUM_IMAGE_TYPE);
122     caller.startActivityForResult(intent, ExoConstants.REQUEST_PICK_IMAGE_FROM_GALLERY);
123   }
124   
125   /**
126    * 
127    * @param ctx
128    */
129   public static void alertNeedStoragePermission(Context ctx) {
130     AlertDialog.Builder db = new AlertDialog.Builder(ctx);
131     db.setMessage(R.string.PermissionStorageRationale)
132       .setPositiveButton(R.string.OK, null);
133     AlertDialog dialog = db.create();
134     dialog.show();
135   }
136 
137   /**
138    * Extract the extension from the given filename
139    * @param name File's name
140    * @return the part after the last dot (.) or an empty string if no dot is found
141    */
142   public static String getExtension(String name) {
143     int index = name.lastIndexOf(dotSign);
144     if (index == -1) return "";
145     String extension = name.substring(index + 1, name.length());
146     return extension;
147   }
148 
149   private static String getDateFormat() {
150     String dateFormat = null;
151     Calendar cal = Calendar.getInstance();
152     long minus = cal.getTimeInMillis();
153     String inFormat = new String("yyyy_MM_dd_hh_mm_ss");
154     dateFormat = (String) DateFormat.format(inFormat, minus);
155     return dateFormat;
156   }
157 
158   /**
159    * Creates a date with format dd/MM/yyyy hh:mm from the given timestamp
160    * @param value the time, as a String
161    * @return the date, as a String
162    */
163   public static String getDateFromTime(String value) {
164     String dateFormat = null;
165     if (value != null) {
166       long minus = Long.valueOf(value);
167       String inFormat = new String("dd/MM/yyyy hh:mm");
168       dateFormat = (String) DateFormat.format(inFormat, minus);
169     }
170 
171     return dateFormat;
172   }
173 
174   /**
175    * Name the image captured when posting an activity<br/>
176    * {@link PhotoUtils.MOBILE_IMAGE} + date + .jpg
177    * 
178    * @return the name
179    */
180   public static String getImageFileName() {
181     StringBuffer buffer = new StringBuffer();
182     buffer.append(MOBILE_IMAGE);
183     buffer.append(getDateFormat());
184     buffer.append(".jpg");
185     return buffer.toString();
186   }
187 
188   public static Bitmap shrinkBitmap(String file, int width, int height) {
189     
190     BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
191     bmpFactoryOptions.inJustDecodeBounds = true;
192     Bitmap bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);
193     
194     int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight / (float) height);
195     int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth / (float) width);
196     
197     if (heightRatio > 1 || widthRatio > 1) {
198       if (heightRatio > widthRatio) {
199         bmpFactoryOptions.inSampleSize = heightRatio;
200       } else {
201         bmpFactoryOptions.inSampleSize = widthRatio;
202       }
203     }
204 
205     if ("image/jpeg".equalsIgnoreCase(bmpFactoryOptions.outMimeType)) {
206       bmpFactoryOptions.inPreferredConfig = Bitmap.Config.RGB_565;
207       bmpFactoryOptions.inDither = true;
208     } else {
209       bmpFactoryOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
210     }
211     bmpFactoryOptions.inJustDecodeBounds = false;
212     
213     CrashUtils.setShrinkInfo(bmpFactoryOptions);
214     
215     bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);
216     
217     CrashUtils.setShrinkInfo(null);
218     return bitmap;
219   }
220 
221   public static Bitmap resizeImage(Bitmap originalImage, int newW) {
222 
223     Bitmap resizedBitmap = null;
224 
225     int width = originalImage.getWidth();
226 
227     if (width >= newW) {
228 
229       int height = originalImage.getHeight();
230 
231       float scaleWidth = ((float) newW) / width;
232 
233       float scaleHeight = scaleWidth;
234       
235       CrashUtils.setResizeInfo(originalImage.getByteCount());
236 
237       Matrix matrix = new Matrix();
238 
239       matrix.postScale(scaleWidth, scaleHeight);
240 
241       resizedBitmap = Bitmap.createBitmap(originalImage,
242                                           0,
243                                           0,
244                                           width,
245                                           height,
246                                           matrix,
247                                           true);
248       CrashUtils.setResizeInfo(-1);
249     } else
250       return originalImage;
251     return resizedBitmap;
252 
253   }
254 
255   public static File reziseFileImage(File file) {
256     try {
257       String parentPath = Environment.getExternalStorageDirectory() + "/eXo/";
258       Bitmap bitmap = shrinkBitmap(file.getPath(), IMAGE_WIDTH, IMAGE_HEIGH);
259       bitmap = ExoDocumentUtils.rotateBitmapToNormal(file.getAbsolutePath(), bitmap);
260       ByteArrayOutputStream output = new ByteArrayOutputStream();
261       String ext = getExtension(file.getName());
262       if ("jpg".equalsIgnoreCase(ext) || "jpeg".equalsIgnoreCase(ext)) {
263         bitmap.compress(CompressFormat.JPEG, IMAGE_QUALITY, output);
264         ext = "." + ext;
265       } else {
266         bitmap.compress(CompressFormat.PNG, IMAGE_QUALITY, output);
267         ext = ".png";
268       }
269       File tempFile = new File(parentPath + TEMP_FILE_NAME + ext);
270       FileOutputStream out = new FileOutputStream(tempFile);
271       output.writeTo(out);
272       return tempFile;
273     } catch (IOException e) {
274       if (Log.LOGD)
275         Log.d(PhotoUtils.class.getSimpleName(), e.getMessage(), Log.getStackTraceString(e));
276       return null;
277     }
278 
279   }
280 
281   public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
282     try {
283 
284       bitmap = resizeImage(bitmap, ExoConstants.AVATAR_DEFAULT_SIZE);
285       int width = bitmap.getWidth();
286       int heigth = bitmap.getHeight();
287       Bitmap output = Bitmap.createBitmap(width, heigth, Config.ARGB_8888);
288       Canvas canvas = new Canvas(output);
289 
290       final int color = 0xff424242;
291       final Paint paint = new Paint();
292       final Rect rect = new Rect(0, 0, width, heigth);
293       final RectF rectF = new RectF(rect);
294       final float roundPx = pixels;
295 
296       paint.setAntiAlias(true);
297       canvas.drawARGB(0, 0, 0, 0);
298       paint.setColor(color);
299       canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
300       paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
301       canvas.drawBitmap(bitmap, rect, rect, paint);
302       bitmap.recycle();
303       return output;
304     } catch (OutOfMemoryError e) {
305       if (Log.LOGD)
306         Log.d(PhotoUtils.class.getSimpleName(), e.getMessage(), Log.getStackTraceString(e));
307       return null;
308     }
309   }
310 
311   /*
312    * This method for getting the image url which return from Intent.ACTION_PICK
313    */
314   public static String getFileFromUri(Uri uri, Activity activity) {
315     String filePath = null;
316     String[] projection = { MediaStore.Images.ImageColumns.DATA /* col1 */ };
317     Cursor c = activity.managedQuery(uri, projection, null, null, null);
318     if (c != null && c.moveToFirst()) {
319       int columnIndex = c.getColumnIndex(MediaColumns.DATA);
320       filePath = c.getString(columnIndex);
321     }
322 
323     return filePath;
324   }
325 
326   public static String downloadFile(String url, String name) {
327     File file = null;
328     HttpParams httpParameters = new BasicHttpParams();
329     HttpConnectionParams.setConnectionTimeout(httpParameters, 30000);
330     HttpConnectionParams.setSoTimeout(httpParameters, 30000);
331     HttpConnectionParams.setTcpNoDelay(httpParameters, true);
332 
333     DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
334     HttpGet httpGet = new HttpGet(url);
335     try {
336       HttpResponse response = httpClient.execute(httpGet);
337       HttpEntity entity = response.getEntity();
338       if (entity != null) {
339         InputStream is = entity.getContent();
340         String parentPath = Environment.getExternalStorageDirectory() + "/eXo/";
341         file = new File(parentPath + name);
342         OutputStream out = new FileOutputStream(file);
343         byte buf[] = new byte[1024];
344         int len;
345         while ((len = is.read(buf)) > 0)
346           out.write(buf, 0, len);
347         out.close();
348         is.close();
349       }
350 
351     } catch (ClientProtocolException e) {
352       if (Log.LOGD)
353         Log.d(PhotoUtils.class.getSimpleName(), e.getMessage(), Log.getStackTraceString(e));
354       return null;
355     } catch (IOException e) {
356       if (Log.LOGD)
357         Log.d(PhotoUtils.class.getSimpleName(), e.getMessage(), Log.getStackTraceString(e));
358       return null;
359     } finally {
360       httpClient.getConnectionManager().shutdown();
361     }
362 
363     return file.getAbsolutePath();
364   }
365 
366   /*
367    * This method for getting the image url which return from Intent.ACTION_PICK
368    * include extra photos (from Picasa, etc...)
369    */
370   public static String extractFilenameFromUri(Uri uri, Activity activity) {
371 
372     String filePath = null;
373     String[] projection = { MediaStore.Images.ImageColumns.DATA, MediaColumns.DISPLAY_NAME };
374 
375     Cursor cursor = activity.managedQuery(uri, projection, null, null, null);
376     if (cursor != null && cursor.moveToFirst()) {
377       int columnIndex = cursor.getColumnIndex(MediaColumns.DATA);
378       if (columnIndex != -1) {
379 
380         // regular processing for gallery files
381         filePath = cursor.getString(columnIndex);
382       } else {
383         Log.i("PHOTO_PICKER", "Get image from Picasa Album");
384         // this is for get image from other provider (exp. Picasa ...)
385         columnIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME);
386         if (columnIndex != -1) {
387           try {
388             String name = cursor.getString(columnIndex);
389             Log.i("PHOTO_PICKER", "Image Name: " + name);
390             final InputStream is = activity.getContentResolver().openInputStream(uri);
391             String parentPath = Environment.getExternalStorageDirectory() + "/eXo/";
392             File file = new File(parentPath + name);
393             OutputStream out = new FileOutputStream(file);
394             byte buf[] = new byte[1024];
395             int len;
396             while ((len = is.read(buf)) > 0)
397               out.write(buf, 0, len);
398             out.close();
399             is.close();
400             filePath = file.getAbsolutePath();
401           } catch (FileNotFoundException e) {
402             Log.e("PHOTO_PICKER", "could not find the path");
403             return null;
404           } catch (IOException e) {
405             Log.e("PHOTO_PICKER", "error in write file to sdcard");
406             return null;
407           }
408         }
409       }
410     }
411     return filePath;
412   }
413 
414   /*
415    * Resize the image bitmap with the maximum size is 1/4 of the screen width
416    */
417   public static Bitmap resizeImageBitmap(Context context, Bitmap bm) {
418     DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
419     int widthScreen = displayMetrics.widthPixels;
420     // the fixed size is 1/4 the screen width
421     int fixedSize = widthScreen / 4;
422     // the minimum size is 1/9 the screen width
423     int minSize = widthScreen / 9;
424 
425     // get the real size of image
426     int scaledWidth = bm.getWidth();
427     int scaledHeight = bm.getHeight();
428 
429     int height = 0;
430     int width = 0;
431     // set the minimum size
432     if (scaledHeight <= minSize) {
433       scaledHeight = minSize;
434     }
435     if (scaledWidth <= minSize) {
436       scaledWidth = minSize;
437     }
438 
439     // resize the image
440     if (scaledWidth > scaledHeight) {
441       width = fixedSize;
442       height = (width * scaledHeight) / scaledWidth;
443     } else if (scaledWidth < scaledHeight) {
444       height = fixedSize;
445       width = (height * scaledWidth) / scaledHeight;
446     } else {
447       width = height = fixedSize;
448     }
449 
450     return Bitmap.createScaledBitmap(bm, width, height, true /* filter */);
451   }
452 
453   public static void copyStream(InputStream is, OutputStream os) throws IOException {
454     final int buffer_size = 1024;
455     byte[] bytes = new byte[buffer_size];
456     int count;
457     while ((count = is.read(bytes, 0, buffer_size)) != -1) {
458       os.write(bytes, 0, count);
459     }
460   }
461 
462   /**
463    * Make radial gradient bitmap
464    */
465   public static Bitmap makeRadGrad(int width, int height) {
466     RadialGradient gradient = new RadialGradient(width / 2,
467                                                  height / 2,
468                                                  width / 2,
469                                                  0x8F8F8F8F,
470                                                  0x1C1C1C1C,
471                                                  android.graphics.Shader.TileMode.CLAMP);
472     Paint p = new Paint();
473     p.setDither(true);
474     p.setShader(gradient);
475 
476     Bitmap bitmap = Bitmap.createBitmap(width, height, Config.RGB_565);
477     Canvas c = new Canvas(bitmap);
478     c.drawOval(new RectF(0, 0, width, height), p);
479 
480     return bitmap;
481   }
482 }