2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.cooliris.media;
20 import android.app.ProgressDialog;
21 import android.content.ActivityNotFoundException;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.graphics.Bitmap;
26 import android.graphics.Canvas;
27 import android.graphics.Matrix;
28 import android.graphics.Rect;
29 import android.net.Uri;
30 import android.os.Handler;
31 import android.os.ParcelFileDescriptor;
32 import android.util.Log;
33 import android.webkit.MimeTypeMap;
35 import java.io.Closeable;
38 * Collection of utility functions used in this package.
41 private static final String TAG = "db.Util";
42 private static final String MAPS_PACKAGE_NAME =
43 "com.google.android.apps.maps";
44 private static final String MAPS_CLASS_NAME =
45 "com.google.android.maps.MapsActivity";
51 // Rotates the bitmap by the specified degree.
52 // If a new bitmap is created, the original bitmap is recycled.
53 public static Bitmap rotate(Bitmap b, int degrees) {
54 if (degrees != 0 && b != null) {
55 Matrix m = new Matrix();
57 (float) b.getWidth() / 2, (float) b.getHeight() / 2);
59 Bitmap b2 = Bitmap.createBitmap(
60 b, 0, 0, b.getWidth(), b.getHeight(), m, true);
65 } catch (OutOfMemoryError ex) {
66 // We have no memory to rotate. Return the original bitmap.
72 public static Bitmap transform(Matrix scaler,
77 int deltaX = source.getWidth() - targetWidth;
78 int deltaY = source.getHeight() - targetHeight;
79 if (!scaleUp && (deltaX < 0 || deltaY < 0)) {
81 * In this case the bitmap is smaller, at least in one dimension,
82 * than the target. Transform it by placing as much of the image
83 * as possible into the target and leaving the top/bottom or
84 * left/right (or both) black.
86 Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight,
87 Bitmap.Config.ARGB_8888);
88 Canvas c = new Canvas(b2);
90 int deltaXHalf = Math.max(0, deltaX / 2);
91 int deltaYHalf = Math.max(0, deltaY / 2);
95 deltaXHalf + Math.min(targetWidth, source.getWidth()),
96 deltaYHalf + Math.min(targetHeight, source.getHeight()));
97 int dstX = (targetWidth - src.width()) / 2;
98 int dstY = (targetHeight - src.height()) / 2;
103 targetHeight - dstY);
104 c.drawBitmap(source, src, dst, null);
107 float bitmapWidthF = source.getWidth();
108 float bitmapHeightF = source.getHeight();
110 float bitmapAspect = bitmapWidthF / bitmapHeightF;
111 float viewAspect = (float) targetWidth / targetHeight;
113 if (bitmapAspect > viewAspect) {
114 float scale = targetHeight / bitmapHeightF;
115 if (scale < .9F || scale > 1F) {
116 scaler.setScale(scale, scale);
121 float scale = targetWidth / bitmapWidthF;
122 if (scale < .9F || scale > 1F) {
123 scaler.setScale(scale, scale);
130 if (scaler != null) {
131 // this is used for minithumb and crop, so we want to filter here.
132 b1 = Bitmap.createBitmap(source, 0, 0,
133 source.getWidth(), source.getHeight(), scaler, true);
138 int dx1 = Math.max(0, b1.getWidth() - targetWidth);
139 int dy1 = Math.max(0, b1.getHeight() - targetHeight);
141 Bitmap b2 = Bitmap.createBitmap(
156 * Creates a centered bitmap of the desired size. Recycles the input.
159 public static Bitmap extractMiniThumb(
160 Bitmap source, int width, int height) {
161 return Util.extractMiniThumb(source, width, height, true);
164 public static Bitmap extractMiniThumb(
165 Bitmap source, int width, int height, boolean recycle) {
166 if (source == null) {
171 if (source.getWidth() < source.getHeight()) {
172 scale = width / (float) source.getWidth();
174 scale = height / (float) source.getHeight();
176 Matrix matrix = new Matrix();
177 matrix.setScale(scale, scale);
178 Bitmap miniThumbnail = transform(matrix, source, width, height, false);
180 if (recycle && miniThumbnail != source) {
183 return miniThumbnail;
187 public static <T> int indexOf(T [] array, T s) {
188 for (int i = 0; i < array.length; i++) {
189 if (array[i].equals(s)) {
196 public static void closeSilently(Closeable c) {
197 if (c == null) return;
200 } catch (Throwable t) {
205 public static void closeSilently(ParcelFileDescriptor c) {
206 if (c == null) return;
209 } catch (Throwable t) {
214 public static void Assert(boolean cond) {
216 throw new AssertionError();
220 public static boolean equals(String a, String b) {
221 // return true if both string are null or the content equals
222 return a == b || a.equals(b);
225 private static class BackgroundJob
226 extends MonitoredActivity.LifeCycleAdapter implements Runnable {
228 private final MonitoredActivity mActivity;
229 private final ProgressDialog mDialog;
230 private final Runnable mJob;
231 private final Handler mHandler;
232 private final Runnable mCleanupRunner = new Runnable() {
234 mActivity.removeLifeCycleListener(BackgroundJob.this);
235 if (mDialog.getWindow() != null) mDialog.dismiss();
239 public BackgroundJob(MonitoredActivity activity, Runnable job,
240 ProgressDialog dialog, Handler handler) {
241 mActivity = activity;
244 mActivity.addLifeCycleListener(this);
252 mHandler.post(mCleanupRunner);
258 public void onActivityDestroyed(MonitoredActivity activity) {
259 // We get here only when the onDestroyed being called before
260 // the mCleanupRunner. So, run it now and remove it from the queue
261 mCleanupRunner.run();
262 mHandler.removeCallbacks(mCleanupRunner);
266 public void onActivityStopped(MonitoredActivity activity) {
271 public void onActivityStarted(MonitoredActivity activity) {
276 public static void startBackgroundJob(MonitoredActivity activity,
277 String title, String message, Runnable job, Handler handler) {
278 // Make the progress dialog uncancelable, so that we can gurantee
279 // the thread will be done before the activity getting destroyed.
280 ProgressDialog dialog = ProgressDialog.show(
281 activity, title, message, true, false);
282 new Thread(new BackgroundJob(activity, job, dialog, handler)).start();
285 // Returns an intent which is used for "set as" menu items.
286 public static Intent createSetAsIntent(Uri uri, String mimeType) {
287 // Infer MIME type if missing for file URLs.
288 if (uri.getScheme().equals("file")) {
289 String path = uri.getPath();
290 int lastDotIndex = path.lastIndexOf('.');
291 if (lastDotIndex != -1) {
292 mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
293 uri.getPath().substring(lastDotIndex + 1).toLowerCase());
297 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
298 intent.setDataAndType(uri, mimeType);
299 intent.putExtra("mimeType", mimeType);
303 // Opens Maps application for a map with given latlong. There is a bug
304 // which crashes the Browser when opening this kind of URL. So, we open
305 // it in GMM instead. For those platforms which have no GMM installed,
306 // the default Maps application will be chosen.
309 public static void openMaps(Context context, double latitude, double longitude) {
311 // Try to open the GMM first
313 // We don't use "geo:latitude,longitude" because it only centers
314 // the MapView to the specified location, but we need a marker
315 // for further operations (routing to/from).
316 // The q=(lat, lng) syntax is suggested by geo-team.
317 String url = String.format(
318 "http://maps.google.com/maps?f=q&q=(%s,%s)", latitude, longitude);
319 ComponentName compName =
320 new ComponentName(MAPS_PACKAGE_NAME, MAPS_CLASS_NAME);
321 Intent mapsIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url))
322 .setComponent(compName);
323 context.startActivity(mapsIntent);
324 } catch (ActivityNotFoundException e) {
325 // Use the "geo intent" if no GMM is installed
326 Log.e(TAG, "GMM activity not found!", e);
327 String url = String.format("geo:%s,%s", latitude, longitude);
328 Intent mapsIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
329 context.startActivity(mapsIntent);