From b50b5cbfbc0a67db6fc43373363b10381c9c61a3 Mon Sep 17 00:00:00 2001 From: Angus Kong Date: Fri, 9 Aug 2013 14:55:20 -0700 Subject: Clean up Gallery codes. bug:10263696 Change-Id: I3a16dba3aabe52b8103a2c591cfa39907265a263 --- .../com/android/gallery3d/common/ApiHelper.java | 234 ----- .../android/gallery3d/common/AsyncTaskUtil.java | 66 -- .../com/android/gallery3d/common/BitmapUtils.java | 260 ------ .../com/android/gallery3d/common/BlobCache.java | 668 -------------- .../src/com/android/gallery3d/common/Entry.java | 58 -- .../com/android/gallery3d/common/EntrySchema.java | 542 ------------ .../com/android/gallery3d/common/FileCache.java | 312 ------- .../com/android/gallery3d/common/Fingerprint.java | 187 ---- .../gallery3d/common/HttpClientFactory.java | 133 --- .../src/com/android/gallery3d/common/LruCache.java | 90 -- .../com/android/gallery3d/common/OverScroller.java | 958 --------------------- .../src/com/android/gallery3d/common/Scroller.java | 507 ----------- .../src/com/android/gallery3d/common/Utils.java | 340 -------- .../gallery3d/jpegstream/JPEGInputStream.java | 193 ----- .../gallery3d/jpegstream/JPEGOutputStream.java | 144 ---- .../android/gallery3d/jpegstream/JpegConfig.java | 32 - .../android/gallery3d/jpegstream/StreamUtils.java | 80 -- .../src/com/android/gallery3d/util/Future.java | 35 - .../com/android/gallery3d/util/FutureListener.java | 21 - .../gallery3d/util/PriorityThreadFactory.java | 49 -- .../src/com/android/gallery3d/util/ThreadPool.java | 268 ------ 21 files changed, 5177 deletions(-) delete mode 100644 gallerycommon/src/com/android/gallery3d/common/ApiHelper.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/AsyncTaskUtil.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/BitmapUtils.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/BlobCache.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/Entry.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/EntrySchema.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/FileCache.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/Fingerprint.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/HttpClientFactory.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/LruCache.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/OverScroller.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/Scroller.java delete mode 100644 gallerycommon/src/com/android/gallery3d/common/Utils.java delete mode 100644 gallerycommon/src/com/android/gallery3d/jpegstream/JPEGInputStream.java delete mode 100644 gallerycommon/src/com/android/gallery3d/jpegstream/JPEGOutputStream.java delete mode 100644 gallerycommon/src/com/android/gallery3d/jpegstream/JpegConfig.java delete mode 100644 gallerycommon/src/com/android/gallery3d/jpegstream/StreamUtils.java delete mode 100644 gallerycommon/src/com/android/gallery3d/util/Future.java delete mode 100644 gallerycommon/src/com/android/gallery3d/util/FutureListener.java delete mode 100644 gallerycommon/src/com/android/gallery3d/util/PriorityThreadFactory.java delete mode 100644 gallerycommon/src/com/android/gallery3d/util/ThreadPool.java (limited to 'gallerycommon/src/com/android/gallery3d') diff --git a/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java b/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java deleted file mode 100644 index f4de5c9ff..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/ApiHelper.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import android.app.admin.DevicePolicyManager; -import android.content.ComponentName; -import android.hardware.Camera; -import android.os.Build; -import android.provider.MediaStore.MediaColumns; -import android.view.View; -import android.view.WindowManager; - -import java.lang.reflect.Field; - -public class ApiHelper { - public static interface VERSION_CODES { - // These value are copied from Build.VERSION_CODES - public static final int GINGERBREAD_MR1 = 10; - public static final int HONEYCOMB = 11; - public static final int HONEYCOMB_MR1 = 12; - public static final int HONEYCOMB_MR2 = 13; - public static final int ICE_CREAM_SANDWICH = 14; - public static final int ICE_CREAM_SANDWICH_MR1 = 15; - public static final int JELLY_BEAN = 16; - public static final int JELLY_BEAN_MR1 = 17; - public static final int JELLY_BEAN_MR2 = 18; - } - - public static final boolean AT_LEAST_16 = Build.VERSION.SDK_INT >= 16; - - public static final boolean USE_888_PIXEL_FORMAT = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean ENABLE_PHOTO_EDITOR = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_VIEW_SYSTEM_UI_FLAG_LAYOUT_STABLE = - hasField(View.class, "SYSTEM_UI_FLAG_LAYOUT_STABLE"); - - public static final boolean HAS_VIEW_SYSTEM_UI_FLAG_HIDE_NAVIGATION = - hasField(View.class, "SYSTEM_UI_FLAG_HIDE_NAVIGATION"); - - public static final boolean HAS_MEDIA_COLUMNS_WIDTH_AND_HEIGHT = - hasField(MediaColumns.class, "WIDTH"); - - public static final boolean HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_REUSING_BITMAP_IN_BITMAP_FACTORY = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_SET_BEAM_PUSH_URIS = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_SET_DEFALT_BUFFER_SIZE = hasMethod( - "android.graphics.SurfaceTexture", "setDefaultBufferSize", - int.class, int.class); - - public static final boolean HAS_RELEASE_SURFACE_TEXTURE = hasMethod( - "android.graphics.SurfaceTexture", "release"); - - public static final boolean HAS_SURFACE_TEXTURE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_MTP = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1; - - public static final boolean HAS_AUTO_FOCUS_MOVE_CALLBACK = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_REMOTE_VIEWS_SERVICE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_INTENT_EXTRA_LOCAL_ONLY = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_SET_SYSTEM_UI_VISIBILITY = - hasMethod(View.class, "setSystemUiVisibility", int.class); - - public static final boolean HAS_FACE_DETECTION; - static { - boolean hasFaceDetection = false; - try { - Class listenerClass = Class.forName( - "android.hardware.Camera$FaceDetectionListener"); - hasFaceDetection = - hasMethod(Camera.class, "setFaceDetectionListener", listenerClass) && - hasMethod(Camera.class, "startFaceDetection") && - hasMethod(Camera.class, "stopFaceDetection") && - hasMethod(Camera.Parameters.class, "getMaxNumDetectedFaces"); - } catch (Throwable t) { - } - HAS_FACE_DETECTION = hasFaceDetection; - } - - public static final boolean HAS_GET_CAMERA_DISABLED = - hasMethod(DevicePolicyManager.class, "getCameraDisabled", ComponentName.class); - - public static final boolean HAS_MEDIA_ACTION_SOUND = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_TIME_LAPSE_RECORDING = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_ZOOM_WHEN_RECORDING = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_CAMERA_FOCUS_AREA = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_CAMERA_METERING_AREA = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_MOTION_EVENT_TRANSFORM = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_EFFECTS_RECORDING = false; - - // "Background" filter does not have "context" input port in jelly bean. - public static final boolean HAS_EFFECTS_RECORDING_CONTEXT_INPUT = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1; - - public static final boolean HAS_GET_SUPPORTED_VIDEO_SIZE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_SET_ICON_ATTRIBUTE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_MEDIA_PROVIDER_FILES_TABLE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_SURFACE_TEXTURE_RECORDING = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_ACTION_BAR = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - // Ex: View.setTranslationX. - public static final boolean HAS_VIEW_TRANSFORM_PROPERTIES = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_CAMERA_HDR = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1; - - public static final boolean HAS_OPTIONS_IN_MUTABLE = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean CAN_START_PREVIEW_IN_JPEG_CALLBACK = - Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH; - - public static final boolean HAS_VIEW_PROPERTY_ANIMATOR = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1; - - public static final boolean HAS_POST_ON_ANIMATION = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_ANNOUNCE_FOR_ACCESSIBILITY = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_OBJECT_ANIMATION = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_GLES20_REQUIRED = - Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB; - - public static final boolean HAS_ROTATION_ANIMATION = - hasField(WindowManager.LayoutParams.class, "rotationAnimation"); - - public static final boolean HAS_ORIENTATION_LOCK = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2; - - public static final boolean HAS_CANCELLATION_SIGNAL = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN; - - public static final boolean HAS_MEDIA_MUXER = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2; - - public static final boolean HAS_DISPLAY_LISTENER = - Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1; - - public static int getIntFieldIfExists(Class klass, String fieldName, - Class obj, int defaultVal) { - try { - Field f = klass.getDeclaredField(fieldName); - return f.getInt(obj); - } catch (Exception e) { - return defaultVal; - } - } - - private static boolean hasField(Class klass, String fieldName) { - try { - klass.getDeclaredField(fieldName); - return true; - } catch (NoSuchFieldException e) { - return false; - } - } - - private static boolean hasMethod(String className, String methodName, - Class... parameterTypes) { - try { - Class klass = Class.forName(className); - klass.getDeclaredMethod(methodName, parameterTypes); - return true; - } catch (Throwable th) { - return false; - } - } - - private static boolean hasMethod( - Class klass, String methodName, Class ... paramTypes) { - try { - klass.getDeclaredMethod(methodName, paramTypes); - return true; - } catch (NoSuchMethodException e) { - return false; - } - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/AsyncTaskUtil.java b/gallerycommon/src/com/android/gallery3d/common/AsyncTaskUtil.java deleted file mode 100644 index b70c4d365..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/AsyncTaskUtil.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import android.os.AsyncTask; -import android.os.Build; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.concurrent.Executor; - -/** - * Helper class to execute an AsyncTask in parallel if SDK version is 11 or newer. - */ -public class AsyncTaskUtil { - private static Method sMethodExecuteOnExecutor; - private static Executor sExecutor; - static { - if (Build.VERSION.SDK_INT >= 11) { - try { - sExecutor = (Executor) AsyncTask.class.getField("THREAD_POOL_EXECUTOR") - .get(null); - sMethodExecuteOnExecutor = AsyncTask.class.getMethod( - "executeOnExecutor", Executor.class, Object[].class); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - } - - public static void executeInParallel(AsyncTask task, Param... params) { - if (Build.VERSION.SDK_INT < 11) { - task.execute(params); - } else { - try { - sMethodExecuteOnExecutor.invoke(task, sExecutor, params); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - } - - private AsyncTaskUtil() { - } -} - diff --git a/gallerycommon/src/com/android/gallery3d/common/BitmapUtils.java b/gallerycommon/src/com/android/gallery3d/common/BitmapUtils.java deleted file mode 100644 index a671ed2b9..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/BitmapUtils.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import android.graphics.Bitmap; -import android.graphics.Bitmap.CompressFormat; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.os.Build; -import android.util.FloatMath; -import android.util.Log; - -import java.io.ByteArrayOutputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class BitmapUtils { - private static final String TAG = "BitmapUtils"; - private static final int DEFAULT_JPEG_QUALITY = 90; - public static final int UNCONSTRAINED = -1; - - private BitmapUtils(){} - - /* - * Compute the sample size as a function of minSideLength - * and maxNumOfPixels. - * minSideLength is used to specify that minimal width or height of a - * bitmap. - * maxNumOfPixels is used to specify the maximal size in pixels that is - * tolerable in terms of memory usage. - * - * The function returns a sample size based on the constraints. - * Both size and minSideLength can be passed in as UNCONSTRAINED, - * which indicates no care of the corresponding constraint. - * The functions prefers returning a sample size that - * generates a smaller bitmap, unless minSideLength = UNCONSTRAINED. - * - * Also, the function rounds up the sample size to a power of 2 or multiple - * of 8 because BitmapFactory only honors sample size this way. - * For example, BitmapFactory downsamples an image by 2 even though the - * request is 3. So we round up the sample size to avoid OOM. - */ - public static int computeSampleSize(int width, int height, - int minSideLength, int maxNumOfPixels) { - int initialSize = computeInitialSampleSize( - width, height, minSideLength, maxNumOfPixels); - - return initialSize <= 8 - ? Utils.nextPowerOf2(initialSize) - : (initialSize + 7) / 8 * 8; - } - - private static int computeInitialSampleSize(int w, int h, - int minSideLength, int maxNumOfPixels) { - if (maxNumOfPixels == UNCONSTRAINED - && minSideLength == UNCONSTRAINED) return 1; - - int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : - (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels)); - - if (minSideLength == UNCONSTRAINED) { - return lowerBound; - } else { - int sampleSize = Math.min(w / minSideLength, h / minSideLength); - return Math.max(sampleSize, lowerBound); - } - } - - // This computes a sample size which makes the longer side at least - // minSideLength long. If that's not possible, return 1. - public static int computeSampleSizeLarger(int w, int h, - int minSideLength) { - int initialSize = Math.max(w / minSideLength, h / minSideLength); - if (initialSize <= 1) return 1; - - return initialSize <= 8 - ? Utils.prevPowerOf2(initialSize) - : initialSize / 8 * 8; - } - - // Find the min x that 1 / x >= scale - public static int computeSampleSizeLarger(float scale) { - int initialSize = (int) FloatMath.floor(1f / scale); - if (initialSize <= 1) return 1; - - return initialSize <= 8 - ? Utils.prevPowerOf2(initialSize) - : initialSize / 8 * 8; - } - - // Find the max x that 1 / x <= scale. - public static int computeSampleSize(float scale) { - Utils.assertTrue(scale > 0); - int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale)); - return initialSize <= 8 - ? Utils.nextPowerOf2(initialSize) - : (initialSize + 7) / 8 * 8; - } - - public static Bitmap resizeBitmapByScale( - Bitmap bitmap, float scale, boolean recycle) { - int width = Math.round(bitmap.getWidth() * scale); - int height = Math.round(bitmap.getHeight() * scale); - if (width == bitmap.getWidth() - && height == bitmap.getHeight()) return bitmap; - Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap)); - Canvas canvas = new Canvas(target); - canvas.scale(scale, scale); - Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); - canvas.drawBitmap(bitmap, 0, 0, paint); - if (recycle) bitmap.recycle(); - return target; - } - - private static Bitmap.Config getConfig(Bitmap bitmap) { - Bitmap.Config config = bitmap.getConfig(); - if (config == null) { - config = Bitmap.Config.ARGB_8888; - } - return config; - } - - public static Bitmap resizeDownBySideLength( - Bitmap bitmap, int maxLength, boolean recycle) { - int srcWidth = bitmap.getWidth(); - int srcHeight = bitmap.getHeight(); - float scale = Math.min( - (float) maxLength / srcWidth, (float) maxLength / srcHeight); - if (scale >= 1.0f) return bitmap; - return resizeBitmapByScale(bitmap, scale, recycle); - } - - public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) { - int w = bitmap.getWidth(); - int h = bitmap.getHeight(); - if (w == size && h == size) return bitmap; - - // scale the image so that the shorter side equals to the target; - // the longer side will be center-cropped. - float scale = (float) size / Math.min(w, h); - - Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap)); - int width = Math.round(scale * bitmap.getWidth()); - int height = Math.round(scale * bitmap.getHeight()); - Canvas canvas = new Canvas(target); - canvas.translate((size - width) / 2f, (size - height) / 2f); - canvas.scale(scale, scale); - Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); - canvas.drawBitmap(bitmap, 0, 0, paint); - if (recycle) bitmap.recycle(); - return target; - } - - public static void recycleSilently(Bitmap bitmap) { - if (bitmap == null) return; - try { - bitmap.recycle(); - } catch (Throwable t) { - Log.w(TAG, "unable recycle bitmap", t); - } - } - - public static Bitmap rotateBitmap(Bitmap source, int rotation, boolean recycle) { - if (rotation == 0) return source; - int w = source.getWidth(); - int h = source.getHeight(); - Matrix m = new Matrix(); - m.postRotate(rotation); - Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, w, h, m, true); - if (recycle) source.recycle(); - return bitmap; - } - - public static Bitmap createVideoThumbnail(String filePath) { - // MediaMetadataRetriever is available on API Level 8 - // but is hidden until API Level 10 - Class clazz = null; - Object instance = null; - try { - clazz = Class.forName("android.media.MediaMetadataRetriever"); - instance = clazz.newInstance(); - - Method method = clazz.getMethod("setDataSource", String.class); - method.invoke(instance, filePath); - - // The method name changes between API Level 9 and 10. - if (Build.VERSION.SDK_INT <= 9) { - return (Bitmap) clazz.getMethod("captureFrame").invoke(instance); - } else { - byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance); - if (data != null) { - Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); - if (bitmap != null) return bitmap; - } - return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance); - } - } catch (IllegalArgumentException ex) { - // Assume this is a corrupt video file - } catch (RuntimeException ex) { - // Assume this is a corrupt video file. - } catch (InstantiationException e) { - Log.e(TAG, "createVideoThumbnail", e); - } catch (InvocationTargetException e) { - Log.e(TAG, "createVideoThumbnail", e); - } catch (ClassNotFoundException e) { - Log.e(TAG, "createVideoThumbnail", e); - } catch (NoSuchMethodException e) { - Log.e(TAG, "createVideoThumbnail", e); - } catch (IllegalAccessException e) { - Log.e(TAG, "createVideoThumbnail", e); - } finally { - try { - if (instance != null) { - clazz.getMethod("release").invoke(instance); - } - } catch (Exception ignored) { - } - } - return null; - } - - public static byte[] compressToBytes(Bitmap bitmap) { - return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY); - } - - public static byte[] compressToBytes(Bitmap bitmap, int quality) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(65536); - bitmap.compress(CompressFormat.JPEG, quality, baos); - return baos.toByteArray(); - } - - public static boolean isSupportedByRegionDecoder(String mimeType) { - if (mimeType == null) return false; - mimeType = mimeType.toLowerCase(); - return mimeType.startsWith("image/") && - (!mimeType.equals("image/gif") && !mimeType.endsWith("bmp")); - } - - public static boolean isRotationSupported(String mimeType) { - if (mimeType == null) return false; - mimeType = mimeType.toLowerCase(); - return mimeType.equals("image/jpeg"); - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/BlobCache.java b/gallerycommon/src/com/android/gallery3d/common/BlobCache.java deleted file mode 100644 index 3c131e591..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/BlobCache.java +++ /dev/null @@ -1,668 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// This is an on-disk cache which maps a 64-bits key to a byte array. -// -// It consists of three files: one index file and two data files. One of the -// data files is "active", and the other is "inactive". New entries are -// appended into the active region until it reaches the size limit. At that -// point the active file and the inactive file are swapped, and the new active -// file is truncated to empty (and the index for that file is also cleared). -// The index is a hash table with linear probing. When the load factor reaches -// 0.5, it does the same thing like when the size limit is reached. -// -// The index file format: (all numbers are stored in little-endian) -// [0] Magic number: 0xB3273030 -// [4] MaxEntries: Max number of hash entries per region. -// [8] MaxBytes: Max number of data bytes per region (including header). -// [12] ActiveRegion: The active growing region: 0 or 1. -// [16] ActiveEntries: The number of hash entries used in the active region. -// [20] ActiveBytes: The number of data bytes used in the active region. -// [24] Version number. -// [28] Checksum of [0..28). -// [32] Hash entries for region 0. The size is X = (12 * MaxEntries bytes). -// [32 + X] Hash entries for region 1. The size is also X. -// -// Each hash entry is 12 bytes: 8 bytes key and 4 bytes offset into the data -// file. The offset is 0 when the slot is free. Note that 0 is a valid value -// for key. The keys are used directly as index into a hash table, so they -// should be suitably distributed. -// -// Each data file stores data for one region. The data file is concatenated -// blobs followed by the magic number 0xBD248510. -// -// The blob format: -// [0] Key of this blob -// [8] Checksum of this blob -// [12] Offset of this blob -// [16] Length of this blob (not including header) -// [20] Blob -// -// Below are the interface for BlobCache. The instance of this class does not -// support concurrent use by multiple threads. -// -// public BlobCache(String path, int maxEntries, int maxBytes, boolean reset) throws IOException; -// public void insert(long key, byte[] data) throws IOException; -// public byte[] lookup(long key) throws IOException; -// public void lookup(LookupRequest req) throws IOException; -// public void close(); -// public void syncIndex(); -// public void syncAll(); -// public static void deleteFiles(String path); -// -package com.android.gallery3d.common; - -import android.util.Log; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteOrder; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; -import java.util.Arrays; -import java.util.zip.Adler32; - -public class BlobCache implements Closeable { - private static final String TAG = "BlobCache"; - - private static final int MAGIC_INDEX_FILE = 0xB3273030; - private static final int MAGIC_DATA_FILE = 0xBD248510; - - // index header offset - private static final int IH_MAGIC = 0; - private static final int IH_MAX_ENTRIES = 4; - private static final int IH_MAX_BYTES = 8; - private static final int IH_ACTIVE_REGION = 12; - private static final int IH_ACTIVE_ENTRIES = 16; - private static final int IH_ACTIVE_BYTES = 20; - private static final int IH_VERSION = 24; - private static final int IH_CHECKSUM = 28; - private static final int INDEX_HEADER_SIZE = 32; - - private static final int DATA_HEADER_SIZE = 4; - - // blob header offset - private static final int BH_KEY = 0; - private static final int BH_CHECKSUM = 8; - private static final int BH_OFFSET = 12; - private static final int BH_LENGTH = 16; - private static final int BLOB_HEADER_SIZE = 20; - - private RandomAccessFile mIndexFile; - private RandomAccessFile mDataFile0; - private RandomAccessFile mDataFile1; - private FileChannel mIndexChannel; - private MappedByteBuffer mIndexBuffer; - - private int mMaxEntries; - private int mMaxBytes; - private int mActiveRegion; - private int mActiveEntries; - private int mActiveBytes; - private int mVersion; - - private RandomAccessFile mActiveDataFile; - private RandomAccessFile mInactiveDataFile; - private int mActiveHashStart; - private int mInactiveHashStart; - private byte[] mIndexHeader = new byte[INDEX_HEADER_SIZE]; - private byte[] mBlobHeader = new byte[BLOB_HEADER_SIZE]; - private Adler32 mAdler32 = new Adler32(); - - // Creates the cache. Three files will be created: - // path + ".idx", path + ".0", and path + ".1" - // The ".0" file and the ".1" file each stores data for a region. Each of - // them can grow to the size specified by maxBytes. The maxEntries parameter - // specifies the maximum number of entries each region can have. If the - // "reset" parameter is true, the cache will be cleared before use. - public BlobCache(String path, int maxEntries, int maxBytes, boolean reset) - throws IOException { - this(path, maxEntries, maxBytes, reset, 0); - } - - public BlobCache(String path, int maxEntries, int maxBytes, boolean reset, - int version) throws IOException { - mIndexFile = new RandomAccessFile(path + ".idx", "rw"); - mDataFile0 = new RandomAccessFile(path + ".0", "rw"); - mDataFile1 = new RandomAccessFile(path + ".1", "rw"); - mVersion = version; - - if (!reset && loadIndex()) { - return; - } - - resetCache(maxEntries, maxBytes); - - if (!loadIndex()) { - closeAll(); - throw new IOException("unable to load index"); - } - } - - // Delete the files associated with the given path previously created - // by the BlobCache constructor. - public static void deleteFiles(String path) { - deleteFileSilently(path + ".idx"); - deleteFileSilently(path + ".0"); - deleteFileSilently(path + ".1"); - } - - private static void deleteFileSilently(String path) { - try { - new File(path).delete(); - } catch (Throwable t) { - // ignore; - } - } - - // Close the cache. All resources are released. No other method should be - // called after this is called. - @Override - public void close() { - syncAll(); - closeAll(); - } - - private void closeAll() { - closeSilently(mIndexChannel); - closeSilently(mIndexFile); - closeSilently(mDataFile0); - closeSilently(mDataFile1); - } - - // Returns true if loading index is successful. After this method is called, - // mIndexHeader and index header in file should be kept sync. - private boolean loadIndex() { - try { - mIndexFile.seek(0); - mDataFile0.seek(0); - mDataFile1.seek(0); - - byte[] buf = mIndexHeader; - if (mIndexFile.read(buf) != INDEX_HEADER_SIZE) { - Log.w(TAG, "cannot read header"); - return false; - } - - if (readInt(buf, IH_MAGIC) != MAGIC_INDEX_FILE) { - Log.w(TAG, "cannot read header magic"); - return false; - } - - if (readInt(buf, IH_VERSION) != mVersion) { - Log.w(TAG, "version mismatch"); - return false; - } - - mMaxEntries = readInt(buf, IH_MAX_ENTRIES); - mMaxBytes = readInt(buf, IH_MAX_BYTES); - mActiveRegion = readInt(buf, IH_ACTIVE_REGION); - mActiveEntries = readInt(buf, IH_ACTIVE_ENTRIES); - mActiveBytes = readInt(buf, IH_ACTIVE_BYTES); - - int sum = readInt(buf, IH_CHECKSUM); - if (checkSum(buf, 0, IH_CHECKSUM) != sum) { - Log.w(TAG, "header checksum does not match"); - return false; - } - - // Sanity check - if (mMaxEntries <= 0) { - Log.w(TAG, "invalid max entries"); - return false; - } - if (mMaxBytes <= 0) { - Log.w(TAG, "invalid max bytes"); - return false; - } - if (mActiveRegion != 0 && mActiveRegion != 1) { - Log.w(TAG, "invalid active region"); - return false; - } - if (mActiveEntries < 0 || mActiveEntries > mMaxEntries) { - Log.w(TAG, "invalid active entries"); - return false; - } - if (mActiveBytes < DATA_HEADER_SIZE || mActiveBytes > mMaxBytes) { - Log.w(TAG, "invalid active bytes"); - return false; - } - if (mIndexFile.length() != - INDEX_HEADER_SIZE + mMaxEntries * 12 * 2) { - Log.w(TAG, "invalid index file length"); - return false; - } - - // Make sure data file has magic - byte[] magic = new byte[4]; - if (mDataFile0.read(magic) != 4) { - Log.w(TAG, "cannot read data file magic"); - return false; - } - if (readInt(magic, 0) != MAGIC_DATA_FILE) { - Log.w(TAG, "invalid data file magic"); - return false; - } - if (mDataFile1.read(magic) != 4) { - Log.w(TAG, "cannot read data file magic"); - return false; - } - if (readInt(magic, 0) != MAGIC_DATA_FILE) { - Log.w(TAG, "invalid data file magic"); - return false; - } - - // Map index file to memory - mIndexChannel = mIndexFile.getChannel(); - mIndexBuffer = mIndexChannel.map(FileChannel.MapMode.READ_WRITE, - 0, mIndexFile.length()); - mIndexBuffer.order(ByteOrder.LITTLE_ENDIAN); - - setActiveVariables(); - return true; - } catch (IOException ex) { - Log.e(TAG, "loadIndex failed.", ex); - return false; - } - } - - private void setActiveVariables() throws IOException { - mActiveDataFile = (mActiveRegion == 0) ? mDataFile0 : mDataFile1; - mInactiveDataFile = (mActiveRegion == 1) ? mDataFile0 : mDataFile1; - mActiveDataFile.setLength(mActiveBytes); - mActiveDataFile.seek(mActiveBytes); - - mActiveHashStart = INDEX_HEADER_SIZE; - mInactiveHashStart = INDEX_HEADER_SIZE; - - if (mActiveRegion == 0) { - mInactiveHashStart += mMaxEntries * 12; - } else { - mActiveHashStart += mMaxEntries * 12; - } - } - - private void resetCache(int maxEntries, int maxBytes) throws IOException { - mIndexFile.setLength(0); // truncate to zero the index - mIndexFile.setLength(INDEX_HEADER_SIZE + maxEntries * 12 * 2); - mIndexFile.seek(0); - byte[] buf = mIndexHeader; - writeInt(buf, IH_MAGIC, MAGIC_INDEX_FILE); - writeInt(buf, IH_MAX_ENTRIES, maxEntries); - writeInt(buf, IH_MAX_BYTES, maxBytes); - writeInt(buf, IH_ACTIVE_REGION, 0); - writeInt(buf, IH_ACTIVE_ENTRIES, 0); - writeInt(buf, IH_ACTIVE_BYTES, DATA_HEADER_SIZE); - writeInt(buf, IH_VERSION, mVersion); - writeInt(buf, IH_CHECKSUM, checkSum(buf, 0, IH_CHECKSUM)); - mIndexFile.write(buf); - // This is only needed if setLength does not zero the extended part. - // writeZero(mIndexFile, maxEntries * 12 * 2); - - mDataFile0.setLength(0); - mDataFile1.setLength(0); - mDataFile0.seek(0); - mDataFile1.seek(0); - writeInt(buf, 0, MAGIC_DATA_FILE); - mDataFile0.write(buf, 0, 4); - mDataFile1.write(buf, 0, 4); - } - - // Flip the active region and the inactive region. - private void flipRegion() throws IOException { - mActiveRegion = 1 - mActiveRegion; - mActiveEntries = 0; - mActiveBytes = DATA_HEADER_SIZE; - - writeInt(mIndexHeader, IH_ACTIVE_REGION, mActiveRegion); - writeInt(mIndexHeader, IH_ACTIVE_ENTRIES, mActiveEntries); - writeInt(mIndexHeader, IH_ACTIVE_BYTES, mActiveBytes); - updateIndexHeader(); - - setActiveVariables(); - clearHash(mActiveHashStart); - syncIndex(); - } - - // Sync mIndexHeader to the index file. - private void updateIndexHeader() { - writeInt(mIndexHeader, IH_CHECKSUM, - checkSum(mIndexHeader, 0, IH_CHECKSUM)); - mIndexBuffer.position(0); - mIndexBuffer.put(mIndexHeader); - } - - // Clear the hash table starting from the specified offset. - private void clearHash(int hashStart) { - byte[] zero = new byte[1024]; - mIndexBuffer.position(hashStart); - for (int count = mMaxEntries * 12; count > 0;) { - int todo = Math.min(count, 1024); - mIndexBuffer.put(zero, 0, todo); - count -= todo; - } - } - - // Inserts a (key, data) pair into the cache. - public void insert(long key, byte[] data) throws IOException { - if (DATA_HEADER_SIZE + BLOB_HEADER_SIZE + data.length > mMaxBytes) { - throw new RuntimeException("blob is too large!"); - } - - if (mActiveBytes + BLOB_HEADER_SIZE + data.length > mMaxBytes - || mActiveEntries * 2 >= mMaxEntries) { - flipRegion(); - } - - if (!lookupInternal(key, mActiveHashStart)) { - // If we don't have an existing entry with the same key, increase - // the entry count. - mActiveEntries++; - writeInt(mIndexHeader, IH_ACTIVE_ENTRIES, mActiveEntries); - } - - insertInternal(key, data, data.length); - updateIndexHeader(); - } - - public void clearEntry(long key) throws IOException { - if (!lookupInternal(key, mActiveHashStart)) { - return; // Nothing to clear - } - byte[] header = mBlobHeader; - Arrays.fill(header, (byte) 0); - mActiveDataFile.seek(mFileOffset); - mActiveDataFile.write(header); - } - - // Appends the data to the active file. It also updates the hash entry. - // The proper hash entry (suitable for insertion or replacement) must be - // pointed by mSlotOffset. - private void insertInternal(long key, byte[] data, int length) - throws IOException { - byte[] header = mBlobHeader; - int sum = checkSum(data); - writeLong(header, BH_KEY, key); - writeInt(header, BH_CHECKSUM, sum); - writeInt(header, BH_OFFSET, mActiveBytes); - writeInt(header, BH_LENGTH, length); - mActiveDataFile.write(header); - mActiveDataFile.write(data, 0, length); - - mIndexBuffer.putLong(mSlotOffset, key); - mIndexBuffer.putInt(mSlotOffset + 8, mActiveBytes); - mActiveBytes += BLOB_HEADER_SIZE + length; - writeInt(mIndexHeader, IH_ACTIVE_BYTES, mActiveBytes); - } - - public static class LookupRequest { - public long key; // input: the key to find - public byte[] buffer; // input/output: the buffer to store the blob - public int length; // output: the length of the blob - } - - // This method is for one-off lookup. For repeated lookup, use the version - // accepting LookupRequest to avoid repeated memory allocation. - private LookupRequest mLookupRequest = new LookupRequest(); - public byte[] lookup(long key) throws IOException { - mLookupRequest.key = key; - mLookupRequest.buffer = null; - if (lookup(mLookupRequest)) { - return mLookupRequest.buffer; - } else { - return null; - } - } - - // Returns true if the associated blob for the given key is available. - // The blob is stored in the buffer pointed by req.buffer, and the length - // is in stored in the req.length variable. - // - // The user can input a non-null value in req.buffer, and this method will - // try to use that buffer. If that buffer is not large enough, this method - // will allocate a new buffer and assign it to req.buffer. - // - // This method tries not to throw IOException even if the data file is - // corrupted, but it can still throw IOException if things get strange. - public boolean lookup(LookupRequest req) throws IOException { - // Look up in the active region first. - if (lookupInternal(req.key, mActiveHashStart)) { - if (getBlob(mActiveDataFile, mFileOffset, req)) { - return true; - } - } - - // We want to copy the data from the inactive file to the active file - // if it's available. So we keep the offset of the hash entry so we can - // avoid looking it up again. - int insertOffset = mSlotOffset; - - // Look up in the inactive region. - if (lookupInternal(req.key, mInactiveHashStart)) { - if (getBlob(mInactiveDataFile, mFileOffset, req)) { - // If we don't have enough space to insert this blob into - // the active file, just return it. - if (mActiveBytes + BLOB_HEADER_SIZE + req.length > mMaxBytes - || mActiveEntries * 2 >= mMaxEntries) { - return true; - } - // Otherwise copy it over. - mSlotOffset = insertOffset; - try { - insertInternal(req.key, req.buffer, req.length); - mActiveEntries++; - writeInt(mIndexHeader, IH_ACTIVE_ENTRIES, mActiveEntries); - updateIndexHeader(); - } catch (Throwable t) { - Log.e(TAG, "cannot copy over"); - } - return true; - } - } - - return false; - } - - - // Copies the blob for the specified offset in the specified file to - // req.buffer. If req.buffer is null or too small, allocate a buffer and - // assign it to req.buffer. - // Returns false if the blob is not available (either the index file is - // not sync with the data file, or one of them is corrupted). The length - // of the blob is stored in the req.length variable. - private boolean getBlob(RandomAccessFile file, int offset, - LookupRequest req) throws IOException { - byte[] header = mBlobHeader; - long oldPosition = file.getFilePointer(); - try { - file.seek(offset); - if (file.read(header) != BLOB_HEADER_SIZE) { - Log.w(TAG, "cannot read blob header"); - return false; - } - long blobKey = readLong(header, BH_KEY); - if (blobKey == 0) { - return false; // This entry has been cleared. - } - if (blobKey != req.key) { - Log.w(TAG, "blob key does not match: " + blobKey); - return false; - } - int sum = readInt(header, BH_CHECKSUM); - int blobOffset = readInt(header, BH_OFFSET); - if (blobOffset != offset) { - Log.w(TAG, "blob offset does not match: " + blobOffset); - return false; - } - int length = readInt(header, BH_LENGTH); - if (length < 0 || length > mMaxBytes - offset - BLOB_HEADER_SIZE) { - Log.w(TAG, "invalid blob length: " + length); - return false; - } - if (req.buffer == null || req.buffer.length < length) { - req.buffer = new byte[length]; - } - - byte[] blob = req.buffer; - req.length = length; - - if (file.read(blob, 0, length) != length) { - Log.w(TAG, "cannot read blob data"); - return false; - } - if (checkSum(blob, 0, length) != sum) { - Log.w(TAG, "blob checksum does not match: " + sum); - return false; - } - return true; - } catch (Throwable t) { - Log.e(TAG, "getBlob failed.", t); - return false; - } finally { - file.seek(oldPosition); - } - } - - // Tries to look up a key in the specified hash region. - // Returns true if the lookup is successful. - // The slot offset in the index file is saved in mSlotOffset. If the lookup - // is successful, it's the slot found. Otherwise it's the slot suitable for - // insertion. - // If the lookup is successful, the file offset is also saved in - // mFileOffset. - private int mSlotOffset; - private int mFileOffset; - private boolean lookupInternal(long key, int hashStart) { - int slot = (int) (key % mMaxEntries); - if (slot < 0) slot += mMaxEntries; - int slotBegin = slot; - while (true) { - int offset = hashStart + slot * 12; - long candidateKey = mIndexBuffer.getLong(offset); - int candidateOffset = mIndexBuffer.getInt(offset + 8); - if (candidateOffset == 0) { - mSlotOffset = offset; - return false; - } else if (candidateKey == key) { - mSlotOffset = offset; - mFileOffset = candidateOffset; - return true; - } else { - if (++slot >= mMaxEntries) { - slot = 0; - } - if (slot == slotBegin) { - Log.w(TAG, "corrupted index: clear the slot."); - mIndexBuffer.putInt(hashStart + slot * 12 + 8, 0); - } - } - } - } - - public void syncIndex() { - try { - mIndexBuffer.force(); - } catch (Throwable t) { - Log.w(TAG, "sync index failed", t); - } - } - - public void syncAll() { - syncIndex(); - try { - mDataFile0.getFD().sync(); - } catch (Throwable t) { - Log.w(TAG, "sync data file 0 failed", t); - } - try { - mDataFile1.getFD().sync(); - } catch (Throwable t) { - Log.w(TAG, "sync data file 1 failed", t); - } - } - - // This is for testing only. - // - // Returns the active count (mActiveEntries). This also verifies that - // the active count matches matches what's inside the hash region. - int getActiveCount() { - int count = 0; - for (int i = 0; i < mMaxEntries; i++) { - int offset = mActiveHashStart + i * 12; - long candidateKey = mIndexBuffer.getLong(offset); - int candidateOffset = mIndexBuffer.getInt(offset + 8); - if (candidateOffset != 0) ++count; - } - if (count == mActiveEntries) { - return count; - } else { - Log.e(TAG, "wrong active count: " + mActiveEntries + " vs " + count); - return -1; // signal failure. - } - } - - int checkSum(byte[] data) { - mAdler32.reset(); - mAdler32.update(data); - return (int) mAdler32.getValue(); - } - - int checkSum(byte[] data, int offset, int nbytes) { - mAdler32.reset(); - mAdler32.update(data, offset, nbytes); - return (int) mAdler32.getValue(); - } - - static void closeSilently(Closeable c) { - if (c == null) return; - try { - c.close(); - } catch (Throwable t) { - // do nothing - } - } - - static int readInt(byte[] buf, int offset) { - return (buf[offset] & 0xff) - | ((buf[offset + 1] & 0xff) << 8) - | ((buf[offset + 2] & 0xff) << 16) - | ((buf[offset + 3] & 0xff) << 24); - } - - static long readLong(byte[] buf, int offset) { - long result = buf[offset + 7] & 0xff; - for (int i = 6; i >= 0; i--) { - result = (result << 8) | (buf[offset + i] & 0xff); - } - return result; - } - - static void writeInt(byte[] buf, int offset, int value) { - for (int i = 0; i < 4; i++) { - buf[offset + i] = (byte) (value & 0xff); - value >>= 8; - } - } - - static void writeLong(byte[] buf, int offset, long value) { - for (int i = 0; i < 8; i++) { - buf[offset + i] = (byte) (value & 0xff); - value >>= 8; - } - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/Entry.java b/gallerycommon/src/com/android/gallery3d/common/Entry.java deleted file mode 100644 index 3f1644e65..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/Entry.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -public abstract class Entry { - public static final String[] ID_PROJECTION = { "_id" }; - - public static interface Columns { - public static final String ID = "_id"; - } - - // The primary key of the entry. - @Column("_id") - public long id = 0; - - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.TYPE) - public @interface Table { - String value(); - } - - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.FIELD) - public @interface Column { - String value(); - - boolean indexed() default false; - - boolean fullText() default false; - - String defaultValue() default ""; - - boolean unique() default false; - } - - public void clear() { - id = 0; - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/EntrySchema.java b/gallerycommon/src/com/android/gallery3d/common/EntrySchema.java deleted file mode 100644 index 7bf7e431c..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/EntrySchema.java +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import android.content.ContentValues; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.text.TextUtils; - -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; -import java.util.ArrayList; - -public final class EntrySchema { - @SuppressWarnings("unused") - private static final String TAG = "EntrySchema"; - - public static final int TYPE_STRING = 0; - public static final int TYPE_BOOLEAN = 1; - public static final int TYPE_SHORT = 2; - public static final int TYPE_INT = 3; - public static final int TYPE_LONG = 4; - public static final int TYPE_FLOAT = 5; - public static final int TYPE_DOUBLE = 6; - public static final int TYPE_BLOB = 7; - private static final String SQLITE_TYPES[] = { - "TEXT", "INTEGER", "INTEGER", "INTEGER", "INTEGER", "REAL", "REAL", "NONE" }; - - private static final String FULL_TEXT_INDEX_SUFFIX = "_fulltext"; - - private final String mTableName; - private final ColumnInfo[] mColumnInfo; - private final String[] mProjection; - private final boolean mHasFullTextIndex; - - public EntrySchema(Class clazz) { - // Get table and column metadata from reflection. - ColumnInfo[] columns = parseColumnInfo(clazz); - mTableName = parseTableName(clazz); - mColumnInfo = columns; - - // Cache the list of projection columns and check for full-text columns. - String[] projection = {}; - boolean hasFullTextIndex = false; - if (columns != null) { - projection = new String[columns.length]; - for (int i = 0; i != columns.length; ++i) { - ColumnInfo column = columns[i]; - projection[i] = column.name; - if (column.fullText) { - hasFullTextIndex = true; - } - } - } - mProjection = projection; - mHasFullTextIndex = hasFullTextIndex; - } - - public String getTableName() { - return mTableName; - } - - public ColumnInfo[] getColumnInfo() { - return mColumnInfo; - } - - public String[] getProjection() { - return mProjection; - } - - public int getColumnIndex(String columnName) { - for (ColumnInfo column : mColumnInfo) { - if (column.name.equals(columnName)) { - return column.projectionIndex; - } - } - return -1; - } - - public ColumnInfo getColumn(String columnName) { - int index = getColumnIndex(columnName); - return (index < 0) ? null : mColumnInfo[index]; - } - - private void logExecSql(SQLiteDatabase db, String sql) { - db.execSQL(sql); - } - - public T cursorToObject(Cursor cursor, T object) { - try { - for (ColumnInfo column : mColumnInfo) { - int columnIndex = column.projectionIndex; - Field field = column.field; - switch (column.type) { - case TYPE_STRING: - field.set(object, cursor.isNull(columnIndex) - ? null - : cursor.getString(columnIndex)); - break; - case TYPE_BOOLEAN: - field.setBoolean(object, cursor.getShort(columnIndex) == 1); - break; - case TYPE_SHORT: - field.setShort(object, cursor.getShort(columnIndex)); - break; - case TYPE_INT: - field.setInt(object, cursor.getInt(columnIndex)); - break; - case TYPE_LONG: - field.setLong(object, cursor.getLong(columnIndex)); - break; - case TYPE_FLOAT: - field.setFloat(object, cursor.getFloat(columnIndex)); - break; - case TYPE_DOUBLE: - field.setDouble(object, cursor.getDouble(columnIndex)); - break; - case TYPE_BLOB: - field.set(object, cursor.isNull(columnIndex) - ? null - : cursor.getBlob(columnIndex)); - break; - } - } - return object; - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - private void setIfNotNull(Field field, Object object, Object value) - throws IllegalAccessException { - if (value != null) field.set(object, value); - } - - /** - * Converts the ContentValues to the object. The ContentValues may not - * contain values for all the fields in the object. - */ - public T valuesToObject(ContentValues values, T object) { - try { - for (ColumnInfo column : mColumnInfo) { - String columnName = column.name; - Field field = column.field; - switch (column.type) { - case TYPE_STRING: - setIfNotNull(field, object, values.getAsString(columnName)); - break; - case TYPE_BOOLEAN: - setIfNotNull(field, object, values.getAsBoolean(columnName)); - break; - case TYPE_SHORT: - setIfNotNull(field, object, values.getAsShort(columnName)); - break; - case TYPE_INT: - setIfNotNull(field, object, values.getAsInteger(columnName)); - break; - case TYPE_LONG: - setIfNotNull(field, object, values.getAsLong(columnName)); - break; - case TYPE_FLOAT: - setIfNotNull(field, object, values.getAsFloat(columnName)); - break; - case TYPE_DOUBLE: - setIfNotNull(field, object, values.getAsDouble(columnName)); - break; - case TYPE_BLOB: - setIfNotNull(field, object, values.getAsByteArray(columnName)); - break; - } - } - return object; - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - public void objectToValues(Entry object, ContentValues values) { - try { - for (ColumnInfo column : mColumnInfo) { - String columnName = column.name; - Field field = column.field; - switch (column.type) { - case TYPE_STRING: - values.put(columnName, (String) field.get(object)); - break; - case TYPE_BOOLEAN: - values.put(columnName, field.getBoolean(object)); - break; - case TYPE_SHORT: - values.put(columnName, field.getShort(object)); - break; - case TYPE_INT: - values.put(columnName, field.getInt(object)); - break; - case TYPE_LONG: - values.put(columnName, field.getLong(object)); - break; - case TYPE_FLOAT: - values.put(columnName, field.getFloat(object)); - break; - case TYPE_DOUBLE: - values.put(columnName, field.getDouble(object)); - break; - case TYPE_BLOB: - values.put(columnName, (byte[]) field.get(object)); - break; - } - } - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - public String toDebugString(Entry entry) { - try { - StringBuilder sb = new StringBuilder(); - sb.append("ID=").append(entry.id); - for (ColumnInfo column : mColumnInfo) { - String columnName = column.name; - Field field = column.field; - Object value = field.get(entry); - sb.append(" ").append(columnName).append("=") - .append((value == null) ? "null" : value.toString()); - } - return sb.toString(); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - public String toDebugString(Entry entry, String... columnNames) { - try { - StringBuilder sb = new StringBuilder(); - sb.append("ID=").append(entry.id); - for (String columnName : columnNames) { - ColumnInfo column = getColumn(columnName); - Field field = column.field; - Object value = field.get(entry); - sb.append(" ").append(columnName).append("=") - .append((value == null) ? "null" : value.toString()); - } - return sb.toString(); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - public Cursor queryAll(SQLiteDatabase db) { - return db.query(mTableName, mProjection, null, null, null, null, null); - } - - public boolean queryWithId(SQLiteDatabase db, long id, Entry entry) { - Cursor cursor = db.query(mTableName, mProjection, "_id=?", - new String[] {Long.toString(id)}, null, null, null); - boolean success = false; - if (cursor.moveToFirst()) { - cursorToObject(cursor, entry); - success = true; - } - cursor.close(); - return success; - } - - public long insertOrReplace(SQLiteDatabase db, Entry entry) { - ContentValues values = new ContentValues(); - objectToValues(entry, values); - if (entry.id == 0) { - values.remove("_id"); - } - long id = db.replace(mTableName, "_id", values); - entry.id = id; - return id; - } - - public boolean deleteWithId(SQLiteDatabase db, long id) { - return db.delete(mTableName, "_id=?", new String[] { Long.toString(id) }) == 1; - } - - public void createTables(SQLiteDatabase db) { - // Wrapped class must have a @Table.Definition. - String tableName = mTableName; - Utils.assertTrue(tableName != null); - - // Add the CREATE TABLE statement for the main table. - StringBuilder sql = new StringBuilder("CREATE TABLE "); - sql.append(tableName); - sql.append(" (_id INTEGER PRIMARY KEY AUTOINCREMENT"); - StringBuilder unique = new StringBuilder(); - for (ColumnInfo column : mColumnInfo) { - if (!column.isId()) { - sql.append(','); - sql.append(column.name); - sql.append(' '); - sql.append(SQLITE_TYPES[column.type]); - if (!TextUtils.isEmpty(column.defaultValue)) { - sql.append(" DEFAULT "); - sql.append(column.defaultValue); - } - if (column.unique) { - if (unique.length() == 0) { - unique.append(column.name); - } else { - unique.append(',').append(column.name); - } - } - } - } - if (unique.length() > 0) { - sql.append(",UNIQUE(").append(unique).append(')'); - } - sql.append(");"); - logExecSql(db, sql.toString()); - sql.setLength(0); - - // Create indexes for all indexed columns. - for (ColumnInfo column : mColumnInfo) { - // Create an index on the indexed columns. - if (column.indexed) { - sql.append("CREATE INDEX "); - sql.append(tableName); - sql.append("_index_"); - sql.append(column.name); - sql.append(" ON "); - sql.append(tableName); - sql.append(" ("); - sql.append(column.name); - sql.append(");"); - logExecSql(db, sql.toString()); - sql.setLength(0); - } - } - - if (mHasFullTextIndex) { - // Add an FTS virtual table if using full-text search. - String ftsTableName = tableName + FULL_TEXT_INDEX_SUFFIX; - sql.append("CREATE VIRTUAL TABLE "); - sql.append(ftsTableName); - sql.append(" USING FTS3 (_id INTEGER PRIMARY KEY"); - for (ColumnInfo column : mColumnInfo) { - if (column.fullText) { - // Add the column to the FTS table. - String columnName = column.name; - sql.append(','); - sql.append(columnName); - sql.append(" TEXT"); - } - } - sql.append(");"); - logExecSql(db, sql.toString()); - sql.setLength(0); - - // Build an insert statement that will automatically keep the FTS - // table in sync. - StringBuilder insertSql = new StringBuilder("INSERT OR REPLACE INTO "); - insertSql.append(ftsTableName); - insertSql.append(" (_id"); - for (ColumnInfo column : mColumnInfo) { - if (column.fullText) { - insertSql.append(','); - insertSql.append(column.name); - } - } - insertSql.append(") VALUES (new._id"); - for (ColumnInfo column : mColumnInfo) { - if (column.fullText) { - insertSql.append(",new."); - insertSql.append(column.name); - } - } - insertSql.append(");"); - String insertSqlString = insertSql.toString(); - - // Add an insert trigger. - sql.append("CREATE TRIGGER "); - sql.append(tableName); - sql.append("_insert_trigger AFTER INSERT ON "); - sql.append(tableName); - sql.append(" FOR EACH ROW BEGIN "); - sql.append(insertSqlString); - sql.append("END;"); - logExecSql(db, sql.toString()); - sql.setLength(0); - - // Add an update trigger. - sql.append("CREATE TRIGGER "); - sql.append(tableName); - sql.append("_update_trigger AFTER UPDATE ON "); - sql.append(tableName); - sql.append(" FOR EACH ROW BEGIN "); - sql.append(insertSqlString); - sql.append("END;"); - logExecSql(db, sql.toString()); - sql.setLength(0); - - // Add a delete trigger. - sql.append("CREATE TRIGGER "); - sql.append(tableName); - sql.append("_delete_trigger AFTER DELETE ON "); - sql.append(tableName); - sql.append(" FOR EACH ROW BEGIN DELETE FROM "); - sql.append(ftsTableName); - sql.append(" WHERE _id = old._id; END;"); - logExecSql(db, sql.toString()); - sql.setLength(0); - } - } - - public void dropTables(SQLiteDatabase db) { - String tableName = mTableName; - StringBuilder sql = new StringBuilder("DROP TABLE IF EXISTS "); - sql.append(tableName); - sql.append(';'); - logExecSql(db, sql.toString()); - sql.setLength(0); - - if (mHasFullTextIndex) { - sql.append("DROP TABLE IF EXISTS "); - sql.append(tableName); - sql.append(FULL_TEXT_INDEX_SUFFIX); - sql.append(';'); - logExecSql(db, sql.toString()); - } - - } - - public void deleteAll(SQLiteDatabase db) { - StringBuilder sql = new StringBuilder("DELETE FROM "); - sql.append(mTableName); - sql.append(";"); - logExecSql(db, sql.toString()); - } - - private String parseTableName(Class clazz) { - // Check for a table annotation. - Entry.Table table = clazz.getAnnotation(Entry.Table.class); - if (table == null) { - return null; - } - - // Return the table name. - return table.value(); - } - - private ColumnInfo[] parseColumnInfo(Class clazz) { - ArrayList columns = new ArrayList(); - while (clazz != null) { - parseColumnInfo(clazz, columns); - clazz = clazz.getSuperclass(); - } - - // Return a list. - ColumnInfo[] columnList = new ColumnInfo[columns.size()]; - columns.toArray(columnList); - return columnList; - } - - private void parseColumnInfo(Class clazz, ArrayList columns) { - // Gather metadata from each annotated field. - Field[] fields = clazz.getDeclaredFields(); // including non-public fields - for (int i = 0; i != fields.length; ++i) { - // Get column metadata from the annotation. - Field field = fields[i]; - Entry.Column info = ((AnnotatedElement) field).getAnnotation(Entry.Column.class); - if (info == null) continue; - - // Determine the field type. - int type; - Class fieldType = field.getType(); - if (fieldType == String.class) { - type = TYPE_STRING; - } else if (fieldType == boolean.class) { - type = TYPE_BOOLEAN; - } else if (fieldType == short.class) { - type = TYPE_SHORT; - } else if (fieldType == int.class) { - type = TYPE_INT; - } else if (fieldType == long.class) { - type = TYPE_LONG; - } else if (fieldType == float.class) { - type = TYPE_FLOAT; - } else if (fieldType == double.class) { - type = TYPE_DOUBLE; - } else if (fieldType == byte[].class) { - type = TYPE_BLOB; - } else { - throw new IllegalArgumentException( - "Unsupported field type for column: " + fieldType.getName()); - } - - // Add the column to the array. - int index = columns.size(); - columns.add(new ColumnInfo(info.value(), type, info.indexed(), info.unique(), - info.fullText(), info.defaultValue(), field, index)); - } - } - - public static final class ColumnInfo { - private static final String ID_KEY = "_id"; - - public final String name; - public final int type; - public final boolean indexed; - public final boolean unique; - public final boolean fullText; - public final String defaultValue; - public final Field field; - public final int projectionIndex; - - public ColumnInfo(String name, int type, boolean indexed, boolean unique, - boolean fullText, String defaultValue, Field field, int projectionIndex) { - this.name = name.toLowerCase(); - this.type = type; - this.indexed = indexed; - this.unique = unique; - this.fullText = fullText; - this.defaultValue = defaultValue; - this.field = field; - this.projectionIndex = projectionIndex; - - field.setAccessible(true); // in order to set non-public fields - } - - public boolean isId() { - return ID_KEY.equals(name); - } - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/FileCache.java b/gallerycommon/src/com/android/gallery3d/common/FileCache.java deleted file mode 100644 index d7deda6fa..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/FileCache.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.util.Log; - -import com.android.gallery3d.common.Entry.Table; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; - -public class FileCache implements Closeable { - private static final int LRU_CAPACITY = 4; - private static final int MAX_DELETE_COUNT = 16; - - private static final String TAG = "FileCache"; - private static final String TABLE_NAME = FileEntry.SCHEMA.getTableName(); - private static final String FILE_PREFIX = "download"; - private static final String FILE_POSTFIX = ".tmp"; - - private static final String QUERY_WHERE = - FileEntry.Columns.HASH_CODE + "=? AND " + FileEntry.Columns.CONTENT_URL + "=?"; - private static final String ID_WHERE = FileEntry.Columns.ID + "=?"; - private static final String[] PROJECTION_SIZE_SUM = - {String.format("sum(%s)", FileEntry.Columns.SIZE)}; - private static final String FREESPACE_PROJECTION[] = { - FileEntry.Columns.ID, FileEntry.Columns.FILENAME, - FileEntry.Columns.CONTENT_URL, FileEntry.Columns.SIZE}; - private static final String FREESPACE_ORDER_BY = - String.format("%s ASC", FileEntry.Columns.LAST_ACCESS); - - private final LruCache mEntryMap = - new LruCache(LRU_CAPACITY); - - private File mRootDir; - private long mCapacity; - private boolean mInitialized = false; - private long mTotalBytes; - - private DatabaseHelper mDbHelper; - - public static final class CacheEntry { - private long id; - public String contentUrl; - public File cacheFile; - - private CacheEntry(long id, String contentUrl, File cacheFile) { - this.id = id; - this.contentUrl = contentUrl; - this.cacheFile = cacheFile; - } - } - - public static void deleteFiles(Context context, File rootDir, String dbName) { - try { - context.getDatabasePath(dbName).delete(); - File[] files = rootDir.listFiles(); - if (files == null) return; - for (File file : rootDir.listFiles()) { - String name = file.getName(); - if (file.isFile() && name.startsWith(FILE_PREFIX) - && name.endsWith(FILE_POSTFIX)) file.delete(); - } - } catch (Throwable t) { - Log.w(TAG, "cannot reset database", t); - } - } - - public FileCache(Context context, File rootDir, String dbName, long capacity) { - mRootDir = Utils.checkNotNull(rootDir); - mCapacity = capacity; - mDbHelper = new DatabaseHelper(context, dbName); - } - - @Override - public void close() { - mDbHelper.close(); - } - - public void store(String downloadUrl, File file) { - if (!mInitialized) initialize(); - - Utils.assertTrue(file.getParentFile().equals(mRootDir)); - FileEntry entry = new FileEntry(); - entry.hashCode = Utils.crc64Long(downloadUrl); - entry.contentUrl = downloadUrl; - entry.filename = file.getName(); - entry.size = file.length(); - entry.lastAccess = System.currentTimeMillis(); - if (entry.size >= mCapacity) { - file.delete(); - throw new IllegalArgumentException("file too large: " + entry.size); - } - synchronized (this) { - FileEntry original = queryDatabase(downloadUrl); - if (original != null) { - file.delete(); - entry.filename = original.filename; - entry.size = original.size; - } else { - mTotalBytes += entry.size; - } - FileEntry.SCHEMA.insertOrReplace( - mDbHelper.getWritableDatabase(), entry); - if (mTotalBytes > mCapacity) freeSomeSpaceIfNeed(MAX_DELETE_COUNT); - } - } - - public CacheEntry lookup(String downloadUrl) { - if (!mInitialized) initialize(); - CacheEntry entry; - synchronized (mEntryMap) { - entry = mEntryMap.get(downloadUrl); - } - - if (entry != null) { - synchronized (this) { - updateLastAccess(entry.id); - } - return entry; - } - - synchronized (this) { - FileEntry file = queryDatabase(downloadUrl); - if (file == null) return null; - entry = new CacheEntry( - file.id, downloadUrl, new File(mRootDir, file.filename)); - if (!entry.cacheFile.isFile()) { // file has been removed - try { - mDbHelper.getWritableDatabase().delete( - TABLE_NAME, ID_WHERE, new String[] {String.valueOf(file.id)}); - mTotalBytes -= file.size; - } catch (Throwable t) { - Log.w(TAG, "cannot delete entry: " + file.filename, t); - } - return null; - } - synchronized (mEntryMap) { - mEntryMap.put(downloadUrl, entry); - } - return entry; - } - } - - private FileEntry queryDatabase(String downloadUrl) { - long hash = Utils.crc64Long(downloadUrl); - String whereArgs[] = new String[] {String.valueOf(hash), downloadUrl}; - Cursor cursor = mDbHelper.getReadableDatabase().query(TABLE_NAME, - FileEntry.SCHEMA.getProjection(), - QUERY_WHERE, whereArgs, null, null, null); - try { - if (!cursor.moveToNext()) return null; - FileEntry entry = new FileEntry(); - FileEntry.SCHEMA.cursorToObject(cursor, entry); - updateLastAccess(entry.id); - return entry; - } finally { - cursor.close(); - } - } - - private void updateLastAccess(long id) { - ContentValues values = new ContentValues(); - values.put(FileEntry.Columns.LAST_ACCESS, System.currentTimeMillis()); - mDbHelper.getWritableDatabase().update(TABLE_NAME, - values, ID_WHERE, new String[] {String.valueOf(id)}); - } - - public File createFile() throws IOException { - return File.createTempFile(FILE_PREFIX, FILE_POSTFIX, mRootDir); - } - - private synchronized void initialize() { - if (mInitialized) return; - - if (!mRootDir.isDirectory()) { - mRootDir.mkdirs(); - if (!mRootDir.isDirectory()) { - throw new RuntimeException("cannot create: " + mRootDir.getAbsolutePath()); - } - } - - Cursor cursor = mDbHelper.getReadableDatabase().query( - TABLE_NAME, PROJECTION_SIZE_SUM, - null, null, null, null, null); - try { - if (cursor.moveToNext()) mTotalBytes = cursor.getLong(0); - } finally { - cursor.close(); - } - if (mTotalBytes > mCapacity) freeSomeSpaceIfNeed(MAX_DELETE_COUNT); - - // Mark initialized when everything above went through. If an exception was thrown, - // initialize() will be retried later. - mInitialized = true; - } - - private void freeSomeSpaceIfNeed(int maxDeleteFileCount) { - Cursor cursor = mDbHelper.getReadableDatabase().query( - TABLE_NAME, FREESPACE_PROJECTION, - null, null, null, null, FREESPACE_ORDER_BY); - try { - while (maxDeleteFileCount > 0 - && mTotalBytes > mCapacity && cursor.moveToNext()) { - long id = cursor.getLong(0); - String path = cursor.getString(1); - String url = cursor.getString(2); - long size = cursor.getLong(3); - - synchronized (mEntryMap) { - // if some one still uses it - if (mEntryMap.containsKey(url)) continue; - } - - --maxDeleteFileCount; - if (new File(mRootDir, path).delete()) { - mTotalBytes -= size; - mDbHelper.getWritableDatabase().delete(TABLE_NAME, - ID_WHERE, new String[]{String.valueOf(id)}); - } else { - Log.w(TAG, "unable to delete file: " + path); - } - } - } finally { - cursor.close(); - } - } - - @Table("files") - private static class FileEntry extends Entry { - public static final EntrySchema SCHEMA = new EntrySchema(FileEntry.class); - - public interface Columns extends Entry.Columns { - public static final String HASH_CODE = "hash_code"; - public static final String CONTENT_URL = "content_url"; - public static final String FILENAME = "filename"; - public static final String SIZE = "size"; - public static final String LAST_ACCESS = "last_access"; - } - - @Column(value = Columns.HASH_CODE, indexed = true) - public long hashCode; - - @Column(Columns.CONTENT_URL) - public String contentUrl; - - @Column(Columns.FILENAME) - public String filename; - - @Column(Columns.SIZE) - public long size; - - @Column(value = Columns.LAST_ACCESS, indexed = true) - public long lastAccess; - - @Override - public String toString() { - return new StringBuilder() - .append("hash_code: ").append(hashCode).append(", ") - .append("content_url").append(contentUrl).append(", ") - .append("last_access").append(lastAccess).append(", ") - .append("filename").append(filename).toString(); - } - } - - private final class DatabaseHelper extends SQLiteOpenHelper { - public static final int DATABASE_VERSION = 1; - - public DatabaseHelper(Context context, String dbName) { - super(context, dbName, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - FileEntry.SCHEMA.createTables(db); - - // delete old files - for (File file : mRootDir.listFiles()) { - if (!file.delete()) { - Log.w(TAG, "fail to remove: " + file.getAbsolutePath()); - } - } - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - //reset everything - FileEntry.SCHEMA.dropTables(db); - onCreate(db); - } - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/Fingerprint.java b/gallerycommon/src/com/android/gallery3d/common/Fingerprint.java deleted file mode 100644 index 2847e57ce..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/Fingerprint.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import java.io.IOException; -import java.io.InputStream; -import java.security.DigestInputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.List; - -/** - * MD5-based digest Wrapper. - */ -public class Fingerprint { - // Instance of the MessageDigest using our specified digest algorithm. - private static final MessageDigest DIGESTER; - - /** - * Name of the digest algorithm we use in {@link java.security.MessageDigest} - */ - private static final String DIGEST_MD5 = "md5"; - - // Version 1 streamId prefix. - // Hard coded stream id length limit is 40-chars. Don't ask! - private static final String STREAM_ID_CS_PREFIX = "cs_01_"; - - // 16 bytes for 128-bit fingerprint - private static final int FINGERPRINT_BYTE_LENGTH; - - // length of prefix + 32 hex chars for 128-bit fingerprint - private static final int STREAM_ID_CS_01_LENGTH; - - static { - try { - DIGESTER = MessageDigest.getInstance(DIGEST_MD5); - FINGERPRINT_BYTE_LENGTH = DIGESTER.getDigestLength(); - STREAM_ID_CS_01_LENGTH = STREAM_ID_CS_PREFIX.length() - + (FINGERPRINT_BYTE_LENGTH * 2); - } catch (NoSuchAlgorithmException e) { - // can't continue, but really shouldn't happen - throw new IllegalStateException(e); - } - } - - // md5 digest bytes. - private final byte[] mMd5Digest; - - /** - * Creates a new Fingerprint. - */ - public Fingerprint(byte[] bytes) { - if ((bytes == null) || (bytes.length != FINGERPRINT_BYTE_LENGTH)) { - throw new IllegalArgumentException(); - } - mMd5Digest = bytes; - } - - /** - * Creates a Fingerprint based on the contents of a file. - * - * Note that this will close() stream after calculating the digest. - * @param byteCount length of original data will be stored at byteCount[0] as a side product - * of the fingerprint calculation - */ - public static Fingerprint fromInputStream(InputStream stream, long[] byteCount) - throws IOException { - DigestInputStream in = null; - long count = 0; - try { - in = new DigestInputStream(stream, DIGESTER); - byte[] bytes = new byte[8192]; - while (true) { - // scan through file to compute a fingerprint. - int n = in.read(bytes); - if (n < 0) break; - count += n; - } - } finally { - if (in != null) in.close(); - } - if ((byteCount != null) && (byteCount.length > 0)) byteCount[0] = count; - return new Fingerprint(in.getMessageDigest().digest()); - } - - /** - * Decodes a string stream id to a 128-bit fingerprint. - */ - public static Fingerprint fromStreamId(String streamId) { - if ((streamId == null) - || !streamId.startsWith(STREAM_ID_CS_PREFIX) - || (streamId.length() != STREAM_ID_CS_01_LENGTH)) { - throw new IllegalArgumentException("bad streamId: " + streamId); - } - - // decode the hex bytes of the fingerprint portion - byte[] bytes = new byte[FINGERPRINT_BYTE_LENGTH]; - int byteIdx = 0; - for (int idx = STREAM_ID_CS_PREFIX.length(); idx < STREAM_ID_CS_01_LENGTH; - idx += 2) { - int value = (toDigit(streamId, idx) << 4) | toDigit(streamId, idx + 1); - bytes[byteIdx++] = (byte) (value & 0xff); - } - return new Fingerprint(bytes); - } - - /** - * Scans a list of strings for a valid streamId. - * - * @param streamIdList list of stream id's to be scanned - * @return valid fingerprint or null if it can't be found - */ - public static Fingerprint extractFingerprint(List streamIdList) { - for (String streamId : streamIdList) { - if (streamId.startsWith(STREAM_ID_CS_PREFIX)) { - return fromStreamId(streamId); - } - } - return null; - } - - /** - * Encodes a 128-bit fingerprint as a string stream id. - * - * Stream id string is limited to 40 characters, which could be digits, lower case ASCII and - * underscores. - */ - public String toStreamId() { - StringBuilder streamId = new StringBuilder(STREAM_ID_CS_PREFIX); - appendHexFingerprint(streamId, mMd5Digest); - return streamId.toString(); - } - - public byte[] getBytes() { - return mMd5Digest; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof Fingerprint)) return false; - Fingerprint other = (Fingerprint) obj; - return Arrays.equals(mMd5Digest, other.mMd5Digest); - } - - public boolean equals(byte[] md5Digest) { - return Arrays.equals(mMd5Digest, md5Digest); - } - - @Override - public int hashCode() { - return Arrays.hashCode(mMd5Digest); - } - - // Utility methods. - - private static int toDigit(String streamId, int index) { - int digit = Character.digit(streamId.charAt(index), 16); - if (digit < 0) { - throw new IllegalArgumentException("illegal hex digit in " + streamId); - } - return digit; - } - - private static void appendHexFingerprint(StringBuilder sb, byte[] bytes) { - for (int idx = 0; idx < FINGERPRINT_BYTE_LENGTH; idx++) { - int value = bytes[idx]; - sb.append(Integer.toHexString((value >> 4) & 0x0f)); - sb.append(Integer.toHexString(value& 0x0f)); - } - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/HttpClientFactory.java b/gallerycommon/src/com/android/gallery3d/common/HttpClientFactory.java deleted file mode 100644 index 18b7a8875..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/HttpClientFactory.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Build; - -import org.apache.http.HttpVersion; -import org.apache.http.client.HttpClient; -import org.apache.http.conn.params.ConnManagerParams; -import org.apache.http.params.CoreProtocolPNames; -import org.apache.http.params.HttpParams; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Constructs {@link HttpClient} instances and isolates client code from API - * level differences. - */ -public final class HttpClientFactory { - // TODO: migrate GDataClient to use this util method instead of apache's - // DefaultHttpClient. - /** - * Creates an HttpClient with the userAgent string constructed from the - * package name contained in the context. - * @return the client - */ - public static HttpClient newHttpClient(Context context) { - return HttpClientFactory.newHttpClient(getUserAgent(context)); - } - - /** - * Creates an HttpClient with the specified userAgent string. - * @param userAgent the userAgent string - * @return the client - */ - public static HttpClient newHttpClient(String userAgent) { - // AndroidHttpClient is available on all platform releases, - // but is hidden until API Level 8 - try { - Class clazz = Class.forName("android.net.http.AndroidHttpClient"); - Method newInstance = clazz.getMethod("newInstance", String.class); - Object instance = newInstance.invoke(null, userAgent); - - HttpClient client = (HttpClient) instance; - - // ensure we default to HTTP 1.1 - HttpParams params = client.getParams(); - params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); - - // AndroidHttpClient sets these two parameters thusly by default: - // HttpConnectionParams.setSoTimeout(params, 60 * 1000); - // HttpConnectionParams.setConnectionTimeout(params, 60 * 1000); - - // however it doesn't set this one... - ConnManagerParams.setTimeout(params, 60 * 1000); - - return client; - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** - * Closes an HttpClient. - */ - public static void close(HttpClient client) { - // AndroidHttpClient is available on all platform releases, - // but is hidden until API Level 8 - try { - Class clazz = client.getClass(); - Method method = clazz.getMethod("close", (Class[]) null); - method.invoke(client, (Object[]) null); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - private static String sUserAgent = null; - - private static String getUserAgent(Context context) { - if (sUserAgent == null) { - PackageInfo pi; - try { - pi = context.getPackageManager().getPackageInfo( - context.getPackageName(), 0); - } catch (NameNotFoundException e) { - throw new IllegalStateException("getPackageInfo failed"); - } - sUserAgent = String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s", - pi.packageName, - pi.versionName, - Build.BRAND, - Build.DEVICE, - Build.MODEL, - Build.ID, - Build.VERSION.SDK_INT, - Build.VERSION.RELEASE, - Build.VERSION.INCREMENTAL); - } - return sUserAgent; - } - - private HttpClientFactory() { - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/LruCache.java b/gallerycommon/src/com/android/gallery3d/common/LruCache.java deleted file mode 100644 index 81dabf773..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/LruCache.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * An LRU cache which stores recently inserted entries and all entries ever - * inserted which still has a strong reference elsewhere. - */ -public class LruCache { - - private final HashMap mLruMap; - private final HashMap> mWeakMap = - new HashMap>(); - private ReferenceQueue mQueue = new ReferenceQueue(); - - @SuppressWarnings("serial") - public LruCache(final int capacity) { - mLruMap = new LinkedHashMap(16, 0.75f, true) { - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > capacity; - } - }; - } - - private static class Entry extends WeakReference { - K mKey; - - public Entry(K key, V value, ReferenceQueue queue) { - super(value, queue); - mKey = key; - } - } - - @SuppressWarnings("unchecked") - private void cleanUpWeakMap() { - Entry entry = (Entry) mQueue.poll(); - while (entry != null) { - mWeakMap.remove(entry.mKey); - entry = (Entry) mQueue.poll(); - } - } - - public synchronized boolean containsKey(K key) { - cleanUpWeakMap(); - return mWeakMap.containsKey(key); - } - - public synchronized V put(K key, V value) { - cleanUpWeakMap(); - mLruMap.put(key, value); - Entry entry = mWeakMap.put( - key, new Entry(key, value, mQueue)); - return entry == null ? null : entry.get(); - } - - public synchronized V get(K key) { - cleanUpWeakMap(); - V value = mLruMap.get(key); - if (value != null) return value; - Entry entry = mWeakMap.get(key); - return entry == null ? null : entry.get(); - } - - public synchronized void clear() { - mLruMap.clear(); - mWeakMap.clear(); - mQueue = new ReferenceQueue(); - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/OverScroller.java b/gallerycommon/src/com/android/gallery3d/common/OverScroller.java deleted file mode 100644 index 1ab7953d2..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/OverScroller.java +++ /dev/null @@ -1,958 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import android.content.Context; -import android.hardware.SensorManager; -import android.util.FloatMath; -import android.util.Log; -import android.view.ViewConfiguration; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; - -/** - * This class encapsulates scrolling with the ability to overshoot the bounds - * of a scrolling operation. This class is a drop-in replacement for - * {@link android.widget.Scroller} in most cases. - */ -public class OverScroller { - private int mMode; - - private final SplineOverScroller mScrollerX; - private final SplineOverScroller mScrollerY; - - private Interpolator mInterpolator; - - private final boolean mFlywheel; - - private static final int DEFAULT_DURATION = 250; - private static final int SCROLL_MODE = 0; - private static final int FLING_MODE = 1; - - /** - * Creates an OverScroller with a viscous fluid scroll interpolator and flywheel. - * @param context - */ - public OverScroller(Context context) { - this(context, null); - } - - /** - * Creates an OverScroller with flywheel enabled. - * @param context The context of this application. - * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will - * be used. - */ - public OverScroller(Context context, Interpolator interpolator) { - this(context, interpolator, true); - } - - /** - * Creates an OverScroller. - * @param context The context of this application. - * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will - * be used. - * @param flywheel If true, successive fling motions will keep on increasing scroll speed. - * @hide - */ - public OverScroller(Context context, Interpolator interpolator, boolean flywheel) { - mInterpolator = interpolator; - mFlywheel = flywheel; - mScrollerX = new SplineOverScroller(); - mScrollerY = new SplineOverScroller(); - - SplineOverScroller.initFromContext(context); - } - - /** - * Creates an OverScroller with flywheel enabled. - * @param context The context of this application. - * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will - * be used. - * @param bounceCoefficientX A value between 0 and 1 that will determine the proportion of the - * velocity which is preserved in the bounce when the horizontal edge is reached. A null value - * means no bounce. This behavior is no longer supported and this coefficient has no effect. - * @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction. This - * behavior is no longer supported and this coefficient has no effect. - * !deprecated Use {!link #OverScroller(Context, Interpolator, boolean)} instead. - */ - public OverScroller(Context context, Interpolator interpolator, - float bounceCoefficientX, float bounceCoefficientY) { - this(context, interpolator, true); - } - - /** - * Creates an OverScroller. - * @param context The context of this application. - * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will - * be used. - * @param bounceCoefficientX A value between 0 and 1 that will determine the proportion of the - * velocity which is preserved in the bounce when the horizontal edge is reached. A null value - * means no bounce. This behavior is no longer supported and this coefficient has no effect. - * @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction. This - * behavior is no longer supported and this coefficient has no effect. - * @param flywheel If true, successive fling motions will keep on increasing scroll speed. - * !deprecated Use {!link OverScroller(Context, Interpolator, boolean)} instead. - */ - public OverScroller(Context context, Interpolator interpolator, - float bounceCoefficientX, float bounceCoefficientY, boolean flywheel) { - this(context, interpolator, flywheel); - } - - void setInterpolator(Interpolator interpolator) { - mInterpolator = interpolator; - } - - /** - * The amount of friction applied to flings. The default value - * is {@link ViewConfiguration#getScrollFriction}. - * - * @param friction A scalar dimension-less value representing the coefficient of - * friction. - */ - public final void setFriction(float friction) { - mScrollerX.setFriction(friction); - mScrollerY.setFriction(friction); - } - - /** - * - * Returns whether the scroller has finished scrolling. - * - * @return True if the scroller has finished scrolling, false otherwise. - */ - public final boolean isFinished() { - return mScrollerX.mFinished && mScrollerY.mFinished; - } - - /** - * Force the finished field to a particular value. Contrary to - * {@link #abortAnimation()}, forcing the animation to finished - * does NOT cause the scroller to move to the final x and y - * position. - * - * @param finished The new finished value. - */ - public final void forceFinished(boolean finished) { - mScrollerX.mFinished = mScrollerY.mFinished = finished; - } - - /** - * Returns the current X offset in the scroll. - * - * @return The new X offset as an absolute distance from the origin. - */ - public final int getCurrX() { - return mScrollerX.mCurrentPosition; - } - - /** - * Returns the current Y offset in the scroll. - * - * @return The new Y offset as an absolute distance from the origin. - */ - public final int getCurrY() { - return mScrollerY.mCurrentPosition; - } - - /** - * Returns the absolute value of the current velocity. - * - * @return The original velocity less the deceleration, norm of the X and Y velocity vector. - */ - public float getCurrVelocity() { - float squaredNorm = mScrollerX.mCurrVelocity * mScrollerX.mCurrVelocity; - squaredNorm += mScrollerY.mCurrVelocity * mScrollerY.mCurrVelocity; - return FloatMath.sqrt(squaredNorm); - } - - /** - * Returns the start X offset in the scroll. - * - * @return The start X offset as an absolute distance from the origin. - */ - public final int getStartX() { - return mScrollerX.mStart; - } - - /** - * Returns the start Y offset in the scroll. - * - * @return The start Y offset as an absolute distance from the origin. - */ - public final int getStartY() { - return mScrollerY.mStart; - } - - /** - * Returns where the scroll will end. Valid only for "fling" scrolls. - * - * @return The final X offset as an absolute distance from the origin. - */ - public final int getFinalX() { - return mScrollerX.mFinal; - } - - /** - * Returns where the scroll will end. Valid only for "fling" scrolls. - * - * @return The final Y offset as an absolute distance from the origin. - */ - public final int getFinalY() { - return mScrollerY.mFinal; - } - - /** - * Returns how long the scroll event will take, in milliseconds. - * - * @return The duration of the scroll in milliseconds. - * - * @hide Pending removal once nothing depends on it - * @deprecated OverScrollers don't necessarily have a fixed duration. - * This function will lie to the best of its ability. - */ - @Deprecated - public final int getDuration() { - return Math.max(mScrollerX.mDuration, mScrollerY.mDuration); - } - - /** - * Extend the scroll animation. This allows a running animation to scroll - * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}. - * - * @param extend Additional time to scroll in milliseconds. - * @see #setFinalX(int) - * @see #setFinalY(int) - * - * @hide Pending removal once nothing depends on it - * @deprecated OverScrollers don't necessarily have a fixed duration. - * Instead of setting a new final position and extending - * the duration of an existing scroll, use startScroll - * to begin a new animation. - */ - @Deprecated - public void extendDuration(int extend) { - mScrollerX.extendDuration(extend); - mScrollerY.extendDuration(extend); - } - - /** - * Sets the final position (X) for this scroller. - * - * @param newX The new X offset as an absolute distance from the origin. - * @see #extendDuration(int) - * @see #setFinalY(int) - * - * @hide Pending removal once nothing depends on it - * @deprecated OverScroller's final position may change during an animation. - * Instead of setting a new final position and extending - * the duration of an existing scroll, use startScroll - * to begin a new animation. - */ - @Deprecated - public void setFinalX(int newX) { - mScrollerX.setFinalPosition(newX); - } - - /** - * Sets the final position (Y) for this scroller. - * - * @param newY The new Y offset as an absolute distance from the origin. - * @see #extendDuration(int) - * @see #setFinalX(int) - * - * @hide Pending removal once nothing depends on it - * @deprecated OverScroller's final position may change during an animation. - * Instead of setting a new final position and extending - * the duration of an existing scroll, use startScroll - * to begin a new animation. - */ - @Deprecated - public void setFinalY(int newY) { - mScrollerY.setFinalPosition(newY); - } - - /** - * Call this when you want to know the new location. If it returns true, the - * animation is not yet finished. - */ - public boolean computeScrollOffset() { - if (isFinished()) { - return false; - } - - switch (mMode) { - case SCROLL_MODE: - long time = AnimationUtils.currentAnimationTimeMillis(); - // Any scroller can be used for time, since they were started - // together in scroll mode. We use X here. - final long elapsedTime = time - mScrollerX.mStartTime; - - final int duration = mScrollerX.mDuration; - if (elapsedTime < duration) { - float q = (float) (elapsedTime) / duration; - - if (mInterpolator == null) { - q = Scroller.viscousFluid(q); - } else { - q = mInterpolator.getInterpolation(q); - } - - mScrollerX.updateScroll(q); - mScrollerY.updateScroll(q); - } else { - abortAnimation(); - } - break; - - case FLING_MODE: - if (!mScrollerX.mFinished) { - if (!mScrollerX.update()) { - if (!mScrollerX.continueWhenFinished()) { - mScrollerX.finish(); - } - } - } - - if (!mScrollerY.mFinished) { - if (!mScrollerY.update()) { - if (!mScrollerY.continueWhenFinished()) { - mScrollerY.finish(); - } - } - } - - break; - } - - return true; - } - - /** - * Start scrolling by providing a starting point and the distance to travel. - * The scroll will use the default value of 250 milliseconds for the - * duration. - * - * @param startX Starting horizontal scroll offset in pixels. Positive - * numbers will scroll the content to the left. - * @param startY Starting vertical scroll offset in pixels. Positive numbers - * will scroll the content up. - * @param dx Horizontal distance to travel. Positive numbers will scroll the - * content to the left. - * @param dy Vertical distance to travel. Positive numbers will scroll the - * content up. - */ - public void startScroll(int startX, int startY, int dx, int dy) { - startScroll(startX, startY, dx, dy, DEFAULT_DURATION); - } - - /** - * Start scrolling by providing a starting point and the distance to travel. - * - * @param startX Starting horizontal scroll offset in pixels. Positive - * numbers will scroll the content to the left. - * @param startY Starting vertical scroll offset in pixels. Positive numbers - * will scroll the content up. - * @param dx Horizontal distance to travel. Positive numbers will scroll the - * content to the left. - * @param dy Vertical distance to travel. Positive numbers will scroll the - * content up. - * @param duration Duration of the scroll in milliseconds. - */ - public void startScroll(int startX, int startY, int dx, int dy, int duration) { - mMode = SCROLL_MODE; - mScrollerX.startScroll(startX, dx, duration); - mScrollerY.startScroll(startY, dy, duration); - } - - /** - * Call this when you want to 'spring back' into a valid coordinate range. - * - * @param startX Starting X coordinate - * @param startY Starting Y coordinate - * @param minX Minimum valid X value - * @param maxX Maximum valid X value - * @param minY Minimum valid Y value - * @param maxY Minimum valid Y value - * @return true if a springback was initiated, false if startX and startY were - * already within the valid range. - */ - public boolean springBack(int startX, int startY, int minX, int maxX, int minY, int maxY) { - mMode = FLING_MODE; - - // Make sure both methods are called. - final boolean spingbackX = mScrollerX.springback(startX, minX, maxX); - final boolean spingbackY = mScrollerY.springback(startY, minY, maxY); - return spingbackX || spingbackY; - } - - public void fling(int startX, int startY, int velocityX, int velocityY, - int minX, int maxX, int minY, int maxY) { - fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0); - } - - /** - * Start scrolling based on a fling gesture. The distance traveled will - * depend on the initial velocity of the fling. - * - * @param startX Starting point of the scroll (X) - * @param startY Starting point of the scroll (Y) - * @param velocityX Initial velocity of the fling (X) measured in pixels per - * second. - * @param velocityY Initial velocity of the fling (Y) measured in pixels per - * second - * @param minX Minimum X value. The scroller will not scroll past this point - * unless overX > 0. If overfling is allowed, it will use minX as - * a springback boundary. - * @param maxX Maximum X value. The scroller will not scroll past this point - * unless overX > 0. If overfling is allowed, it will use maxX as - * a springback boundary. - * @param minY Minimum Y value. The scroller will not scroll past this point - * unless overY > 0. If overfling is allowed, it will use minY as - * a springback boundary. - * @param maxY Maximum Y value. The scroller will not scroll past this point - * unless overY > 0. If overfling is allowed, it will use maxY as - * a springback boundary. - * @param overX Overfling range. If > 0, horizontal overfling in either - * direction will be possible. - * @param overY Overfling range. If > 0, vertical overfling in either - * direction will be possible. - */ - public void fling(int startX, int startY, int velocityX, int velocityY, - int minX, int maxX, int minY, int maxY, int overX, int overY) { - // Continue a scroll or fling in progress - if (mFlywheel && !isFinished()) { - float oldVelocityX = mScrollerX.mCurrVelocity; - float oldVelocityY = mScrollerY.mCurrVelocity; - if (Math.signum(velocityX) == Math.signum(oldVelocityX) && - Math.signum(velocityY) == Math.signum(oldVelocityY)) { - velocityX += oldVelocityX; - velocityY += oldVelocityY; - } - } - - mMode = FLING_MODE; - mScrollerX.fling(startX, velocityX, minX, maxX, overX); - mScrollerY.fling(startY, velocityY, minY, maxY, overY); - } - - /** - * Notify the scroller that we've reached a horizontal boundary. - * Normally the information to handle this will already be known - * when the animation is started, such as in a call to one of the - * fling functions. However there are cases where this cannot be known - * in advance. This function will transition the current motion and - * animate from startX to finalX as appropriate. - * - * @param startX Starting/current X position - * @param finalX Desired final X position - * @param overX Magnitude of overscroll allowed. This should be the maximum - * desired distance from finalX. Absolute value - must be positive. - */ - public void notifyHorizontalEdgeReached(int startX, int finalX, int overX) { - mScrollerX.notifyEdgeReached(startX, finalX, overX); - } - - /** - * Notify the scroller that we've reached a vertical boundary. - * Normally the information to handle this will already be known - * when the animation is started, such as in a call to one of the - * fling functions. However there are cases where this cannot be known - * in advance. This function will animate a parabolic motion from - * startY to finalY. - * - * @param startY Starting/current Y position - * @param finalY Desired final Y position - * @param overY Magnitude of overscroll allowed. This should be the maximum - * desired distance from finalY. Absolute value - must be positive. - */ - public void notifyVerticalEdgeReached(int startY, int finalY, int overY) { - mScrollerY.notifyEdgeReached(startY, finalY, overY); - } - - /** - * Returns whether the current Scroller is currently returning to a valid position. - * Valid bounds were provided by the - * {@link #fling(int, int, int, int, int, int, int, int, int, int)} method. - * - * One should check this value before calling - * {@link #startScroll(int, int, int, int)} as the interpolation currently in progress - * to restore a valid position will then be stopped. The caller has to take into account - * the fact that the started scroll will start from an overscrolled position. - * - * @return true when the current position is overscrolled and in the process of - * interpolating back to a valid value. - */ - public boolean isOverScrolled() { - return ((!mScrollerX.mFinished && - mScrollerX.mState != SplineOverScroller.SPLINE) || - (!mScrollerY.mFinished && - mScrollerY.mState != SplineOverScroller.SPLINE)); - } - - /** - * Stops the animation. Contrary to {@link #forceFinished(boolean)}, - * aborting the animating causes the scroller to move to the final x and y - * positions. - * - * @see #forceFinished(boolean) - */ - public void abortAnimation() { - mScrollerX.finish(); - mScrollerY.finish(); - } - - /** - * Returns the time elapsed since the beginning of the scrolling. - * - * @return The elapsed time in milliseconds. - * - * @hide - */ - public int timePassed() { - final long time = AnimationUtils.currentAnimationTimeMillis(); - final long startTime = Math.min(mScrollerX.mStartTime, mScrollerY.mStartTime); - return (int) (time - startTime); - } - - /** - * @hide - */ - public boolean isScrollingInDirection(float xvel, float yvel) { - final int dx = mScrollerX.mFinal - mScrollerX.mStart; - final int dy = mScrollerY.mFinal - mScrollerY.mStart; - return !isFinished() && Math.signum(xvel) == Math.signum(dx) && - Math.signum(yvel) == Math.signum(dy); - } - - static class SplineOverScroller { - // Initial position - private int mStart; - - // Current position - private int mCurrentPosition; - - // Final position - private int mFinal; - - // Initial velocity - private int mVelocity; - - // Current velocity - private float mCurrVelocity; - - // Constant current deceleration - private float mDeceleration; - - // Animation starting time, in system milliseconds - private long mStartTime; - - // Animation duration, in milliseconds - private int mDuration; - - // Duration to complete spline component of animation - private int mSplineDuration; - - // Distance to travel along spline animation - private int mSplineDistance; - - // Whether the animation is currently in progress - private boolean mFinished; - - // The allowed overshot distance before boundary is reached. - private int mOver; - - // Fling friction - private float mFlingFriction = ViewConfiguration.getScrollFriction(); - - // Current state of the animation. - private int mState = SPLINE; - - // Constant gravity value, used in the deceleration phase. - private static final float GRAVITY = 2000.0f; - - // A device specific coefficient adjusted to physical values. - private static float PHYSICAL_COEF; - - private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9)); - private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1) - private static final float START_TENSION = 0.5f; - private static final float END_TENSION = 1.0f; - private static final float P1 = START_TENSION * INFLEXION; - private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION); - - private static final int NB_SAMPLES = 100; - private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1]; - private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1]; - - private static final int SPLINE = 0; - private static final int CUBIC = 1; - private static final int BALLISTIC = 2; - - static { - float x_min = 0.0f; - float y_min = 0.0f; - for (int i = 0; i < NB_SAMPLES; i++) { - final float alpha = (float) i / NB_SAMPLES; - - float x_max = 1.0f; - float x, tx, coef; - while (true) { - x = x_min + (x_max - x_min) / 2.0f; - coef = 3.0f * x * (1.0f - x); - tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x; - if (Math.abs(tx - alpha) < 1E-5) break; - if (tx > alpha) x_max = x; - else x_min = x; - } - SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x; - - float y_max = 1.0f; - float y, dy; - while (true) { - y = y_min + (y_max - y_min) / 2.0f; - coef = 3.0f * y * (1.0f - y); - dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y; - if (Math.abs(dy - alpha) < 1E-5) break; - if (dy > alpha) y_max = y; - else y_min = y; - } - SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y; - } - SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f; - } - - static void initFromContext(Context context) { - final float ppi = context.getResources().getDisplayMetrics().density * 160.0f; - PHYSICAL_COEF = SensorManager.GRAVITY_EARTH // g (m/s^2) - * 39.37f // inch/meter - * ppi - * 0.84f; // look and feel tuning - } - - void setFriction(float friction) { - mFlingFriction = friction; - } - - SplineOverScroller() { - mFinished = true; - } - - void updateScroll(float q) { - mCurrentPosition = mStart + Math.round(q * (mFinal - mStart)); - } - - /* - * Get a signed deceleration that will reduce the velocity. - */ - static private float getDeceleration(int velocity) { - return velocity > 0 ? -GRAVITY : GRAVITY; - } - - /* - * Modifies mDuration to the duration it takes to get from start to newFinal using the - * spline interpolation. The previous duration was needed to get to oldFinal. - */ - private void adjustDuration(int start, int oldFinal, int newFinal) { - final int oldDistance = oldFinal - start; - final int newDistance = newFinal - start; - final float x = Math.abs((float) newDistance / oldDistance); - final int index = (int) (NB_SAMPLES * x); - if (index < NB_SAMPLES) { - final float x_inf = (float) index / NB_SAMPLES; - final float x_sup = (float) (index + 1) / NB_SAMPLES; - final float t_inf = SPLINE_TIME[index]; - final float t_sup = SPLINE_TIME[index + 1]; - final float timeCoef = t_inf + (x - x_inf) / (x_sup - x_inf) * (t_sup - t_inf); - mDuration *= timeCoef; - } - } - - void startScroll(int start, int distance, int duration) { - mFinished = false; - - mStart = start; - mFinal = start + distance; - - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mDuration = duration; - - // Unused - mDeceleration = 0.0f; - mVelocity = 0; - } - - void finish() { - mCurrentPosition = mFinal; - // Not reset since WebView relies on this value for fast fling. - // TODO: restore when WebView uses the fast fling implemented in this class. - // mCurrVelocity = 0.0f; - mFinished = true; - } - - void setFinalPosition(int position) { - mFinal = position; - mFinished = false; - } - - void extendDuration(int extend) { - final long time = AnimationUtils.currentAnimationTimeMillis(); - final int elapsedTime = (int) (time - mStartTime); - mDuration = elapsedTime + extend; - mFinished = false; - } - - boolean springback(int start, int min, int max) { - mFinished = true; - - mStart = mFinal = start; - mVelocity = 0; - - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mDuration = 0; - - if (start < min) { - startSpringback(start, min, 0); - } else if (start > max) { - startSpringback(start, max, 0); - } - - return !mFinished; - } - - private void startSpringback(int start, int end, int velocity) { - // mStartTime has been set - mFinished = false; - mState = CUBIC; - mStart = start; - mFinal = end; - final int delta = start - end; - mDeceleration = getDeceleration(delta); - // TODO take velocity into account - mVelocity = -delta; // only sign is used - mOver = Math.abs(delta); - mDuration = (int) (1000.0 * Math.sqrt(-2.0 * delta / mDeceleration)); - } - - void fling(int start, int velocity, int min, int max, int over) { - mOver = over; - mFinished = false; - mCurrVelocity = mVelocity = velocity; - mDuration = mSplineDuration = 0; - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mCurrentPosition = mStart = start; - - if (start > max || start < min) { - startAfterEdge(start, min, max, velocity); - return; - } - - mState = SPLINE; - double totalDistance = 0.0; - - if (velocity != 0) { - mDuration = mSplineDuration = getSplineFlingDuration(velocity); - totalDistance = getSplineFlingDistance(velocity); - } - - mSplineDistance = (int) (totalDistance * Math.signum(velocity)); - mFinal = start + mSplineDistance; - - // Clamp to a valid final position - if (mFinal < min) { - adjustDuration(mStart, mFinal, min); - mFinal = min; - } - - if (mFinal > max) { - adjustDuration(mStart, mFinal, max); - mFinal = max; - } - } - - private double getSplineDeceleration(int velocity) { - return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * PHYSICAL_COEF)); - } - - private double getSplineFlingDistance(int velocity) { - final double l = getSplineDeceleration(velocity); - final double decelMinusOne = DECELERATION_RATE - 1.0; - return mFlingFriction * PHYSICAL_COEF * Math.exp(DECELERATION_RATE / decelMinusOne * l); - } - - /* Returns the duration, expressed in milliseconds */ - private int getSplineFlingDuration(int velocity) { - final double l = getSplineDeceleration(velocity); - final double decelMinusOne = DECELERATION_RATE - 1.0; - return (int) (1000.0 * Math.exp(l / decelMinusOne)); - } - - private void fitOnBounceCurve(int start, int end, int velocity) { - // Simulate a bounce that started from edge - final float durationToApex = - velocity / mDeceleration; - final float distanceToApex = velocity * velocity / 2.0f / Math.abs(mDeceleration); - final float distanceToEdge = Math.abs(end - start); - final float totalDuration = (float) Math.sqrt( - 2.0 * (distanceToApex + distanceToEdge) / Math.abs(mDeceleration)); - mStartTime -= (int) (1000.0f * (totalDuration - durationToApex)); - mStart = end; - mVelocity = (int) (- mDeceleration * totalDuration); - } - - private void startBounceAfterEdge(int start, int end, int velocity) { - mDeceleration = getDeceleration(velocity == 0 ? start - end : velocity); - fitOnBounceCurve(start, end, velocity); - onEdgeReached(); - } - - private void startAfterEdge(int start, int min, int max, int velocity) { - if (start > min && start < max) { - Log.e("OverScroller", "startAfterEdge called from a valid position"); - mFinished = true; - return; - } - final boolean positive = start > max; - final int edge = positive ? max : min; - final int overDistance = start - edge; - boolean keepIncreasing = overDistance * velocity >= 0; - if (keepIncreasing) { - // Will result in a bounce or a to_boundary depending on velocity. - startBounceAfterEdge(start, edge, velocity); - } else { - final double totalDistance = getSplineFlingDistance(velocity); - if (totalDistance > Math.abs(overDistance)) { - fling(start, velocity, positive ? min : start, positive ? start : max, mOver); - } else { - startSpringback(start, edge, velocity); - } - } - } - - void notifyEdgeReached(int start, int end, int over) { - // mState is used to detect successive notifications - if (mState == SPLINE) { - mOver = over; - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - // We were in fling/scroll mode before: current velocity is such that distance to - // edge is increasing. This ensures that startAfterEdge will not start a new fling. - startAfterEdge(start, end, end, (int) mCurrVelocity); - } - } - - private void onEdgeReached() { - // mStart, mVelocity and mStartTime were adjusted to their values when edge was reached. - float distance = mVelocity * mVelocity / (2.0f * Math.abs(mDeceleration)); - final float sign = Math.signum(mVelocity); - - if (distance > mOver) { - // Default deceleration is not sufficient to slow us down before boundary - mDeceleration = - sign * mVelocity * mVelocity / (2.0f * mOver); - distance = mOver; - } - - mOver = (int) distance; - mState = BALLISTIC; - mFinal = mStart + (int) (mVelocity > 0 ? distance : -distance); - mDuration = - (int) (1000.0f * mVelocity / mDeceleration); - } - - boolean continueWhenFinished() { - switch (mState) { - case SPLINE: - // Duration from start to null velocity - if (mDuration < mSplineDuration) { - // If the animation was clamped, we reached the edge - mStart = mFinal; - // TODO Better compute speed when edge was reached - mVelocity = (int) mCurrVelocity; - mDeceleration = getDeceleration(mVelocity); - mStartTime += mDuration; - onEdgeReached(); - } else { - // Normal stop, no need to continue - return false; - } - break; - case BALLISTIC: - mStartTime += mDuration; - startSpringback(mFinal, mStart, 0); - break; - case CUBIC: - return false; - } - - update(); - return true; - } - - /* - * Update the current position and velocity for current time. Returns - * true if update has been done and false if animation duration has been - * reached. - */ - boolean update() { - final long time = AnimationUtils.currentAnimationTimeMillis(); - final long currentTime = time - mStartTime; - - if (currentTime > mDuration) { - return false; - } - - double distance = 0.0; - switch (mState) { - case SPLINE: { - final float t = (float) currentTime / mSplineDuration; - final int index = (int) (NB_SAMPLES * t); - float distanceCoef = 1.f; - float velocityCoef = 0.f; - if (index < NB_SAMPLES) { - final float t_inf = (float) index / NB_SAMPLES; - final float t_sup = (float) (index + 1) / NB_SAMPLES; - final float d_inf = SPLINE_POSITION[index]; - final float d_sup = SPLINE_POSITION[index + 1]; - velocityCoef = (d_sup - d_inf) / (t_sup - t_inf); - distanceCoef = d_inf + (t - t_inf) * velocityCoef; - } - - distance = distanceCoef * mSplineDistance; - mCurrVelocity = velocityCoef * mSplineDistance / mSplineDuration * 1000.0f; - break; - } - - case BALLISTIC: { - final float t = currentTime / 1000.0f; - mCurrVelocity = mVelocity + mDeceleration * t; - distance = mVelocity * t + mDeceleration * t * t / 2.0f; - break; - } - - case CUBIC: { - final float t = (float) (currentTime) / mDuration; - final float t2 = t * t; - final float sign = Math.signum(mVelocity); - distance = sign * mOver * (3.0f * t2 - 2.0f * t * t2); - mCurrVelocity = sign * mOver * 6.0f * (- t + t2); - break; - } - } - - mCurrentPosition = mStart + (int) Math.round(distance); - - return true; - } - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/Scroller.java b/gallerycommon/src/com/android/gallery3d/common/Scroller.java deleted file mode 100644 index 6cefd6fb0..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/Scroller.java +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import android.content.Context; -import android.hardware.SensorManager; -import android.os.Build; -import android.util.FloatMath; -import android.view.ViewConfiguration; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; - - -/** - * This class encapsulates scrolling. The duration of the scroll - * can be passed in the constructor and specifies the maximum time that - * the scrolling animation should take. Past this time, the scrolling is - * automatically moved to its final stage and computeScrollOffset() - * will always return false to indicate that scrolling is over. - */ -public class Scroller { - private int mMode; - - private int mStartX; - private int mStartY; - private int mFinalX; - private int mFinalY; - - private int mMinX; - private int mMaxX; - private int mMinY; - private int mMaxY; - - private int mCurrX; - private int mCurrY; - private long mStartTime; - private int mDuration; - private float mDurationReciprocal; - private float mDeltaX; - private float mDeltaY; - private boolean mFinished; - private Interpolator mInterpolator; - private boolean mFlywheel; - - private float mVelocity; - - private static final int DEFAULT_DURATION = 250; - private static final int SCROLL_MODE = 0; - private static final int FLING_MODE = 1; - - private static float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9)); - private static float ALPHA = 800; // pixels / seconds - private static float START_TENSION = 0.4f; // Tension at start: (0.4 * total T, 1.0 * Distance) - private static float END_TENSION = 1.0f - START_TENSION; - private static final int NB_SAMPLES = 100; - private static final float[] SPLINE = new float[NB_SAMPLES + 1]; - - private float mDeceleration; - private final float mPpi; - - static { - float x_min = 0.0f; - for (int i = 0; i <= NB_SAMPLES; i++) { - final float t = (float) i / NB_SAMPLES; - float x_max = 1.0f; - float x, tx, coef; - while (true) { - x = x_min + (x_max - x_min) / 2.0f; - coef = 3.0f * x * (1.0f - x); - tx = coef * ((1.0f - x) * START_TENSION + x * END_TENSION) + x * x * x; - if (Math.abs(tx - t) < 1E-5) break; - if (tx > t) x_max = x; - else x_min = x; - } - final float d = coef + x * x * x; - SPLINE[i] = d; - } - SPLINE[NB_SAMPLES] = 1.0f; - - // This controls the viscous fluid effect (how much of it) - sViscousFluidScale = 8.0f; - // must be set to 1.0 (used in viscousFluid()) - sViscousFluidNormalize = 1.0f; - sViscousFluidNormalize = 1.0f / viscousFluid(1.0f); - } - - private static float sViscousFluidScale; - private static float sViscousFluidNormalize; - - /** - * Create a Scroller with the default duration and interpolator. - */ - public Scroller(Context context) { - this(context, null); - } - - /** - * Create a Scroller with the specified interpolator. If the interpolator is - * null, the default (viscous) interpolator will be used. "Flywheel" behavior will - * be in effect for apps targeting Honeycomb or newer. - */ - public Scroller(Context context, Interpolator interpolator) { - this(context, interpolator, - context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB); - } - - /** - * Create a Scroller with the specified interpolator. If the interpolator is - * null, the default (viscous) interpolator will be used. Specify whether or - * not to support progressive "flywheel" behavior in flinging. - */ - public Scroller(Context context, Interpolator interpolator, boolean flywheel) { - mFinished = true; - mInterpolator = interpolator; - mPpi = context.getResources().getDisplayMetrics().density * 160.0f; - mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction()); - mFlywheel = flywheel; - } - - /** - * The amount of friction applied to flings. The default value - * is {@link ViewConfiguration#getScrollFriction}. - * - * @param friction A scalar dimension-less value representing the coefficient of - * friction. - */ - public final void setFriction(float friction) { - mDeceleration = computeDeceleration(friction); - } - - private float computeDeceleration(float friction) { - return SensorManager.GRAVITY_EARTH // g (m/s^2) - * 39.37f // inch/meter - * mPpi // pixels per inch - * friction; - } - - /** - * - * Returns whether the scroller has finished scrolling. - * - * @return True if the scroller has finished scrolling, false otherwise. - */ - public final boolean isFinished() { - return mFinished; - } - - /** - * Force the finished field to a particular value. - * - * @param finished The new finished value. - */ - public final void forceFinished(boolean finished) { - mFinished = finished; - } - - /** - * Returns how long the scroll event will take, in milliseconds. - * - * @return The duration of the scroll in milliseconds. - */ - public final int getDuration() { - return mDuration; - } - - /** - * Returns the current X offset in the scroll. - * - * @return The new X offset as an absolute distance from the origin. - */ - public final int getCurrX() { - return mCurrX; - } - - /** - * Returns the current Y offset in the scroll. - * - * @return The new Y offset as an absolute distance from the origin. - */ - public final int getCurrY() { - return mCurrY; - } - - /** - * Returns the current velocity. - * - * @return The original velocity less the deceleration. Result may be - * negative. - */ - public float getCurrVelocity() { - return mVelocity - mDeceleration * timePassed() / 2000.0f; - } - - /** - * Returns the start X offset in the scroll. - * - * @return The start X offset as an absolute distance from the origin. - */ - public final int getStartX() { - return mStartX; - } - - /** - * Returns the start Y offset in the scroll. - * - * @return The start Y offset as an absolute distance from the origin. - */ - public final int getStartY() { - return mStartY; - } - - /** - * Returns where the scroll will end. Valid only for "fling" scrolls. - * - * @return The final X offset as an absolute distance from the origin. - */ - public final int getFinalX() { - return mFinalX; - } - - /** - * Returns where the scroll will end. Valid only for "fling" scrolls. - * - * @return The final Y offset as an absolute distance from the origin. - */ - public final int getFinalY() { - return mFinalY; - } - - /** - * Call this when you want to know the new location. If it returns true, - * the animation is not yet finished. loc will be altered to provide the - * new location. - */ - public boolean computeScrollOffset() { - if (mFinished) { - return false; - } - - int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); - - if (timePassed < mDuration) { - switch (mMode) { - case SCROLL_MODE: - float x = timePassed * mDurationReciprocal; - - if (mInterpolator == null) - x = viscousFluid(x); - else - x = mInterpolator.getInterpolation(x); - - mCurrX = mStartX + Math.round(x * mDeltaX); - mCurrY = mStartY + Math.round(x * mDeltaY); - break; - case FLING_MODE: - final float t = (float) timePassed / mDuration; - final int index = (int) (NB_SAMPLES * t); - final float t_inf = (float) index / NB_SAMPLES; - final float t_sup = (float) (index + 1) / NB_SAMPLES; - final float d_inf = SPLINE[index]; - final float d_sup = SPLINE[index + 1]; - final float distanceCoef = d_inf + (t - t_inf) / (t_sup - t_inf) * (d_sup - d_inf); - - mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX)); - // Pin to mMinX <= mCurrX <= mMaxX - mCurrX = Math.min(mCurrX, mMaxX); - mCurrX = Math.max(mCurrX, mMinX); - - mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY)); - // Pin to mMinY <= mCurrY <= mMaxY - mCurrY = Math.min(mCurrY, mMaxY); - mCurrY = Math.max(mCurrY, mMinY); - - if (mCurrX == mFinalX && mCurrY == mFinalY) { - mFinished = true; - } - - break; - } - } - else { - mCurrX = mFinalX; - mCurrY = mFinalY; - mFinished = true; - } - return true; - } - - /** - * Start scrolling by providing a starting point and the distance to travel. - * The scroll will use the default value of 250 milliseconds for the - * duration. - * - * @param startX Starting horizontal scroll offset in pixels. Positive - * numbers will scroll the content to the left. - * @param startY Starting vertical scroll offset in pixels. Positive numbers - * will scroll the content up. - * @param dx Horizontal distance to travel. Positive numbers will scroll the - * content to the left. - * @param dy Vertical distance to travel. Positive numbers will scroll the - * content up. - */ - public void startScroll(int startX, int startY, int dx, int dy) { - startScroll(startX, startY, dx, dy, DEFAULT_DURATION); - } - - /** - * Start scrolling by providing a starting point and the distance to travel. - * - * @param startX Starting horizontal scroll offset in pixels. Positive - * numbers will scroll the content to the left. - * @param startY Starting vertical scroll offset in pixels. Positive numbers - * will scroll the content up. - * @param dx Horizontal distance to travel. Positive numbers will scroll the - * content to the left. - * @param dy Vertical distance to travel. Positive numbers will scroll the - * content up. - * @param duration Duration of the scroll in milliseconds. - */ - public void startScroll(int startX, int startY, int dx, int dy, int duration) { - mMode = SCROLL_MODE; - mFinished = false; - mDuration = duration; - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mStartX = startX; - mStartY = startY; - mFinalX = startX + dx; - mFinalY = startY + dy; - mDeltaX = dx; - mDeltaY = dy; - mDurationReciprocal = 1.0f / mDuration; - } - - /** - * Start scrolling based on a fling gesture. The distance travelled will - * depend on the initial velocity of the fling. - * - * @param startX Starting point of the scroll (X) - * @param startY Starting point of the scroll (Y) - * @param velocityX Initial velocity of the fling (X) measured in pixels per - * second. - * @param velocityY Initial velocity of the fling (Y) measured in pixels per - * second - * @param minX Minimum X value. The scroller will not scroll past this - * point. - * @param maxX Maximum X value. The scroller will not scroll past this - * point. - * @param minY Minimum Y value. The scroller will not scroll past this - * point. - * @param maxY Maximum Y value. The scroller will not scroll past this - * point. - */ - public void fling(int startX, int startY, int velocityX, int velocityY, - int minX, int maxX, int minY, int maxY) { - // Continue a scroll or fling in progress - if (mFlywheel && !mFinished) { - float oldVel = getCurrVelocity(); - - float dx = mFinalX - mStartX; - float dy = mFinalY - mStartY; - float hyp = FloatMath.sqrt(dx * dx + dy * dy); - - float ndx = dx / hyp; - float ndy = dy / hyp; - - float oldVelocityX = ndx * oldVel; - float oldVelocityY = ndy * oldVel; - if (Math.signum(velocityX) == Math.signum(oldVelocityX) && - Math.signum(velocityY) == Math.signum(oldVelocityY)) { - velocityX += oldVelocityX; - velocityY += oldVelocityY; - } - } - - mMode = FLING_MODE; - mFinished = false; - - float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY); - - mVelocity = velocity; - final double l = Math.log(START_TENSION * velocity / ALPHA); - mDuration = (int) (1000.0 * Math.exp(l / (DECELERATION_RATE - 1.0))); - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mStartX = startX; - mStartY = startY; - - float coeffX = velocity == 0 ? 1.0f : velocityX / velocity; - float coeffY = velocity == 0 ? 1.0f : velocityY / velocity; - - int totalDistance = - (int) (ALPHA * Math.exp(DECELERATION_RATE / (DECELERATION_RATE - 1.0) * l)); - - mMinX = minX; - mMaxX = maxX; - mMinY = minY; - mMaxY = maxY; - - mFinalX = startX + Math.round(totalDistance * coeffX); - // Pin to mMinX <= mFinalX <= mMaxX - mFinalX = Math.min(mFinalX, mMaxX); - mFinalX = Math.max(mFinalX, mMinX); - - mFinalY = startY + Math.round(totalDistance * coeffY); - // Pin to mMinY <= mFinalY <= mMaxY - mFinalY = Math.min(mFinalY, mMaxY); - mFinalY = Math.max(mFinalY, mMinY); - } - - static float viscousFluid(float x) - { - x *= sViscousFluidScale; - if (x < 1.0f) { - x -= (1.0f - (float)Math.exp(-x)); - } else { - float start = 0.36787944117f; // 1/e == exp(-1) - x = 1.0f - (float)Math.exp(1.0f - x); - x = start + x * (1.0f - start); - } - x *= sViscousFluidNormalize; - return x; - } - - /** - * Stops the animation. Contrary to {@link #forceFinished(boolean)}, - * aborting the animating cause the scroller to move to the final x and y - * position - * - * @see #forceFinished(boolean) - */ - public void abortAnimation() { - mCurrX = mFinalX; - mCurrY = mFinalY; - mFinished = true; - } - - /** - * Extend the scroll animation. This allows a running animation to scroll - * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}. - * - * @param extend Additional time to scroll in milliseconds. - * @see #setFinalX(int) - * @see #setFinalY(int) - */ - public void extendDuration(int extend) { - int passed = timePassed(); - mDuration = passed + extend; - mDurationReciprocal = 1.0f / mDuration; - mFinished = false; - } - - /** - * Returns the time elapsed since the beginning of the scrolling. - * - * @return The elapsed time in milliseconds. - */ - public int timePassed() { - return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); - } - - /** - * Sets the final position (X) for this scroller. - * - * @param newX The new X offset as an absolute distance from the origin. - * @see #extendDuration(int) - * @see #setFinalY(int) - */ - public void setFinalX(int newX) { - mFinalX = newX; - mDeltaX = mFinalX - mStartX; - mFinished = false; - } - - /** - * Sets the final position (Y) for this scroller. - * - * @param newY The new Y offset as an absolute distance from the origin. - * @see #extendDuration(int) - * @see #setFinalX(int) - */ - public void setFinalY(int newY) { - mFinalY = newY; - mDeltaY = mFinalY - mStartY; - mFinished = false; - } - - /** - * @hide - */ - public boolean isScrollingInDirection(float xvel, float yvel) { - return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) && - Math.signum(yvel) == Math.signum(mFinalY - mStartY); - } -} diff --git a/gallerycommon/src/com/android/gallery3d/common/Utils.java b/gallerycommon/src/com/android/gallery3d/common/Utils.java deleted file mode 100644 index 614a081c8..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/Utils.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.common; - -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.database.Cursor; -import android.os.Build; -import android.os.ParcelFileDescriptor; -import android.text.TextUtils; -import android.util.Log; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InterruptedIOException; - -public class Utils { - private static final String TAG = "Utils"; - private static final String DEBUG_TAG = "GalleryDebug"; - - private static final long POLY64REV = 0x95AC9329AC4BC9B5L; - private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL; - - private static long[] sCrcTable = new long[256]; - - private static final boolean IS_DEBUG_BUILD = - Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug"); - - private static final String MASK_STRING = "********************************"; - - // Throws AssertionError if the input is false. - public static void assertTrue(boolean cond) { - if (!cond) { - throw new AssertionError(); - } - } - - // Throws AssertionError with the message. We had a method having the form - // assertTrue(boolean cond, String message, Object ... args); - // However a call to that method will cause memory allocation even if the - // condition is false (due to autoboxing generated by "Object ... args"), - // so we don't use that anymore. - public static void fail(String message, Object ... args) { - throw new AssertionError( - args.length == 0 ? message : String.format(message, args)); - } - - // Throws NullPointerException if the input is null. - public static T checkNotNull(T object) { - if (object == null) throw new NullPointerException(); - return object; - } - - // Returns true if two input Object are both null or equal - // to each other. - public static boolean equals(Object a, Object b) { - return (a == b) || (a == null ? false : a.equals(b)); - } - - // Returns the next power of two. - // Returns the input if it is already power of 2. - // Throws IllegalArgumentException if the input is <= 0 or - // the answer overflows. - public static int nextPowerOf2(int n) { - if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException("n is invalid: " + n); - n -= 1; - n |= n >> 16; - n |= n >> 8; - n |= n >> 4; - n |= n >> 2; - n |= n >> 1; - return n + 1; - } - - // Returns the previous power of two. - // Returns the input if it is already power of 2. - // Throws IllegalArgumentException if the input is <= 0 - public static int prevPowerOf2(int n) { - if (n <= 0) throw new IllegalArgumentException(); - return Integer.highestOneBit(n); - } - - // Returns the input value x clamped to the range [min, max]. - public static int clamp(int x, int min, int max) { - if (x > max) return max; - if (x < min) return min; - return x; - } - - // Returns the input value x clamped to the range [min, max]. - public static float clamp(float x, float min, float max) { - if (x > max) return max; - if (x < min) return min; - return x; - } - - // Returns the input value x clamped to the range [min, max]. - public static long clamp(long x, long min, long max) { - if (x > max) return max; - if (x < min) return min; - return x; - } - - public static boolean isOpaque(int color) { - return color >>> 24 == 0xFF; - } - - public static void swap(int[] array, int i, int j) { - int temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } - - /** - * A function thats returns a 64-bit crc for string - * - * @param in input string - * @return a 64-bit crc value - */ - public static final long crc64Long(String in) { - if (in == null || in.length() == 0) { - return 0; - } - return crc64Long(getBytes(in)); - } - - static { - // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c - long part; - for (int i = 0; i < 256; i++) { - part = i; - for (int j = 0; j < 8; j++) { - long x = ((int) part & 1) != 0 ? POLY64REV : 0; - part = (part >> 1) ^ x; - } - sCrcTable[i] = part; - } - } - - public static final long crc64Long(byte[] buffer) { - long crc = INITIALCRC; - for (int k = 0, n = buffer.length; k < n; ++k) { - crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8); - } - return crc; - } - - public static byte[] getBytes(String in) { - byte[] result = new byte[in.length() * 2]; - int output = 0; - for (char ch : in.toCharArray()) { - result[output++] = (byte) (ch & 0xFF); - result[output++] = (byte) (ch >> 8); - } - return result; - } - - public static void closeSilently(Closeable c) { - if (c == null) return; - try { - c.close(); - } catch (IOException t) { - Log.w(TAG, "close fail ", t); - } - } - - public static int compare(long a, long b) { - return a < b ? -1 : a == b ? 0 : 1; - } - - public static int ceilLog2(float value) { - int i; - for (i = 0; i < 31; i++) { - if ((1 << i) >= value) break; - } - return i; - } - - public static int floorLog2(float value) { - int i; - for (i = 0; i < 31; i++) { - if ((1 << i) > value) break; - } - return i - 1; - } - - public static void closeSilently(ParcelFileDescriptor fd) { - try { - if (fd != null) fd.close(); - } catch (Throwable t) { - Log.w(TAG, "fail to close", t); - } - } - - public static void closeSilently(Cursor cursor) { - try { - if (cursor != null) cursor.close(); - } catch (Throwable t) { - Log.w(TAG, "fail to close", t); - } - } - - public static float interpolateAngle( - float source, float target, float progress) { - // interpolate the angle from source to target - // We make the difference in the range of [-179, 180], this is the - // shortest path to change source to target. - float diff = target - source; - if (diff < 0) diff += 360f; - if (diff > 180) diff -= 360f; - - float result = source + diff * progress; - return result < 0 ? result + 360f : result; - } - - public static float interpolateScale( - float source, float target, float progress) { - return source + progress * (target - source); - } - - public static String ensureNotNull(String value) { - return value == null ? "" : value; - } - - public static float parseFloatSafely(String content, float defaultValue) { - if (content == null) return defaultValue; - try { - return Float.parseFloat(content); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public static int parseIntSafely(String content, int defaultValue) { - if (content == null) return defaultValue; - try { - return Integer.parseInt(content); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public static boolean isNullOrEmpty(String exifMake) { - return TextUtils.isEmpty(exifMake); - } - - public static void waitWithoutInterrupt(Object object) { - try { - object.wait(); - } catch (InterruptedException e) { - Log.w(TAG, "unexpected interrupt: " + object); - } - } - - public static boolean handleInterrruptedException(Throwable e) { - // A helper to deal with the interrupt exception - // If an interrupt detected, we will setup the bit again. - if (e instanceof InterruptedIOException - || e instanceof InterruptedException) { - Thread.currentThread().interrupt(); - return true; - } - return false; - } - - /** - * @return String with special XML characters escaped. - */ - public static String escapeXml(String s) { - StringBuilder sb = new StringBuilder(); - for (int i = 0, len = s.length(); i < len; ++i) { - char c = s.charAt(i); - switch (c) { - case '<': sb.append("<"); break; - case '>': sb.append(">"); break; - case '\"': sb.append("""); break; - case '\'': sb.append("'"); break; - case '&': sb.append("&"); break; - default: sb.append(c); - } - } - return sb.toString(); - } - - public static String getUserAgent(Context context) { - PackageInfo packageInfo; - try { - packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); - } catch (NameNotFoundException e) { - throw new IllegalStateException("getPackageInfo failed"); - } - return String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s", - packageInfo.packageName, - packageInfo.versionName, - Build.BRAND, - Build.DEVICE, - Build.MODEL, - Build.ID, - Build.VERSION.SDK_INT, - Build.VERSION.RELEASE, - Build.VERSION.INCREMENTAL); - } - - public static String[] copyOf(String[] source, int newSize) { - String[] result = new String[newSize]; - newSize = Math.min(source.length, newSize); - System.arraycopy(source, 0, result, 0, newSize); - return result; - } - - // Mask information for debugging only. It returns info.toString() directly - // for debugging build (i.e., 'eng' and 'userdebug') and returns a mask ("****") - // in release build to protect the information (e.g. for privacy issue). - public static String maskDebugInfo(Object info) { - if (info == null) return null; - String s = info.toString(); - int length = Math.min(s.length(), MASK_STRING.length()); - return IS_DEBUG_BUILD ? s : MASK_STRING.substring(0, length); - } - - // This method should be ONLY used for debugging. - public static void debug(String message, Object ... args) { - Log.v(DEBUG_TAG, String.format(message, args)); - } -} diff --git a/gallerycommon/src/com/android/gallery3d/jpegstream/JPEGInputStream.java b/gallerycommon/src/com/android/gallery3d/jpegstream/JPEGInputStream.java deleted file mode 100644 index 44ccd4c6b..000000000 --- a/gallerycommon/src/com/android/gallery3d/jpegstream/JPEGInputStream.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.jpegstream; - -import android.graphics.Point; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -public class JPEGInputStream extends FilterInputStream { - private long JNIPointer = 0; // Used by JNI code. Don't touch. - - private boolean mValidConfig = false; - private boolean mConfigChanged = false; - private int mFormat = -1; - private byte[] mTmpBuffer = new byte[1]; - private int mWidth = 0; - private int mHeight = 0; - - public JPEGInputStream(InputStream in) { - super(in); - } - - public JPEGInputStream(InputStream in, int format) { - super(in); - setConfig(format); - } - - public boolean setConfig(int format) { - // Make sure format is valid - switch (format) { - case JpegConfig.FORMAT_GRAYSCALE: - case JpegConfig.FORMAT_RGB: - case JpegConfig.FORMAT_ABGR: - case JpegConfig.FORMAT_RGBA: - break; - default: - return false; - } - mFormat = format; - mValidConfig = true; - mConfigChanged = true; - return true; - } - - public Point getDimensions() throws IOException { - if (mValidConfig) { - applyConfigChange(); - return new Point(mWidth, mHeight); - } - return null; - } - - @Override - public int available() { - return 0; // TODO - } - - @Override - public void close() throws IOException { - cleanup(); - super.close(); - } - - @Override - public synchronized void mark(int readlimit) { - // Do nothing - } - - @Override - public boolean markSupported() { - return false; - } - - @Override - public int read() throws IOException { - read(mTmpBuffer, 0, 1); - return 0xFF & mTmpBuffer[0]; - } - - @Override - public int read(byte[] buffer) throws IOException { - return read(buffer, 0, buffer.length); - } - - @Override - public int read(byte[] buffer, int offset, int count) throws IOException { - if (offset < 0 || count < 0 || (offset + count) > buffer.length) { - throw new ArrayIndexOutOfBoundsException(String.format( - " buffer length %d, offset %d, length %d", - buffer.length, offset, count)); - } - if (!mValidConfig) { - return 0; - } - applyConfigChange(); - int flag = JpegConfig.J_ERROR_FATAL; - try { - flag = readDecodedBytes(buffer, offset, count); - } finally { - if (flag < 0) { - cleanup(); - } - } - if (flag < 0) { - switch (flag) { - case JpegConfig.J_DONE: - return -1; // Returns -1 after reading EOS. - default: - throw new IOException("Error reading jpeg stream"); - } - } - return flag; - } - - @Override - public synchronized void reset() throws IOException { - throw new IOException("Reset not supported."); - } - - @Override - public long skip(long byteCount) throws IOException { - if (byteCount <= 0) { - return 0; - } - // Shorten skip to a reasonable amount - int flag = skipDecodedBytes((int) (0x7FFFFFFF & byteCount)); - if (flag < 0) { - switch (flag) { - case JpegConfig.J_DONE: - return 0; // Returns 0 after reading EOS. - default: - throw new IOException("Error skipping jpeg stream"); - } - } - return flag; - } - - @Override - protected void finalize() throws Throwable { - try { - cleanup(); - } finally { - super.finalize(); - } - } - - private void applyConfigChange() throws IOException { - if (mConfigChanged) { - cleanup(); - Point dimens = new Point(0, 0); - int flag = setup(dimens, in, mFormat); - switch(flag) { - case JpegConfig.J_SUCCESS: - break; // allow setup to continue - case JpegConfig.J_ERROR_BAD_ARGS: - throw new IllegalArgumentException("Bad arguments to read"); - default: - throw new IOException("Error to reading jpeg headers."); - } - mWidth = dimens.x; - mHeight = dimens.y; - mConfigChanged = false; - } - } - - native private int setup(Point dimens, InputStream in, int format); - - native private void cleanup(); - - native private int readDecodedBytes( byte[] inBuffer, int offset, int inCount); - - native private int skipDecodedBytes(int bytes); - - static { - System.loadLibrary("jni_jpegstream"); - } -} diff --git a/gallerycommon/src/com/android/gallery3d/jpegstream/JPEGOutputStream.java b/gallerycommon/src/com/android/gallery3d/jpegstream/JPEGOutputStream.java deleted file mode 100644 index c49d3759c..000000000 --- a/gallerycommon/src/com/android/gallery3d/jpegstream/JPEGOutputStream.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.jpegstream; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -public class JPEGOutputStream extends FilterOutputStream { - private long JNIPointer = 0; // Used by JNI code. Don't touch. - - private byte[] mTmpBuffer = new byte[1]; - private int mWidth = 0; - private int mHeight = 0; - private int mQuality = 0; - private int mFormat = -1; - private boolean mValidConfig = false; - private boolean mConfigChanged = false; - - public JPEGOutputStream(OutputStream out) { - super(out); - } - - public JPEGOutputStream(OutputStream out, int width, int height, int quality, - int format) { - super(out); - setConfig(width, height, quality, format); - } - - public boolean setConfig(int width, int height, int quality, int format) { - // Clamp quality to range (0, 100] - quality = Math.max(Math.min(quality, 100), 1); - - // Make sure format is valid - switch (format) { - case JpegConfig.FORMAT_GRAYSCALE: - case JpegConfig.FORMAT_RGB: - case JpegConfig.FORMAT_ABGR: - case JpegConfig.FORMAT_RGBA: - break; - default: - return false; - } - - // If valid, set configuration - if (width > 0 && height > 0) { - mWidth = width; - mHeight = height; - mFormat = format; - mQuality = quality; - mValidConfig = true; - mConfigChanged = true; - } else { - return false; - } - - return mValidConfig; - } - - @Override - public void close() throws IOException { - cleanup(); - super.close(); - } - - @Override - public void write(byte[] buffer, int offset, int length) throws IOException { - if (offset < 0 || length < 0 || (offset + length) > buffer.length) { - throw new ArrayIndexOutOfBoundsException(String.format( - " buffer length %d, offset %d, length %d", - buffer.length, offset, length)); - } - if (!mValidConfig) { - return; - } - if (mConfigChanged) { - cleanup(); - int flag = setup(out, mWidth, mHeight, mFormat, mQuality); - switch(flag) { - case JpegConfig.J_SUCCESS: - break; // allow setup to continue - case JpegConfig.J_ERROR_BAD_ARGS: - throw new IllegalArgumentException("Bad arguments to write"); - default: - throw new IOException("Error to writing jpeg headers."); - } - mConfigChanged = false; - } - int returnCode = JpegConfig.J_ERROR_FATAL; - try { - returnCode = writeInputBytes(buffer, offset, length); - } finally { - if (returnCode < 0) { - cleanup(); - } - } - if (returnCode < 0) { - throw new IOException("Error writing jpeg stream"); - } - } - - @Override - public void write(byte[] buffer) throws IOException { - write(buffer, 0, buffer.length); - } - - @Override - public void write(int oneByte) throws IOException { - mTmpBuffer[0] = (byte) oneByte; - write(mTmpBuffer); - } - - @Override - protected void finalize() throws Throwable { - try { - cleanup(); - } finally { - super.finalize(); - } - } - - native private int setup(OutputStream out, int width, int height, int format, int quality); - - native private void cleanup(); - - native private int writeInputBytes(byte[] inBuffer, int offset, int inCount); - - static { - System.loadLibrary("jni_jpegstream"); - } -} diff --git a/gallerycommon/src/com/android/gallery3d/jpegstream/JpegConfig.java b/gallerycommon/src/com/android/gallery3d/jpegstream/JpegConfig.java deleted file mode 100644 index e514e3b8d..000000000 --- a/gallerycommon/src/com/android/gallery3d/jpegstream/JpegConfig.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.jpegstream; - -public interface JpegConfig { - // Pixel formats - public static final int FORMAT_GRAYSCALE = 0x001; // 1 byte/pixel - public static final int FORMAT_RGB = 0x003; // 3 bytes/pixel RGBRGBRGBRGB... - public static final int FORMAT_RGBA = 0x004; // 4 bytes/pixel RGBARGBARGBARGBA... - public static final int FORMAT_ABGR = 0x104; // 4 bytes/pixel ABGRABGRABGR... - - // Jni error codes - static final int J_SUCCESS = 0; - static final int J_ERROR_FATAL = -1; - static final int J_ERROR_BAD_ARGS = -2; - static final int J_EXCEPTION = -3; - static final int J_DONE = -4; -} diff --git a/gallerycommon/src/com/android/gallery3d/jpegstream/StreamUtils.java b/gallerycommon/src/com/android/gallery3d/jpegstream/StreamUtils.java deleted file mode 100644 index abd8f681e..000000000 --- a/gallerycommon/src/com/android/gallery3d/jpegstream/StreamUtils.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.jpegstream; - -import java.nio.ByteOrder; - -public class StreamUtils { - - private StreamUtils() { - } - - /** - * Copies the input byte array into the output int array with the given - * endianness. If input is not a multiple of 4, ignores the last 1-3 bytes - * and returns true. - */ - public static boolean byteToIntArray(int[] output, byte[] input, ByteOrder endianness) { - int length = input.length - (input.length % 4); - if (output.length * 4 < length) { - throw new ArrayIndexOutOfBoundsException("Output array is too short to hold input"); - } - if (endianness == ByteOrder.BIG_ENDIAN) { - for (int i = 0, j = 0; i < output.length; i++, j += 4) { - output[i] = ((input[j] & 0xFF) << 24) | ((input[j + 1] & 0xFF) << 16) - | ((input[j + 2] & 0xFF) << 8) | ((input[j + 3] & 0xFF)); - } - } else { - for (int i = 0, j = 0; i < output.length; i++, j += 4) { - output[i] = ((input[j + 3] & 0xFF) << 24) | ((input[j + 2] & 0xFF) << 16) - | ((input[j + 1] & 0xFF) << 8) | ((input[j] & 0xFF)); - } - } - return input.length % 4 != 0; - } - - public static int[] byteToIntArray(byte[] input, ByteOrder endianness) { - int[] output = new int[input.length / 4]; - byteToIntArray(output, input, endianness); - return output; - } - - /** - * Uses native endianness. - */ - public static int[] byteToIntArray(byte[] input) { - return byteToIntArray(input, ByteOrder.nativeOrder()); - } - - /** - * Returns the number of bytes in a pixel for a given format defined in - * JpegConfig. - */ - public static int pixelSize(int format) { - switch (format) { - case JpegConfig.FORMAT_ABGR: - case JpegConfig.FORMAT_RGBA: - return 4; - case JpegConfig.FORMAT_RGB: - return 3; - case JpegConfig.FORMAT_GRAYSCALE: - return 1; - default: - return -1; - } - } -} diff --git a/gallerycommon/src/com/android/gallery3d/util/Future.java b/gallerycommon/src/com/android/gallery3d/util/Future.java deleted file mode 100644 index 580a2a120..000000000 --- a/gallerycommon/src/com/android/gallery3d/util/Future.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.util; - -// This Future differs from the java.util.concurrent.Future in these aspects: -// -// - Once cancel() is called, isCancelled() always returns true. It is a sticky -// flag used to communicate to the implementation. The implmentation may -// ignore that flag. Regardless whether the Future is cancelled, a return -// value will be provided to get(). The implementation may choose to return -// null if it finds the Future is cancelled. -// -// - get() does not throw exceptions. -// -public interface Future { - public void cancel(); - public boolean isCancelled(); - public boolean isDone(); - public T get(); - public void waitDone(); -} diff --git a/gallerycommon/src/com/android/gallery3d/util/FutureListener.java b/gallerycommon/src/com/android/gallery3d/util/FutureListener.java deleted file mode 100644 index ed1f820c7..000000000 --- a/gallerycommon/src/com/android/gallery3d/util/FutureListener.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.util; - -public interface FutureListener { - public void onFutureDone(Future future); -} diff --git a/gallerycommon/src/com/android/gallery3d/util/PriorityThreadFactory.java b/gallerycommon/src/com/android/gallery3d/util/PriorityThreadFactory.java deleted file mode 100644 index 30d8e4a96..000000000 --- a/gallerycommon/src/com/android/gallery3d/util/PriorityThreadFactory.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.gallery3d.util; - - -import android.os.Process; - -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * A thread factory that creates threads with a given thread priority. - */ -public class PriorityThreadFactory implements ThreadFactory { - - private final int mPriority; - private final AtomicInteger mNumber = new AtomicInteger(); - private final String mName; - - public PriorityThreadFactory(String name, int priority) { - mName = name; - mPriority = priority; - } - - @Override - public Thread newThread(Runnable r) { - return new Thread(r, mName + '-' + mNumber.getAndIncrement()) { - @Override - public void run() { - Process.setThreadPriority(mPriority); - super.run(); - } - }; - } - -} diff --git a/gallerycommon/src/com/android/gallery3d/util/ThreadPool.java b/gallerycommon/src/com/android/gallery3d/util/ThreadPool.java deleted file mode 100644 index 115dc6625..000000000 --- a/gallerycommon/src/com/android/gallery3d/util/ThreadPool.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.util; - -import android.util.Log; - -import java.util.concurrent.Executor; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -public class ThreadPool { - @SuppressWarnings("unused") - private static final String TAG = "ThreadPool"; - private static final int CORE_POOL_SIZE = 4; - private static final int MAX_POOL_SIZE = 8; - private static final int KEEP_ALIVE_TIME = 10; // 10 seconds - - // Resource type - public static final int MODE_NONE = 0; - public static final int MODE_CPU = 1; - public static final int MODE_NETWORK = 2; - - public static final JobContext JOB_CONTEXT_STUB = new JobContextStub(); - - ResourceCounter mCpuCounter = new ResourceCounter(2); - ResourceCounter mNetworkCounter = new ResourceCounter(2); - - // A Job is like a Callable, but it has an addition JobContext parameter. - public interface Job { - public T run(JobContext jc); - } - - public interface JobContext { - boolean isCancelled(); - void setCancelListener(CancelListener listener); - boolean setMode(int mode); - } - - private static class JobContextStub implements JobContext { - @Override - public boolean isCancelled() { - return false; - } - - @Override - public void setCancelListener(CancelListener listener) { - } - - @Override - public boolean setMode(int mode) { - return true; - } - } - - public interface CancelListener { - public void onCancel(); - } - - private static class ResourceCounter { - public int value; - public ResourceCounter(int v) { - value = v; - } - } - - private final Executor mExecutor; - - public ThreadPool() { - this(CORE_POOL_SIZE, MAX_POOL_SIZE); - } - - public ThreadPool(int initPoolSize, int maxPoolSize) { - mExecutor = new ThreadPoolExecutor( - initPoolSize, maxPoolSize, KEEP_ALIVE_TIME, - TimeUnit.SECONDS, new LinkedBlockingQueue(), - new PriorityThreadFactory("thread-pool", - android.os.Process.THREAD_PRIORITY_BACKGROUND)); - } - - // Submit a job to the thread pool. The listener will be called when the - // job is finished (or cancelled). - public Future submit(Job job, FutureListener listener) { - Worker w = new Worker(job, listener); - mExecutor.execute(w); - return w; - } - - public Future submit(Job job) { - return submit(job, null); - } - - private class Worker implements Runnable, Future, JobContext { - @SuppressWarnings("hiding") - private static final String TAG = "Worker"; - private Job mJob; - private FutureListener mListener; - private CancelListener mCancelListener; - private ResourceCounter mWaitOnResource; - private volatile boolean mIsCancelled; - private boolean mIsDone; - private T mResult; - private int mMode; - - public Worker(Job job, FutureListener listener) { - mJob = job; - mListener = listener; - } - - // This is called by a thread in the thread pool. - @Override - public void run() { - T result = null; - - // A job is in CPU mode by default. setMode returns false - // if the job is cancelled. - if (setMode(MODE_CPU)) { - try { - result = mJob.run(this); - } catch (Throwable ex) { - Log.w(TAG, "Exception in running a job", ex); - } - } - - synchronized(this) { - setMode(MODE_NONE); - mResult = result; - mIsDone = true; - notifyAll(); - } - if (mListener != null) mListener.onFutureDone(this); - } - - // Below are the methods for Future. - @Override - public synchronized void cancel() { - if (mIsCancelled) return; - mIsCancelled = true; - if (mWaitOnResource != null) { - synchronized (mWaitOnResource) { - mWaitOnResource.notifyAll(); - } - } - if (mCancelListener != null) { - mCancelListener.onCancel(); - } - } - - @Override - public boolean isCancelled() { - return mIsCancelled; - } - - @Override - public synchronized boolean isDone() { - return mIsDone; - } - - @Override - public synchronized T get() { - while (!mIsDone) { - try { - wait(); - } catch (Exception ex) { - Log.w(TAG, "ingore exception", ex); - // ignore. - } - } - return mResult; - } - - @Override - public void waitDone() { - get(); - } - - // Below are the methods for JobContext (only called from the - // thread running the job) - @Override - public synchronized void setCancelListener(CancelListener listener) { - mCancelListener = listener; - if (mIsCancelled && mCancelListener != null) { - mCancelListener.onCancel(); - } - } - - @Override - public boolean setMode(int mode) { - // Release old resource - ResourceCounter rc = modeToCounter(mMode); - if (rc != null) releaseResource(rc); - mMode = MODE_NONE; - - // Acquire new resource - rc = modeToCounter(mode); - if (rc != null) { - if (!acquireResource(rc)) { - return false; - } - mMode = mode; - } - - return true; - } - - private ResourceCounter modeToCounter(int mode) { - if (mode == MODE_CPU) { - return mCpuCounter; - } else if (mode == MODE_NETWORK) { - return mNetworkCounter; - } else { - return null; - } - } - - private boolean acquireResource(ResourceCounter counter) { - while (true) { - synchronized (this) { - if (mIsCancelled) { - mWaitOnResource = null; - return false; - } - mWaitOnResource = counter; - } - - synchronized (counter) { - if (counter.value > 0) { - counter.value--; - break; - } else { - try { - counter.wait(); - } catch (InterruptedException ex) { - // ignore. - } - } - } - } - - synchronized (this) { - mWaitOnResource = null; - } - - return true; - } - - private void releaseResource(ResourceCounter counter) { - synchronized (counter) { - counter.value++; - counter.notifyAll(); - } - } - } -} -- cgit v1.2.3