1bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp/* 2bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * Copyright (C) 2011 Google Inc. 3bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * Licensed to The Android Open Source Project. 4bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * 5bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * Licensed under the Apache License, Version 2.0 (the "License"); 6bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * you may not use this file except in compliance with the License. 7bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * You may obtain a copy of the License at 8bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * 9bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * http://www.apache.org/licenses/LICENSE-2.0 10bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * 11bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * Unless required by applicable law or agreed to in writing, software 12bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * distributed under the License is distributed on an "AS IS" BASIS, 13bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * See the License for the specific language governing permissions and 15bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * limitations under the License. 16bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp */ 17bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 18bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copppackage com.android.ex.photo.util; 19bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 20bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.content.ContentResolver; 21bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.graphics.Bitmap; 22bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.graphics.BitmapFactory; 239323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrookimport android.graphics.Matrix; 24bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.graphics.Point; 25bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.graphics.Rect; 26bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.net.Uri; 27bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.os.Build; 289323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrookimport android.util.DisplayMetrics; 29bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport android.util.Log; 30bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 31bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport com.android.ex.photo.PhotoViewActivity; 329323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrookimport com.android.ex.photo.util.Exif; 33bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 34237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrookimport java.io.ByteArrayInputStream; 359323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrookimport java.io.ByteArrayOutputStream; 36bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport java.io.FileNotFoundException; 37bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport java.io.IOException; 38bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport java.io.InputStream; 39bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport java.net.MalformedURLException; 40bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Coppimport java.net.URL; 41bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 429323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook 43bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp/** 44bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * Image utilities 45bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp */ 46bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copppublic class ImageUtils { 47bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp // Logging 48bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp private static final String TAG = "ImageUtils"; 49bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 50bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp /** Minimum class memory class to use full-res photos */ 51bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp private final static long MIN_NORMAL_CLASS = 32; 52bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp /** Minimum class memory class to use small photos */ 53bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp private final static long MIN_SMALL_CLASS = 24; 54bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 55bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp public static enum ImageSize { 56bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp EXTRA_SMALL, 57bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp SMALL, 58bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp NORMAL, 59bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 60bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 61bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp public static final ImageSize sUseImageSize; 62bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp static { 63bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp // On HC and beyond, assume devices are more capable 64bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp if (Build.VERSION.SDK_INT >= 11) { 65bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp sUseImageSize = ImageSize.NORMAL; 66bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } else { 67bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp if (PhotoViewActivity.sMemoryClass >= MIN_NORMAL_CLASS) { 68bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp // We have plenty of memory; use full sized photos 69bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp sUseImageSize = ImageSize.NORMAL; 70bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } else if (PhotoViewActivity.sMemoryClass >= MIN_SMALL_CLASS) { 71bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp // We have slight less memory; use smaller sized photos 72bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp sUseImageSize = ImageSize.SMALL; 73bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } else { 74bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp // We have little memory; use very small sized photos 75bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp sUseImageSize = ImageSize.EXTRA_SMALL; 76bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 77bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 78bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 79bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 80bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp /** 81bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @return true if the MimeType type is image 82bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp */ 83bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp public static boolean isImageMimeType(String mimeType) { 84bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp return mimeType != null && mimeType.startsWith("image/"); 85bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 86bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 87bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp /** 88bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * Create a bitmap from a local URI 89bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * 90bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @param resolver The ContentResolver 91bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @param uri The local URI 92bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @param maxSize The maximum size (either width or height) 93bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * 94f24e7099f9688518d705116c1b4279fc6279d3d6Mark Wei * @return The new bitmap or null 95bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp */ 96bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp public static Bitmap createLocalBitmap(ContentResolver resolver, Uri uri, int maxSize) { 97bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp // TODO: make this method not download the image for both getImageBounds and decodeStream 98bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp InputStream inputStream = null; 99bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp try { 100bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp final BitmapFactory.Options opts = new BitmapFactory.Options(); 101bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp final Point bounds = getImageBounds(resolver, uri); 102bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp inputStream = openInputStream(resolver, uri); 1037aabd796bbcb149db9ac183c1d0aec09fccd42a4Adam Copp if (bounds == null || inputStream == null) { 1047aabd796bbcb149db9ac183c1d0aec09fccd42a4Adam Copp return null; 1057aabd796bbcb149db9ac183c1d0aec09fccd42a4Adam Copp } 106bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp opts.inSampleSize = Math.max(bounds.x / maxSize, bounds.y / maxSize); 107bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 108bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp final Bitmap decodedBitmap = decodeStream(inputStream, null, opts); 109bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 110bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp // Correct thumbnail orientation as necessary 111f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein // TODO: Fix rotation if it's actually a problem 112f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein //return rotateBitmap(resolver, uri, decodedBitmap); 113f77a7eb196d16110c7b1087352b423913821ff61Andrew Sapperstein return decodedBitmap; 114bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 115bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } catch (FileNotFoundException exception) { 116bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp // Do nothing - the photo will appear to be missing 117bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } catch (IOException exception) { 118bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp // Do nothing - the photo will appear to be missing 1191f00d9d7c4beb007d491fc766f7a0c8fc4977a50The Android Open Source Project } catch (IllegalArgumentException exception) { 1201f00d9d7c4beb007d491fc766f7a0c8fc4977a50The Android Open Source Project // Do nothing - the photo will appear to be missing 121bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } finally { 122bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp try { 123bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp if (inputStream != null) { 124bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp inputStream.close(); 125bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 126bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } catch (IOException ignore) { 127bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 128bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 129bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp return null; 130bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 131bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 132bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp /** 133bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * Wrapper around {@link BitmapFactory#decodeStream(InputStream, Rect, 134bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * BitmapFactory.Options)} that returns {@code null} on {@link 135bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * OutOfMemoryError}. 136bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * 137bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @param is The input stream that holds the raw data to be decoded into a 138bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * bitmap. 139bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @param outPadding If not null, return the padding rect for the bitmap if 140bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * it exists, otherwise set padding to [-1,-1,-1,-1]. If 141bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * no bitmap is returned (null) then padding is 142bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * unchanged. 143bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @param opts null-ok; Options that control downsampling and whether the 144bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * image should be completely decoded, or just is size returned. 145bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @return The decoded bitmap, or null if the image data could not be 146bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * decoded, or, if opts is non-null, if opts requested only the 147bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * size be returned (in opts.outWidth and opts.outHeight) 148bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp */ 149bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp public static Bitmap decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts) { 1509323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook ByteArrayOutputStream out = null; 151237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook InputStream byteStream = null; 152bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp try { 1539323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook out = new ByteArrayOutputStream(); 1549323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook final byte[] buffer = new byte[4096]; 1559323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook int n = is.read(buffer); 1569323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook while (n >= 0) { 1579323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook out.write(buffer, 0, n); 1589323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook n = is.read(buffer); 1599323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook } 160237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook 1619323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook final byte[] bitmapBytes = out.toByteArray(); 1629323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook 1639323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook // Determine the orientation for this image 1649323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook final int orientation = Exif.getOrientation(bitmapBytes); 165237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook 166237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook // Create an InputStream from this byte array 167237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook byteStream = new ByteArrayInputStream(bitmapBytes); 168237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook 169237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook final Bitmap originalBitmap = BitmapFactory.decodeStream(byteStream, outPadding, opts); 1709323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook 1719323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook if (originalBitmap != null && orientation != 0) { 1729323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook final Matrix matrix = new Matrix(); 1739323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook matrix.postRotate(orientation); 1749323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook return Bitmap.createBitmap(originalBitmap, 0, 0, originalBitmap.getWidth(), 1759323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook originalBitmap.getHeight(), matrix, true); 1769323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook } 1779323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook return originalBitmap; 178bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } catch (OutOfMemoryError oome) { 179bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp Log.e(TAG, "ImageUtils#decodeStream(InputStream, Rect, Options) threw an OOME", oome); 180bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp return null; 1819323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook } catch (IOException ioe) { 1829323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook Log.e(TAG, "ImageUtils#decodeStream(InputStream, Rect, Options) threw an IOE", ioe); 1839323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook return null; 1849323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook } finally { 1859323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook if (out != null) { 1869323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook try { 1879323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook out.close(); 1889323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook } catch (IOException e) { 1899323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook // Do nothing 1909323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook } 1919323b13fc9bc79ce38ce7c851a2aa894ab988ed0Paul Westbrook } 192237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook if (byteStream != null) { 193237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook try { 194237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook byteStream.close(); 195237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook } catch (IOException e) { 196237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook // Do nothing 197237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook } 198237ded1a59b1fc148a3ffcf78d6f9d34af5c170cPaul Westbrook } 199bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 200bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 201bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 202bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp /** 203bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * Gets the image bounds 204bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * 205bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @param resolver The ContentResolver 206bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @param uri The uri 207bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * 208bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp * @return The image bounds 209bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp */ 210bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp private static Point getImageBounds(ContentResolver resolver, Uri uri) 211bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp throws IOException { 212bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp final BitmapFactory.Options opts = new BitmapFactory.Options(); 213bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp InputStream inputStream = null; 214bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp String scheme = uri.getScheme(); 215bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp try { 216bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp opts.inJustDecodeBounds = true; 217bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp inputStream = openInputStream(resolver, uri); 2187aabd796bbcb149db9ac183c1d0aec09fccd42a4Adam Copp if (inputStream == null) { 2197aabd796bbcb149db9ac183c1d0aec09fccd42a4Adam Copp return null; 2207aabd796bbcb149db9ac183c1d0aec09fccd42a4Adam Copp } 221bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp decodeStream(inputStream, null, opts); 222bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 223bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp return new Point(opts.outWidth, opts.outHeight); 224bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } finally { 225bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp try { 226bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp if (inputStream != null) { 227bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp inputStream.close(); 228bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 229bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } catch (IOException ignore) { 230bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 231bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 232bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 233bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp 234bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp private static InputStream openInputStream(ContentResolver resolver, Uri uri) throws 235bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp FileNotFoundException { 236bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp String scheme = uri.getScheme(); 237bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp if("http".equals(scheme) || "https".equals(scheme)) { 238bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp try { 239bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp return new URL(uri.toString()).openStream(); 240bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } catch (MalformedURLException e) { 241bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp // Fall-back to the previous behaviour, just in case 242bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp Log.w(TAG, "Could not convert the uri to url: " + uri.toString()); 243bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp return resolver.openInputStream(uri); 244bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } catch (IOException e) { 245bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp Log.w(TAG, "Could not open input stream for uri: " + uri.toString()); 246bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp return null; 247bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 248bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 249bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp return resolver.openInputStream(uri); 250bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp } 251bd8b47b147f29f196f37d66ccb561d40414ab5b6Adam Copp} 252