• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.BufferedInputStream;
20 import java.io.BufferedOutputStream;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.net.URI;
28 import java.net.URISyntaxException;
29 import java.net.URL;
30 import java.net.URLConnection;
31 
32 import org.apache.http.HttpEntity;
33 import org.apache.http.HttpResponse;
34 import org.apache.http.client.methods.HttpGet;
35 import org.apache.http.client.methods.HttpUriRequest;
36 import org.apache.http.client.params.HttpClientParams;
37 import org.apache.http.conn.ClientConnectionManager;
38 import org.apache.http.conn.scheme.PlainSocketFactory;
39 import org.apache.http.conn.scheme.Scheme;
40 import org.apache.http.conn.scheme.SchemeRegistry;
41 import org.apache.http.impl.client.DefaultHttpClient;
42 import org.apache.http.impl.conn.*;
43 import org.apache.http.params.BasicHttpParams;
44 import org.apache.http.params.HttpConnectionParams;
45 import org.apache.http.params.HttpParams;
46 import org.apache.http.params.HttpProtocolParams;
47 
48 import android.content.ContentResolver;
49 import android.content.Context;
50 import android.graphics.Bitmap;
51 import android.graphics.BitmapFactory;
52 import android.net.Uri;
53 import android.util.Log;
54 
55 import com.cooliris.cache.CacheService;
56 
57 public class UriTexture extends Texture {
58     public static final int MAX_RESOLUTION = 1024;
59     private static final String TAG = "UriTexture";
60     protected String mUri;
61     protected long mCacheId;
62     private static final int MAX_RESOLUTION_A = MAX_RESOLUTION;
63     private static final int MAX_RESOLUTION_B = MAX_RESOLUTION;
64     public static final String URI_CACHE = CacheService.getCachePath("hires-image-cache");
65     private static final String USER_AGENT = "Cooliris-ImageDownload";
66     private static final int CONNECTION_TIMEOUT = 20000; // ms.
67     public static final HttpParams HTTP_PARAMS;
68     public static final SchemeRegistry SCHEME_REGISTRY;
69     static {
70         // Prepare HTTP parameters.
71         HttpParams params = new BasicHttpParams();
HttpConnectionParams.setStaleCheckingEnabled(params, false)72         HttpConnectionParams.setStaleCheckingEnabled(params, false);
HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT)73         HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, CONNECTION_TIMEOUT)74         HttpConnectionParams.setSoTimeout(params, CONNECTION_TIMEOUT);
HttpClientParams.setRedirecting(params, true)75         HttpClientParams.setRedirecting(params, true);
HttpProtocolParams.setUserAgent(params, USER_AGENT)76         HttpProtocolParams.setUserAgent(params, USER_AGENT);
77         HTTP_PARAMS = params;
78 
79         // Register HTTP protocol.
80         SCHEME_REGISTRY = new SchemeRegistry();
SCHEME_REGISTRY.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80))81         SCHEME_REGISTRY.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
82     }
83 
84     private SingleClientConnManager mConnectionManager;
85 
86     static {
87         File uri_cache = new File(URI_CACHE);
uri_cache.mkdirs()88         uri_cache.mkdirs();
89     }
90 
UriTexture(String imageUri)91     public UriTexture(String imageUri) {
92         mUri = imageUri;
93     }
94 
setCacheId(long id)95     public void setCacheId(long id) {
96         mCacheId = id;
97     }
98 
computeSampleSize(InputStream stream, int maxResolutionX, int maxResolutionY)99     private static int computeSampleSize(InputStream stream, int maxResolutionX,
100         int maxResolutionY) {
101         BitmapFactory.Options options = new BitmapFactory.Options();
102         options.inJustDecodeBounds = true;
103         BitmapFactory.decodeStream(stream, null, options);
104         int maxNumOfPixels = maxResolutionX * maxResolutionY;
105         int minSideLength = Math.min(maxResolutionX, maxResolutionY) / 2;
106         return Utils.computeSampleSize(options, minSideLength, maxNumOfPixels);
107     }
108 
createFromUri(Context context, String uri, int maxResolutionX, int maxResolutionY, long cacheId, ClientConnectionManager connectionManager)109     public static final Bitmap createFromUri(Context context, String uri, int maxResolutionX, int maxResolutionY, long cacheId,
110             ClientConnectionManager connectionManager) throws IOException, URISyntaxException, OutOfMemoryError {
111         final BitmapFactory.Options options = new BitmapFactory.Options();
112         options.inScaled = false;
113         options.inPreferredConfig = Bitmap.Config.RGB_565;
114         options.inDither = true;
115         long crc64 = 0;
116         Bitmap bitmap = null;
117         if (uri.startsWith(ContentResolver.SCHEME_CONTENT)) {
118             // We need the filepath for the given content uri
119             crc64 = cacheId;
120         } else {
121             crc64 = Utils.Crc64Long(uri);
122         }
123         bitmap = createFromCache(crc64, maxResolutionX);
124         if (bitmap != null) {
125             return bitmap;
126         }
127         final boolean local = uri.startsWith(ContentResolver.SCHEME_CONTENT) || uri.startsWith("file://");
128 
129         // Get the input stream for computing the sample size.
130         BufferedInputStream bufferedInput = null;
131         if (uri.startsWith(ContentResolver.SCHEME_CONTENT) ||
132                 uri.startsWith(ContentResolver.SCHEME_FILE)) {
133             // Get the stream from a local file.
134             bufferedInput = new BufferedInputStream(context.getContentResolver()
135                     .openInputStream(Uri.parse(uri)), 16384);
136         } else {
137             // Get the stream from a remote URL.
138             bufferedInput = createInputStreamFromRemoteUrl(uri, connectionManager);
139         }
140 
141         // Compute the sample size, i.e., not decoding real pixels.
142         if (bufferedInput != null) {
143             options.inSampleSize = computeSampleSize(bufferedInput, maxResolutionX, maxResolutionY);
144         } else {
145             return null;
146         }
147 
148         // Get the input stream again for decoding it to a bitmap.
149         bufferedInput = null;
150         if (uri.startsWith(ContentResolver.SCHEME_CONTENT) ||
151                 uri.startsWith(ContentResolver.SCHEME_FILE)) {
152             // Get the stream from a local file.
153             bufferedInput = new BufferedInputStream(context.getContentResolver()
154                     .openInputStream(Uri.parse(uri)), 16384);
155         } else {
156             // Get the stream from a remote URL.
157             bufferedInput = createInputStreamFromRemoteUrl(uri, connectionManager);
158         }
159 
160         // Decode bufferedInput to a bitmap.
161         if (bufferedInput != null) {
162             options.inDither = false;
163             options.inJustDecodeBounds = false;
164             Thread timeoutThread = new Thread("BitmapTimeoutThread") {
165                 public void run() {
166                     try {
167                         Thread.sleep(6000);
168                         options.requestCancelDecode();
169                     } catch (InterruptedException e) {
170                     }
171                 }
172             };
173             timeoutThread.start();
174 
175             bitmap = BitmapFactory.decodeStream(bufferedInput, null, options);
176         }
177 
178         if ((options.inSampleSize > 1 || !local) && bitmap != null) {
179             writeToCache(crc64, bitmap, maxResolutionX / options.inSampleSize);
180         }
181         return bitmap;
182     }
183 
createInputStreamFromRemoteUrl( String uri, ClientConnectionManager connectionManager)184     private static final BufferedInputStream createInputStreamFromRemoteUrl(
185             String uri, ClientConnectionManager connectionManager) {
186         InputStream contentInput = null;
187         if (connectionManager == null) {
188             try {
189                 URL url = new URI(uri).toURL();
190                 URLConnection conn = url.openConnection();
191                 conn.connect();
192                 contentInput = conn.getInputStream();
193             } catch (Exception e) {
194                 Log.w(TAG, "Request failed: " + uri);
195                 e.printStackTrace();
196                 return null;
197             }
198         } else {
199             // We create a cancelable http request from the client
200             final DefaultHttpClient mHttpClient = new DefaultHttpClient(connectionManager, HTTP_PARAMS);
201             HttpUriRequest request = new HttpGet(uri);
202             // Execute the HTTP request.
203             HttpResponse httpResponse = null;
204             try {
205                 httpResponse = mHttpClient.execute(request);
206                 HttpEntity entity = httpResponse.getEntity();
207                 if (entity != null) {
208                     // Wrap the entity input stream in a GZIP decoder if
209                     // necessary.
210                     contentInput = entity.getContent();
211                 }
212             } catch (Exception e) {
213                 Log.w(TAG, "Request failed: " + request.getURI());
214                 return null;
215             }
216         }
217         if (contentInput != null) {
218             return new BufferedInputStream(contentInput, 4096);
219         } else {
220             return null;
221         }
222     }
223 
224     @Override
load(RenderView view)225     protected Bitmap load(RenderView view) {
226         Bitmap bitmap = null;
227         if (mUri == null)
228             return bitmap;
229         try {
230             if (mUri.startsWith("http://")) {
231                 if (!isCached(Utils.Crc64Long(mUri), MAX_RESOLUTION_A)) {
232                     mConnectionManager = new SingleClientConnManager(HTTP_PARAMS, SCHEME_REGISTRY);
233                 }
234             }
235             bitmap = createFromUri(view.getContext(), mUri, MAX_RESOLUTION_A, MAX_RESOLUTION_B, mCacheId, mConnectionManager);
236         } catch (Exception e2) {
237             Log.e(TAG, "Unable to load image from URI " + mUri);
238             e2.printStackTrace();
239         }
240         return bitmap;
241     }
242 
createFilePathFromCrc64(long crc64, int maxResolution)243     public static final String createFilePathFromCrc64(long crc64, int maxResolution) {
244         return URI_CACHE + crc64 + "_" + maxResolution + ".cache";
245     }
246 
isCached(long crc64, int maxResolution)247     public static boolean isCached(long crc64, int maxResolution) {
248         String file = null;
249         if (crc64 != 0) {
250             file = createFilePathFromCrc64(crc64, maxResolution);
251             try {
252                 new FileInputStream(file);
253                 return true;
254             } catch (FileNotFoundException e) {
255                 return false;
256             }
257         }
258         return false;
259     }
260 
createFromCache(long crc64, int maxResolution)261     public static Bitmap createFromCache(long crc64, int maxResolution) {
262         try {
263             String file = null;
264             Bitmap bitmap = null;
265             final BitmapFactory.Options options = new BitmapFactory.Options();
266             options.inScaled = false;
267             options.inPreferredConfig = Bitmap.Config.RGB_565;
268             options.inDither = true;
269             if (crc64 != 0) {
270                 file = createFilePathFromCrc64(crc64, maxResolution);
271                 bitmap = BitmapFactory.decodeFile(file, options);
272             }
273             return bitmap;
274         } catch (Exception e) {
275             return null;
276         }
277     }
278 
writeHttpDataInDirectory(Context context, String uri, String path)279     public static String writeHttpDataInDirectory(Context context, String uri, String path) {
280         long crc64 = Utils.Crc64Long(uri);
281         if (!isCached(crc64, 1024)) {
282             Bitmap bitmap;
283             try {
284                 bitmap = UriTexture.createFromUri(context, uri, 1024, 1024, crc64, null);
285             } catch (OutOfMemoryError e) {
286                 return null;
287             } catch (IOException e) {
288                 return null;
289             } catch (URISyntaxException e) {
290                 return null;
291             }
292             bitmap.recycle();
293         }
294         String fileString = createFilePathFromCrc64(crc64, 1024);
295         try {
296             File file = new File(fileString);
297             if (file.exists()) {
298                 // We write a copy of this file
299                 String newPath = path + (path.endsWith("/") ? "" : "/") + crc64 + ".jpg";
300                 File newFile = new File(newPath);
301                 Utils.Copy(file, newFile);
302                 return newPath;
303             }
304             return null;
305         } catch (Exception e) {
306             return null;
307         }
308     }
309 
writeToCache(long crc64, Bitmap bitmap, int maxResolution)310     public static void writeToCache(long crc64, Bitmap bitmap, int maxResolution) {
311         String file = createFilePathFromCrc64(crc64, maxResolution);
312         if (bitmap != null && file != null && crc64 != 0) {
313             try {
314                 File fileC = new File(file);
315                 fileC.createNewFile();
316                 final FileOutputStream fos = new FileOutputStream(fileC);
317                 final BufferedOutputStream bos = new BufferedOutputStream(fos, 16384);
318                 bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
319                 bos.flush();
320                 bos.close();
321                 fos.close();
322             } catch (Exception e) {
323 
324             }
325         }
326     }
327 
invalidateCache(long crc64, int maxResolution)328     public static void invalidateCache(long crc64, int maxResolution) {
329         String file = createFilePathFromCrc64(crc64, maxResolution);
330         if (file != null && crc64 != 0) {
331             try {
332                 File fileC = new File(file);
333                 fileC.delete();
334             } catch (Exception e) {
335 
336             }
337         }
338 
339     }
340 
341     @Override
finalize()342     public void finalize() {
343         if (mConnectionManager != null) {
344             mConnectionManager.shutdown();
345         }
346     }
347 }
348