diff options
7 files changed, 58 insertions, 438 deletions
diff --git a/gallerycommon/src/com/android/gallery3d/common/LongSparseArray.java b/gallerycommon/src/com/android/gallery3d/common/LongSparseArray.java deleted file mode 100644 index b3298e672..000000000 --- a/gallerycommon/src/com/android/gallery3d/common/LongSparseArray.java +++ /dev/null @@ -1,368 +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; - - -// Copied from android.util.LongSparseArray for unbundling - -/** - * SparseArray mapping longs to Objects. Unlike a normal array of Objects, - * there can be gaps in the indices. It is intended to be more efficient - * than using a HashMap to map Longs to Objects. - */ -public class LongSparseArray<E> implements Cloneable { - private static final Object DELETED = new Object(); - private boolean mGarbage = false; - - private long[] mKeys; - private Object[] mValues; - private int mSize; - - /** - * Creates a new LongSparseArray containing no mappings. - */ - public LongSparseArray() { - this(10); - } - - /** - * Creates a new LongSparseArray containing no mappings that will not - * require any additional memory allocation to store the specified - * number of mappings. - */ - public LongSparseArray(int initialCapacity) { - initialCapacity = idealLongArraySize(initialCapacity); - - mKeys = new long[initialCapacity]; - mValues = new Object[initialCapacity]; - mSize = 0; - } - - @Override - @SuppressWarnings("unchecked") - public LongSparseArray<E> clone() { - LongSparseArray<E> clone = null; - try { - clone = (LongSparseArray<E>) super.clone(); - clone.mKeys = mKeys.clone(); - clone.mValues = mValues.clone(); - } catch (CloneNotSupportedException cnse) { - /* ignore */ - } - return clone; - } - - /** - * Gets the Object mapped from the specified key, or <code>null</code> - * if no such mapping has been made. - */ - public E get(long key) { - return get(key, null); - } - - /** - * Gets the Object mapped from the specified key, or the specified Object - * if no such mapping has been made. - */ - @SuppressWarnings("unchecked") - public E get(long key, E valueIfKeyNotFound) { - int i = binarySearch(mKeys, 0, mSize, key); - - if (i < 0 || mValues[i] == DELETED) { - return valueIfKeyNotFound; - } else { - return (E) mValues[i]; - } - } - - /** - * Removes the mapping from the specified key, if there was any. - */ - public void delete(long key) { - int i = binarySearch(mKeys, 0, mSize, key); - - if (i >= 0) { - if (mValues[i] != DELETED) { - mValues[i] = DELETED; - mGarbage = true; - } - } - } - - /** - * Alias for {@link #delete(long)}. - */ - public void remove(long key) { - delete(key); - } - - /** - * Removes the mapping at the specified index. - */ - public void removeAt(int index) { - if (mValues[index] != DELETED) { - mValues[index] = DELETED; - mGarbage = true; - } - } - - private void gc() { - // Log.e("SparseArray", "gc start with " + mSize); - - int n = mSize; - int o = 0; - long[] keys = mKeys; - Object[] values = mValues; - - for (int i = 0; i < n; i++) { - Object val = values[i]; - - if (val != DELETED) { - if (i != o) { - keys[o] = keys[i]; - values[o] = val; - values[i] = null; - } - - o++; - } - } - - mGarbage = false; - mSize = o; - - // Log.e("SparseArray", "gc end with " + mSize); - } - - /** - * Adds a mapping from the specified key to the specified value, - * replacing the previous mapping from the specified key if there - * was one. - */ - public void put(long key, E value) { - int i = binarySearch(mKeys, 0, mSize, key); - - if (i >= 0) { - mValues[i] = value; - } else { - i = ~i; - - if (i < mSize && mValues[i] == DELETED) { - mKeys[i] = key; - mValues[i] = value; - return; - } - - if (mGarbage && mSize >= mKeys.length) { - gc(); - - // Search again because indices may have changed. - i = ~binarySearch(mKeys, 0, mSize, key); - } - - if (mSize >= mKeys.length) { - int n = idealLongArraySize(mSize + 1); - - long[] nkeys = new long[n]; - Object[] nvalues = new Object[n]; - - // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); - System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); - System.arraycopy(mValues, 0, nvalues, 0, mValues.length); - - mKeys = nkeys; - mValues = nvalues; - } - - if (mSize - i != 0) { - // Log.e("SparseArray", "move " + (mSize - i)); - System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i); - System.arraycopy(mValues, i, mValues, i + 1, mSize - i); - } - - mKeys[i] = key; - mValues[i] = value; - mSize++; - } - } - - /** - * Returns the number of key-value mappings that this LongSparseArray - * currently stores. - */ - public int size() { - if (mGarbage) { - gc(); - } - - return mSize; - } - - /** - * Given an index in the range <code>0...size()-1</code>, returns - * the key from the <code>index</code>th key-value mapping that this - * LongSparseArray stores. - */ - public long keyAt(int index) { - if (mGarbage) { - gc(); - } - - return mKeys[index]; - } - - /** - * Given an index in the range <code>0...size()-1</code>, returns - * the value from the <code>index</code>th key-value mapping that this - * LongSparseArray stores. - */ - @SuppressWarnings("unchecked") - public E valueAt(int index) { - if (mGarbage) { - gc(); - } - - return (E) mValues[index]; - } - - /** - * Given an index in the range <code>0...size()-1</code>, sets a new - * value for the <code>index</code>th key-value mapping that this - * LongSparseArray stores. - */ - public void setValueAt(int index, E value) { - if (mGarbage) { - gc(); - } - - mValues[index] = value; - } - - /** - * Returns the index for which {@link #keyAt} would return the - * specified key, or a negative number if the specified - * key is not mapped. - */ - public int indexOfKey(long key) { - if (mGarbage) { - gc(); - } - - return binarySearch(mKeys, 0, mSize, key); - } - - /** - * Returns an index for which {@link #valueAt} would return the - * specified key, or a negative number if no keys map to the - * specified value. - * Beware that this is a linear search, unlike lookups by key, - * and that multiple keys can map to the same value and this will - * find only one of them. - */ - public int indexOfValue(E value) { - if (mGarbage) { - gc(); - } - - for (int i = 0; i < mSize; i++) - if (mValues[i] == value) - return i; - - return -1; - } - - /** - * Removes all key-value mappings from this LongSparseArray. - */ - public void clear() { - int n = mSize; - Object[] values = mValues; - - for (int i = 0; i < n; i++) { - values[i] = null; - } - - mSize = 0; - mGarbage = false; - } - - /** - * Puts a key/value pair into the array, optimizing for the case where - * the key is greater than all existing keys in the array. - */ - public void append(long key, E value) { - if (mSize != 0 && key <= mKeys[mSize - 1]) { - put(key, value); - return; - } - - if (mGarbage && mSize >= mKeys.length) { - gc(); - } - - int pos = mSize; - if (pos >= mKeys.length) { - int n = idealLongArraySize(pos + 1); - - long[] nkeys = new long[n]; - Object[] nvalues = new Object[n]; - - // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); - System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); - System.arraycopy(mValues, 0, nvalues, 0, mValues.length); - - mKeys = nkeys; - mValues = nvalues; - } - - mKeys[pos] = key; - mValues[pos] = value; - mSize = pos + 1; - } - - private static int binarySearch(long[] a, int start, int len, long key) { - int high = start + len, low = start - 1, guess; - - while (high - low > 1) { - guess = (high + low) / 2; - - if (a[guess] < key) - low = guess; - else - high = guess; - } - - if (high == start + len) - return ~(start + len); - else if (a[high] == key) - return high; - else - return ~high; - } - - private static int idealByteArraySize(int need) { - for (int i = 4; i < 32; i++) - if (need <= (1 << i) - 12) - return (1 << i) - 12; - - return need; - } - - public static int idealLongArraySize(int need) { - return idealByteArraySize(need * 8) / 8; - } -} diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java index 8485b25eb..31dd79c8e 100644 --- a/src/com/android/gallery3d/app/PhotoDataAdapter.java +++ b/src/com/android/gallery3d/app/PhotoDataAdapter.java @@ -550,9 +550,8 @@ public class PhotoDataAdapter implements PhotoPage.Model { } @Override - public Bitmap getTile(int level, int x, int y, int tileSize, - int borderSize, BitmapPool pool) { - return mTileProvider.getTile(level, x, y, tileSize, borderSize, pool); + public Bitmap getTile(int level, int x, int y, int tileSize, BitmapPool pool) { + return mTileProvider.getTile(level, x, y, tileSize, pool); } @Override diff --git a/src/com/android/gallery3d/ui/BitmapTileProvider.java b/src/com/android/gallery3d/ui/BitmapTileProvider.java index d4c9b1d30..c3466e7fe 100644 --- a/src/com/android/gallery3d/ui/BitmapTileProvider.java +++ b/src/com/android/gallery3d/ui/BitmapTileProvider.java @@ -25,7 +25,7 @@ import com.android.gallery3d.data.BitmapPool; import java.util.ArrayList; -public class BitmapTileProvider implements TileImageView.Model { +public class BitmapTileProvider implements TileImageView.TileSource { private final ScreenNail mScreenNail; private final Bitmap[] mMipmaps; private final Config mConfig; @@ -72,22 +72,21 @@ public class BitmapTileProvider implements TileImageView.Model { @Override public Bitmap getTile(int level, int x, int y, int tileSize, - int borderSize, BitmapPool pool) { + BitmapPool pool) { x >>= level; y >>= level; - int size = tileSize + 2 * borderSize; Bitmap result = pool == null ? null : pool.getBitmap(); if (result == null) { - result = Bitmap.createBitmap(size, size, mConfig); + result = Bitmap.createBitmap(tileSize, tileSize, mConfig); } else { result.eraseColor(0); } Bitmap mipmap = mMipmaps[level]; Canvas canvas = new Canvas(result); - int offsetX = -x + borderSize; - int offsetY = -y + borderSize; + int offsetX = -x; + int offsetY = -y; canvas.drawBitmap(mipmap, offsetX, offsetY, null); return result; } diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java index 58389e4ae..5272ffcf0 100644 --- a/src/com/android/gallery3d/ui/PhotoView.java +++ b/src/com/android/gallery3d/ui/PhotoView.java @@ -52,7 +52,7 @@ public class PhotoView extends GLView { public int height; } - public interface Model extends TileImageView.Model { + public interface Model extends TileImageView.TileSource { public int getCurrentIndex(); public void moveTo(int index); diff --git a/src/com/android/gallery3d/ui/TileImageView.java b/src/com/android/gallery3d/ui/TileImageView.java index 8f26981fe..e71acf19f 100644 --- a/src/com/android/gallery3d/ui/TileImageView.java +++ b/src/com/android/gallery3d/ui/TileImageView.java @@ -16,20 +16,22 @@ package com.android.gallery3d.ui; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; +import android.support.v4.util.LongSparseArray; +import android.util.DisplayMetrics; import android.util.FloatMath; +import android.view.WindowManager; import com.android.gallery3d.app.GalleryContext; import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.common.LongSparseArray; import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.BitmapPool; import com.android.gallery3d.data.DecodeUtils; import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.GalleryUtils; import com.android.gallery3d.util.ThreadPool; import com.android.gallery3d.util.ThreadPool.CancelListener; import com.android.gallery3d.util.ThreadPool.JobContext; @@ -41,14 +43,11 @@ public class TileImageView extends GLView { @SuppressWarnings("unused") private static final String TAG = "TileImageView"; - - // TILE_SIZE must be 2^N - 2. We put one pixel border in each side of the - // texture to avoid seams between tiles. - private static int TILE_SIZE; - private static final int TILE_BORDER = 1; - private static int BITMAP_SIZE; private static final int UPLOAD_LIMIT = 1; + // TILE_SIZE must be 2^N + private static int sTileSize; + private static BitmapPool sTilePool; /* @@ -76,7 +75,7 @@ public class TileImageView extends GLView { private static final int STATE_RECYCLING = 0x20; private static final int STATE_RECYCLED = 0x40; - private Model mModel; + private TileSource mModel; private ScreenNail mScreenNail; protected int mLevelCount; // cache the value of mScaledBitmaps.length @@ -125,7 +124,7 @@ public class TileImageView extends GLView { private final ThreadPool mThreadPool; private boolean mBackgroundTileUploaded; - public static interface Model { + public static interface TileSource { public int getLevelCount(); public ScreenNail getScreenNail(); public int getImageWidth(); @@ -133,8 +132,7 @@ public class TileImageView extends GLView { // The tile returned by this method can be specified this way: Assuming // the image size is (width, height), first take the intersection of (0, - // 0) - (width, height) and (x, y) - (x + tileSize, y + tileSize). Then - // extend this intersection region by borderSize pixels on each side. If + // 0) - (width, height) and (x, y) - (x + tileSize, y + tileSize). If // in extending the region, we found some part of the region are outside // the image, those pixels are filled with black. // @@ -144,27 +142,34 @@ public class TileImageView extends GLView { // // The method would be called in another thread. public Bitmap getTile(int level, int x, int y, int tileSize, - int borderSize, BitmapPool pool); + BitmapPool pool); + } + + public static boolean isHighResolution(Context context) { + DisplayMetrics metrics = new DisplayMetrics(); + WindowManager wm = (WindowManager) + context.getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getMetrics(metrics); + return metrics.heightPixels > 2048 || metrics.widthPixels > 2048; } public TileImageView(GalleryContext context) { mThreadPool = context.getThreadPool(); mTileDecoder = mThreadPool.submit(new TileDecoder()); - if (TILE_SIZE == 0) { - if (GalleryUtils.isHighResolution(context.getAndroidContext())) { - TILE_SIZE = 510 ; + if (sTileSize == 0) { + if (isHighResolution(context.getAndroidContext())) { + sTileSize = 512 ; } else { - TILE_SIZE = 254; + sTileSize = 256; } - BITMAP_SIZE = TILE_SIZE + TILE_BORDER * 2; sTilePool = ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER - ? new BitmapPool(BITMAP_SIZE, BITMAP_SIZE, 128) + ? new BitmapPool(sTileSize, sTileSize, 128) : null; } } - public void setModel(Model model) { + public void setModel(TileSource model) { mModel = model; if (model != null) notifyModelInvalidated(); } @@ -266,7 +271,7 @@ public class TileImageView extends GLView { } for (int i = fromLevel; i < endLevel; ++i) { - int size = TILE_SIZE << i; + int size = sTileSize << i; Rect r = range[i - fromLevel]; for (int y = r.top, bottom = r.bottom; y < bottom; y += size) { for (int x = r.left, right = r.right; x < right; x += size) { @@ -320,7 +325,7 @@ public class TileImageView extends GLView { int bottom = (int) FloatMath.ceil(top + height / scale); // align the rectangle to tile boundary - int size = TILE_SIZE << level; + int size = sTileSize << level; left = Math.max(0, size * (left / size)); top = Math.max(0, size * (top / size)); right = Math.min(mImageWidth, right); @@ -431,7 +436,7 @@ public class TileImageView extends GLView { mScreenNail.noDraw(); } - int size = (TILE_SIZE << level); + int size = (sTileSize << level); float length = size * mScale; Rect r = mTileRange; @@ -594,7 +599,7 @@ public class TileImageView extends GLView { RectF source = mSourceRect; RectF target = mTargetRect; target.set(x, y, x + length, y + length); - source.set(0, 0, TILE_SIZE, TILE_SIZE); + source.set(0, 0, sTileSize, sTileSize); Tile tile = getTile(tx, ty, level); if (tile != null) { @@ -614,7 +619,7 @@ public class TileImageView extends GLView { if (drawTile(tile, canvas, source, target)) return; } if (mScreenNail != null) { - int size = TILE_SIZE << level; + int size = sTileSize << level; float scaleX = (float) mScreenNail.getWidth() / mImageWidth; float scaleY = (float) mScreenNail.getHeight() / mImageHeight; source.set(tx * scaleX, ty * scaleY, (tx + size) * scaleX, @@ -627,8 +632,6 @@ public class TileImageView extends GLView { Tile tile, GLCanvas canvas, RectF source, RectF target) { while (true) { if (tile.isContentValid()) { - // offset source rectangle for the texture border. - source.offset(TILE_BORDER, TILE_BORDER); canvas.drawTexture(tile, source, target); return true; } @@ -640,15 +643,15 @@ public class TileImageView extends GLView { source.left /= 2f; source.right /= 2f; } else { - source.left = (TILE_SIZE + source.left) / 2f; - source.right = (TILE_SIZE + source.right) / 2f; + source.left = (sTileSize + source.left) / 2f; + source.right = (sTileSize + source.right) / 2f; } if (tile.mY == parent.mY) { source.top /= 2f; source.bottom /= 2f; } else { - source.top = (TILE_SIZE + source.top) / 2f; - source.bottom = (TILE_SIZE + source.bottom) / 2f; + source.top = (sTileSize + source.top) / 2f; + source.bottom = (sTileSize + source.bottom) / 2f; } tile = parent; } @@ -678,7 +681,7 @@ public class TileImageView extends GLView { // by (1 << mTilelevel) from a region in the original image. try { mDecodedTile = DecodeUtils.ensureGLCompatibleBitmap(mModel.getTile( - mTileLevel, mX, mY, TILE_SIZE, TILE_BORDER, sTilePool)); + mTileLevel, mX, mY, sTileSize, sTilePool)); } catch (Throwable t) { Log.w(TAG, "fail to decode tile", t); } @@ -691,9 +694,9 @@ public class TileImageView extends GLView { // We need to override the width and height, so that we won't // draw beyond the boundaries. - int rightEdge = ((mImageWidth - mX) >> mTileLevel) + TILE_BORDER; - int bottomEdge = ((mImageHeight - mY) >> mTileLevel) + TILE_BORDER; - setSize(Math.min(BITMAP_SIZE, rightEdge), Math.min(BITMAP_SIZE, bottomEdge)); + int rightEdge = ((mImageWidth - mX) >> mTileLevel); + int bottomEdge = ((mImageHeight - mY) >> mTileLevel); + setSize(Math.min(sTileSize, rightEdge), Math.min(sTileSize, bottomEdge)); Bitmap bitmap = mDecodedTile; mDecodedTile = null; @@ -707,12 +710,12 @@ public class TileImageView extends GLView { // boundary). @Override public int getTextureWidth() { - return TILE_SIZE + TILE_BORDER * 2; + return sTileSize; } @Override public int getTextureHeight() { - return TILE_SIZE + TILE_BORDER * 2; + return sTileSize; } public void update(int x, int y, int level) { @@ -724,7 +727,7 @@ public class TileImageView extends GLView { public Tile getParentTile() { if (mTileLevel + 1 == mLevelCount) return null; - int size = TILE_SIZE << (mTileLevel + 1); + int size = sTileSize << (mTileLevel + 1); int x = size * (mX / size); int y = size * (mY / size); return getTile(x, y, mTileLevel + 1); @@ -733,7 +736,7 @@ public class TileImageView extends GLView { @Override public String toString() { return String.format("tile(%s, %s, %s / %s)", - mX / TILE_SIZE, mY / TILE_SIZE, mLevel, mLevelCount); + mX / sTileSize, mY / sTileSize, mLevel, mLevelCount); } } diff --git a/src/com/android/gallery3d/ui/TileImageViewAdapter.java b/src/com/android/gallery3d/ui/TileImageViewAdapter.java index 45e2ce218..0d20b0757 100644 --- a/src/com/android/gallery3d/ui/TileImageViewAdapter.java +++ b/src/com/android/gallery3d/ui/TileImageViewAdapter.java @@ -28,7 +28,7 @@ import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.BitmapPool; -public class TileImageViewAdapter implements TileImageView.Model { +public class TileImageViewAdapter implements TileImageView.TileSource { private static final String TAG = "TileImageViewAdapter"; protected ScreenNail mScreenNail; protected boolean mOwnScreenNail; @@ -84,16 +84,14 @@ public class TileImageViewAdapter implements TileImageView.Model { // (44, 44, 256, 256) from the original photo and down sample it to 106. @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) @Override - public Bitmap getTile(int level, int x, int y, int tileSize, - int borderSize, BitmapPool pool) { + public Bitmap getTile(int level, int x, int y, int tileSize, BitmapPool pool) { if (!ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER) { - return getTileWithoutReusingBitmap(level, x, y, tileSize, borderSize); + return getTileWithoutReusingBitmap(level, x, y, tileSize); } - int b = borderSize << level; int t = tileSize << level; - Rect wantRegion = new Rect(x - b, y - b, x + t + b, y + t + b); + Rect wantRegion = new Rect(x, y, x + t, y + t); boolean needClear; BitmapRegionDecoder regionDecoder = null; @@ -112,8 +110,7 @@ public class TileImageViewAdapter implements TileImageView.Model { if (bitmap != null) { if (needClear) bitmap.eraseColor(0); } else { - int s = tileSize + 2 * borderSize; - bitmap = Bitmap.createBitmap(s, s, Config.ARGB_8888); + bitmap = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888); } BitmapFactory.Options options = new BitmapFactory.Options(); @@ -141,10 +138,9 @@ public class TileImageViewAdapter implements TileImageView.Model { } private Bitmap getTileWithoutReusingBitmap( - int level, int x, int y, int tileSize, int borderSize) { - int b = borderSize << level; + int level, int x, int y, int tileSize) { int t = tileSize << level; - Rect wantRegion = new Rect(x - b, y - b, x + t + b, y + t + b); + Rect wantRegion = new Rect(x, y, x + t, y + t); BitmapRegionDecoder regionDecoder; Rect overlapRegion; @@ -173,8 +169,7 @@ public class TileImageViewAdapter implements TileImageView.Model { if (wantRegion.equals(overlapRegion)) return bitmap; - int s = tileSize + 2 * borderSize; - Bitmap result = Bitmap.createBitmap(s, s, Config.ARGB_8888); + Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888); Canvas canvas = new Canvas(result); canvas.drawBitmap(bitmap, (overlapRegion.left - wantRegion.left) >> level, diff --git a/src/com/android/gallery3d/util/GalleryUtils.java b/src/com/android/gallery3d/util/GalleryUtils.java index 547e2dda0..a4b6bfdc7 100644 --- a/src/com/android/gallery3d/util/GalleryUtils.java +++ b/src/com/android/gallery3d/util/GalleryUtils.java @@ -94,14 +94,6 @@ public class GalleryUtils { TiledScreenNail.setMaxSide(maxPixels / 2); } - public static boolean isHighResolution(Context context) { - DisplayMetrics metrics = new DisplayMetrics(); - WindowManager wm = (WindowManager) - context.getSystemService(Context.WINDOW_SERVICE); - wm.getDefaultDisplay().getMetrics(metrics); - return metrics.heightPixels > 2048 || metrics.widthPixels > 2048; - } - public static float[] intColorToFloatARGBArray(int from) { return new float[] { Color.alpha(from) / 255f, |