OSDN Git Service

Fixes bugs in TiledTexture.
authorOwen Lin <owenlin@google.com>
Thu, 11 Oct 2012 07:50:38 +0000 (15:50 +0800)
committerOwen Lin <owenlin@google.com>
Tue, 16 Oct 2012 02:29:28 +0000 (10:29 +0800)
1. Upload tiles in SinglePhotoDataAdapter
2. Rebuild the upload queue after the screen nails being recycled

bug: 6399444

Change-Id: I57e756f8d1d84742bf82dd34c83baf8df89ae4cc

src/com/android/gallery3d/app/CropImage.java
src/com/android/gallery3d/app/PhotoDataAdapter.java
src/com/android/gallery3d/app/PhotoPage.java
src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
src/com/android/gallery3d/ui/BitmapScreenNail.java
src/com/android/gallery3d/ui/PhotoView.java
src/com/android/gallery3d/ui/TileImageView.java
src/com/android/gallery3d/ui/TileImageViewAdapter.java
src/com/android/gallery3d/ui/TiledScreenNail.java [new file with mode: 0644]
src/com/android/gallery3d/util/GalleryUtils.java

index 2b74504..89ca63d 100644 (file)
@@ -61,6 +61,7 @@ import com.android.gallery3d.exif.ExifOutputStream;
 import com.android.gallery3d.exif.ExifReader;
 import com.android.gallery3d.exif.ExifTag;
 import com.android.gallery3d.picasasource.PicasaSource;
+import com.android.gallery3d.ui.BitmapScreenNail;
 import com.android.gallery3d.ui.BitmapTileProvider;
 import com.android.gallery3d.ui.CropView;
 import com.android.gallery3d.ui.GLRoot;
@@ -151,6 +152,7 @@ public class CropImage extends AbstractGalleryActivity {
     private BitmapRegionDecoder mRegionDecoder;
     private Bitmap mBitmapInIntent;
     private boolean mUseRegionDecoder = false;
+    private BitmapScreenNail mBitmapScreenNail;
 
     private ProgressDialog mProgressDialog;
     private Future<BitmapRegionDecoder> mLoadTask;
@@ -813,8 +815,14 @@ public class CropImage extends AbstractGalleryActivity {
                 BitmapUtils.UNCONSTRAINED, BACKUP_PIXEL_COUNT);
         mBitmap = regionDecoder.decodeRegion(
                 new Rect(0, 0, width, height), options);
-        mCropView.setDataModel(new TileImageViewAdapter(
-                mBitmap, regionDecoder), mMediaItem.getFullImageRotation());
+
+        mBitmapScreenNail = new BitmapScreenNail(mBitmap);
+
+        TileImageViewAdapter adapter = new TileImageViewAdapter();
+        adapter.setScreenNail(mBitmapScreenNail, width, height);
+        adapter.setRegionDecoder(regionDecoder);
+
+        mCropView.setDataModel(adapter, mMediaItem.getFullImageRotation());
         if (mDoFaceDetection) {
             mCropView.detectFaces(mBitmap);
         } else {
@@ -976,6 +984,15 @@ public class CropImage extends AbstractGalleryActivity {
         }
     }
 
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (mBitmapScreenNail != null) {
+            mBitmapScreenNail.recycle();
+            mBitmapScreenNail = null;
+        }
+    }
+
     private void dismissProgressDialogIfShown() {
         if (mProgressDialog != null) {
             mProgressDialog.dismiss();
index 5ab022a..20f15be 100644 (file)
@@ -30,11 +30,11 @@ import com.android.gallery3d.data.MediaItem;
 import com.android.gallery3d.data.MediaObject;
 import com.android.gallery3d.data.MediaSet;
 import com.android.gallery3d.data.Path;
-import com.android.gallery3d.ui.BitmapScreenNail;
 import com.android.gallery3d.ui.PhotoView;
 import com.android.gallery3d.ui.ScreenNail;
 import com.android.gallery3d.ui.SynchronizedHandler;
 import com.android.gallery3d.ui.TileImageViewAdapter;
+import com.android.gallery3d.ui.TiledScreenNail;
 import com.android.gallery3d.ui.TiledTexture;
 import com.android.gallery3d.util.Future;
 import com.android.gallery3d.util.FutureListener;
@@ -305,8 +305,8 @@ public class PhotoDataAdapter implements PhotoPage.Model {
         entry.screenNailTask = null;
 
         // Combine the ScreenNails if we already have a BitmapScreenNail
-        if (entry.screenNail instanceof BitmapScreenNail) {
-            BitmapScreenNail original = (BitmapScreenNail) entry.screenNail;
+        if (entry.screenNail instanceof TiledScreenNail) {
+            TiledScreenNail original = (TiledScreenNail) entry.screenNail;
             screenNail = original.combine(screenNail);
         }
 
@@ -404,7 +404,6 @@ public class PhotoDataAdapter implements PhotoPage.Model {
         updateImageCache();
         updateImageRequests();
         updateTileProvider();
-        updateScreenNailUploadQueue();
 
         if (mDataListener != null) {
             mDataListener.onPhotoChanged(index, mItemPath);
@@ -424,8 +423,8 @@ public class PhotoDataAdapter implements PhotoPage.Model {
         if (e == null) return;
 
         ScreenNail s = e.screenNail;
-        if (s instanceof BitmapScreenNail) {
-            TiledTexture t = ((BitmapScreenNail) s).getTexture();
+        if (s instanceof TiledScreenNail) {
+            TiledTexture t = ((TiledScreenNail) s).getTexture();
             if (t != null && !t.isReady()) mUploader.addTexture(t);
         }
     }
@@ -717,7 +716,7 @@ public class PhotoDataAdapter implements PhotoPage.Model {
                 bitmap = BitmapUtils.rotateBitmap(bitmap,
                     mItem.getRotation() - mItem.getFullImageRotation(), true);
             }
-            return bitmap == null ? null : new BitmapScreenNail(bitmap);
+            return bitmap == null ? null : new TiledScreenNail(bitmap);
         }
     }
 
@@ -766,7 +765,7 @@ public class PhotoDataAdapter implements PhotoPage.Model {
     private ScreenNail newPlaceholderScreenNail(MediaItem item) {
         int width = item.getWidth();
         int height = item.getHeight();
-        return new BitmapScreenNail(width, height);
+        return new TiledScreenNail(width, height);
     }
 
     // Returns the task if we started the task or the task is already started.
@@ -828,8 +827,8 @@ public class PhotoDataAdapter implements PhotoPage.Model {
                 if (entry.requestedScreenNail != item.getDataVersion()) {
                     // This ScreenNail is outdated, we want to update it if it's
                     // still a placeholder.
-                    if (entry.screenNail instanceof BitmapScreenNail) {
-                        BitmapScreenNail s = (BitmapScreenNail) entry.screenNail;
+                    if (entry.screenNail instanceof TiledScreenNail) {
+                        TiledScreenNail s = (TiledScreenNail) entry.screenNail;
                         s.updatePlaceholderSize(
                                 item.getWidth(), item.getHeight());
                     }
@@ -847,6 +846,8 @@ public class PhotoDataAdapter implements PhotoPage.Model {
             if (entry.screenNailTask != null) entry.screenNailTask.cancel();
             if (entry.screenNail != null) entry.screenNail.recycle();
         }
+
+        updateScreenNailUploadQueue();
     }
 
     private class FullImageListener
index b11229f..8d6bc60 100644 (file)
@@ -61,7 +61,7 @@ import com.android.gallery3d.data.SnailItem;
 import com.android.gallery3d.data.SnailSource;
 import com.android.gallery3d.picasasource.PicasaSource;
 import com.android.gallery3d.ui.AnimationTime;
-import com.android.gallery3d.ui.BitmapScreenNail;
+import com.android.gallery3d.ui.TiledScreenNail;
 import com.android.gallery3d.ui.DetailsHelper;
 import com.android.gallery3d.ui.DetailsHelper.CloseListener;
 import com.android.gallery3d.ui.DetailsHelper.DetailsSource;
@@ -269,7 +269,7 @@ public class PhotoPage extends ActivityState implements
                 if (!mBackgroundFade.isActive()) {
                     mFadeOutTexture = null;
                     mOpenAnimationRect = null;
-                    BitmapScreenNail.enableDrawPlaceholder();
+                    TiledScreenNail.enableDrawPlaceholder();
                 } else {
                     float fadeAlpha = mBackgroundFade.get();
                     if (fadeAlpha < 1f) {
@@ -1372,7 +1372,7 @@ public class PhotoPage extends ActivityState implements
         mFadeOutTexture = transitions.get(PreparePageFadeoutTexture.KEY_FADE_TEXTURE);
         if (mFadeOutTexture != null) {
             mBackgroundFade.start();
-            BitmapScreenNail.disableDrawPlaceholder();
+            TiledScreenNail.disableDrawPlaceholder();
             mOpenAnimationRect =
                     albumPageTransition == MSG_ALBUMPAGE_NONE ?
                     (Rect) mData.getParcelable(KEY_OPEN_ANIMATION_RECT) :
index 2f6f16f..00f2fe7 100644 (file)
@@ -27,6 +27,7 @@ import com.android.gallery3d.common.BitmapUtils;
 import com.android.gallery3d.common.Utils;
 import com.android.gallery3d.data.MediaItem;
 import com.android.gallery3d.data.Path;
+import com.android.gallery3d.ui.BitmapScreenNail;
 import com.android.gallery3d.ui.PhotoView;
 import com.android.gallery3d.ui.ScreenNail;
 import com.android.gallery3d.ui.SynchronizedHandler;
@@ -50,6 +51,7 @@ public class SinglePhotoDataAdapter extends TileImageViewAdapter
     private PhotoView mPhotoView;
     private ThreadPool mThreadPool;
     private int mLoadingState = LOADING_INIT;
+    private BitmapScreenNail mBitmapScreenNail;
 
     public SinglePhotoDataAdapter(
             AbstractGalleryActivity activity, PhotoView view, MediaItem item) {
@@ -113,6 +115,11 @@ public class SinglePhotoDataAdapter extends TileImageViewAdapter
         return false;
     }
 
+    private void setScreenNail(Bitmap bitmap, int width, int height) {
+        mBitmapScreenNail = new BitmapScreenNail(bitmap);
+        setScreenNail(mBitmapScreenNail, width, height);
+    }
+
     private void onDecodeLargeComplete(ImageBundle bundle) {
         try {
             setScreenNail(bundle.backupImage,
@@ -162,6 +169,10 @@ public class SinglePhotoDataAdapter extends TileImageViewAdapter
         if (task.get() == null) {
             mTask = null;
         }
+        if (mBitmapScreenNail != null) {
+            mBitmapScreenNail.recycle();
+            mBitmapScreenNail = null;
+        }
     }
 
     @Override
index 9b62916..741eefb 100644 (file)
@@ -19,198 +19,40 @@ package com.android.gallery3d.ui;
 import android.graphics.Bitmap;
 import android.graphics.RectF;
 
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.BitmapPool;
-import com.android.gallery3d.data.MediaItem;
-
-// This is a ScreenNail wraps a Bitmap. There are some extra functions:
-//
-// - If we need to draw before the bitmap is available, we draw a rectange of
-// placeholder color (gray).
-//
-// - When the the bitmap is available, and we have drawn the placeholder color
-// before, we will do a fade-in animation.
 public class BitmapScreenNail implements ScreenNail {
-    @SuppressWarnings("unused")
-    private static final String TAG = "BitmapScreenNail";
-
-    // The duration of the fading animation in milliseconds
-    private static final int DURATION = 180;
-
-    private static int sMaxSide = 640;
-
-    // These are special values for mAnimationStartTime
-    private static final long ANIMATION_NOT_NEEDED = -1;
-    private static final long ANIMATION_NEEDED = -2;
-    private static final long ANIMATION_DONE = -3;
-
-    private int mWidth;
-    private int mHeight;
-    private long mAnimationStartTime = ANIMATION_NOT_NEEDED;
-
-    private Bitmap mBitmap;
-    private TiledTexture mTexture;
+    private final BitmapTexture mBitmapTexture;
 
     public BitmapScreenNail(Bitmap bitmap) {
-        mWidth = bitmap.getWidth();
-        mHeight = bitmap.getHeight();
-        mBitmap = bitmap;
-        mTexture = new TiledTexture(bitmap);
-    }
-
-    public BitmapScreenNail(int width, int height) {
-        setSize(width, height);
-    }
-
-    // This gets overridden by bitmap_screennail_placeholder
-    // in GalleryUtils.initialize
-    private static int mPlaceholderColor = 0xFF222222;
-    private static boolean mDrawPlaceholder = true;
-
-    public static void setPlaceholderColor(int color) {
-        mPlaceholderColor = color;
-    }
-
-    private void setSize(int width, int height) {
-        if (width == 0 || height == 0) {
-            width = sMaxSide;
-            height = sMaxSide * 3 / 4;
-        }
-        float scale = Math.min(1, (float) sMaxSide / Math.max(width, height));
-        mWidth = Math.round(scale * width);
-        mHeight = Math.round(scale * height);
-    }
-
-    private static void recycleBitmap(BitmapPool pool, Bitmap bitmap) {
-        if (pool == null || bitmap == null) return;
-        pool.recycle(bitmap);
-    }
-
-    // Combines the two ScreenNails.
-    // Returns the used one and recycle the unused one.
-    public ScreenNail combine(ScreenNail other) {
-        if (other == null) {
-            return this;
-        }
-
-        if (!(other instanceof BitmapScreenNail)) {
-            recycle();
-            return other;
-        }
-
-        // Now both are BitmapScreenNail. Move over the information about width,
-        // height, and Bitmap, then recycle the other.
-        BitmapScreenNail newer = (BitmapScreenNail) other;
-        mWidth = newer.mWidth;
-        mHeight = newer.mHeight;
-        if (newer.mTexture != null) {
-            recycleBitmap(MediaItem.getThumbPool(), mBitmap);
-            if (mTexture != null) mTexture.recycle();
-            mBitmap = newer.mBitmap;
-            mTexture = newer.mTexture;
-            newer.mBitmap = null;
-            newer.mTexture = null;
-        }
-        newer.recycle();
-        return this;
-    }
-
-    public void updatePlaceholderSize(int width, int height) {
-        if (mBitmap != null) return;
-        if (width == 0 || height == 0) return;
-        setSize(width, height);
+        mBitmapTexture = new BitmapTexture(bitmap);
     }
 
     @Override
     public int getWidth() {
-        return mWidth;
+        return mBitmapTexture.getWidth();
     }
 
     @Override
     public int getHeight() {
-        return mHeight;
+        return mBitmapTexture.getHeight();
     }
 
     @Override
-    public void noDraw() {
+    public void draw(GLCanvas canvas, int x, int y, int width, int height) {
+        mBitmapTexture.draw(canvas, x, y, width, height);
     }
 
     @Override
-    public void recycle() {
-        if (mTexture != null) {
-            mTexture.recycle();
-            mTexture = null;
-        }
-        recycleBitmap(MediaItem.getThumbPool(), mBitmap);
-        mBitmap = null;
-    }
-
-    public static void disableDrawPlaceholder() {
-        mDrawPlaceholder = false;
-    }
-
-    public static void enableDrawPlaceholder() {
-        mDrawPlaceholder = true;
+    public void noDraw() {
+        // do nothing
     }
 
     @Override
-    public void draw(GLCanvas canvas, int x, int y, int width, int height) {
-        if (mTexture == null || !mTexture.isReady()) {
-            if (mAnimationStartTime == ANIMATION_NOT_NEEDED) {
-                mAnimationStartTime = ANIMATION_NEEDED;
-            }
-            if(mDrawPlaceholder) {
-                canvas.fillRect(x, y, width, height, mPlaceholderColor);
-            }
-            return;
-        }
-
-        if (mAnimationStartTime == ANIMATION_NEEDED) {
-            mAnimationStartTime = AnimationTime.get();
-        }
-
-        if (isAnimating()) {
-            mTexture.drawMixed(canvas, mPlaceholderColor, getRatio(), x, y,
-                    width, height);
-        } else {
-            mTexture.draw(canvas, x, y, width, height);
-        }
+    public void recycle() {
+        mBitmapTexture.recycle();
     }
 
     @Override
     public void draw(GLCanvas canvas, RectF source, RectF dest) {
-        if (mTexture == null || !mTexture.isReady()) {
-            canvas.fillRect(dest.left, dest.top, dest.width(), dest.height(),
-                    mPlaceholderColor);
-            return;
-        }
-
-        mTexture.draw(canvas, source, dest);
-    }
-
-    public boolean isAnimating() {
-        if (mAnimationStartTime < 0) return false;
-        if (AnimationTime.get() - mAnimationStartTime >= DURATION) {
-            mAnimationStartTime = ANIMATION_DONE;
-            return false;
-        }
-        return true;
-    }
-
-    private float getRatio() {
-        float r = (float) (AnimationTime.get() - mAnimationStartTime) / DURATION;
-        return Utils.clamp(1.0f - r, 0.0f, 1.0f);
-    }
-
-    public boolean isShowingPlaceholder() {
-        return (mBitmap == null) || isAnimating();
-    }
-
-    public TiledTexture getTexture() {
-        return mTexture;
-    }
-
-    public static void setMaxSide(int size) {
-        sMaxSide = size;
+        canvas.drawTexture(mBitmapTexture, source, dest);
     }
 }
index c6bf535..edd7c72 100644 (file)
@@ -850,8 +850,8 @@ public class PhotoView extends GLView {
         }
 
         private boolean isScreenNailAnimating() {
-            return (mScreenNail instanceof BitmapScreenNail)
-                    && ((BitmapScreenNail) mScreenNail).isAnimating();
+            return (mScreenNail instanceof TiledScreenNail)
+                    && ((TiledScreenNail) mScreenNail).isAnimating();
         }
 
         @Override
@@ -1792,8 +1792,8 @@ public class PhotoView extends GLView {
             MediaItem item = mModel.getMediaItem(i);
             if (item == null) continue;
             ScreenNail sc = mModel.getScreenNail(i);
-            if (!(sc instanceof BitmapScreenNail)
-                    || ((BitmapScreenNail) sc).isShowingPlaceholder()) continue;
+            if (!(sc instanceof TiledScreenNail)
+                    || ((TiledScreenNail) sc).isShowingPlaceholder()) continue;
 
             // Now, sc is BitmapScreenNail and is not showing placeholder
             Rect rect = new Rect(getPhotoRect(i));
index 18a7af8..8f26981 100644 (file)
@@ -462,8 +462,8 @@ public class TileImageView extends GLView {
     }
 
     private boolean isScreenNailAnimating() {
-        return (mScreenNail instanceof BitmapScreenNail)
-                && ((BitmapScreenNail) mScreenNail).isAnimating();
+        return (mScreenNail instanceof TiledScreenNail)
+                && ((TiledScreenNail) mScreenNail).isAnimating();
     }
 
     private void uploadBackgroundTiles(GLCanvas canvas) {
index 08d3379..45e2ce2 100644 (file)
@@ -40,51 +40,25 @@ public class TileImageViewAdapter implements TileImageView.Model {
     public TileImageViewAdapter() {
     }
 
-    public TileImageViewAdapter(
-            Bitmap bitmap, BitmapRegionDecoder regionDecoder) {
-        Utils.checkNotNull(bitmap);
-        updateScreenNail(new BitmapScreenNail(bitmap), true);
-        mRegionDecoder = regionDecoder;
-        mImageWidth = regionDecoder.getWidth();
-        mImageHeight = regionDecoder.getHeight();
-        mLevelCount = calculateLevelCount();
-    }
-
     public synchronized void clear() {
-        updateScreenNail(null, false);
+        mScreenNail = null;
         mImageWidth = 0;
         mImageHeight = 0;
         mLevelCount = 0;
         mRegionDecoder = null;
     }
 
-    public synchronized void setScreenNail(Bitmap bitmap, int width, int height) {
-        Utils.checkNotNull(bitmap);
-        updateScreenNail(new BitmapScreenNail(bitmap), true);
-        mImageWidth = width;
-        mImageHeight = height;
-        mRegionDecoder = null;
-        mLevelCount = 0;
-    }
-
+    // Caller is responsible to recycle the ScreenNail
     public synchronized void setScreenNail(
             ScreenNail screenNail, int width, int height) {
         Utils.checkNotNull(screenNail);
-        updateScreenNail(screenNail, false);
+        mScreenNail = screenNail;
         mImageWidth = width;
         mImageHeight = height;
         mRegionDecoder = null;
         mLevelCount = 0;
     }
 
-    private void updateScreenNail(ScreenNail screenNail, boolean own) {
-        if (mScreenNail != null && mOwnScreenNail) {
-            mScreenNail.recycle();
-        }
-        mScreenNail = screenNail;
-        mOwnScreenNail = own;
-    }
-
     public synchronized void setRegionDecoder(BitmapRegionDecoder decoder) {
         mRegionDecoder = Utils.checkNotNull(decoder);
         mImageWidth = decoder.getWidth();
diff --git a/src/com/android/gallery3d/ui/TiledScreenNail.java b/src/com/android/gallery3d/ui/TiledScreenNail.java
new file mode 100644 (file)
index 0000000..d2b34e3
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * 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.ui;
+
+import android.graphics.Bitmap;
+import android.graphics.RectF;
+
+import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.data.BitmapPool;
+import com.android.gallery3d.data.MediaItem;
+
+// This is a ScreenNail wraps a Bitmap. There are some extra functions:
+//
+// - If we need to draw before the bitmap is available, we draw a rectange of
+// placeholder color (gray).
+//
+// - When the the bitmap is available, and we have drawn the placeholder color
+// before, we will do a fade-in animation.
+public class TiledScreenNail implements ScreenNail {
+    @SuppressWarnings("unused")
+    private static final String TAG = "TiledScreenNail";
+
+    // The duration of the fading animation in milliseconds
+    private static final int DURATION = 180;
+
+    private static int sMaxSide = 640;
+
+    // These are special values for mAnimationStartTime
+    private static final long ANIMATION_NOT_NEEDED = -1;
+    private static final long ANIMATION_NEEDED = -2;
+    private static final long ANIMATION_DONE = -3;
+
+    private int mWidth;
+    private int mHeight;
+    private long mAnimationStartTime = ANIMATION_NOT_NEEDED;
+
+    private Bitmap mBitmap;
+    private TiledTexture mTexture;
+
+    public TiledScreenNail(Bitmap bitmap) {
+        mWidth = bitmap.getWidth();
+        mHeight = bitmap.getHeight();
+        mBitmap = bitmap;
+        mTexture = new TiledTexture(bitmap);
+    }
+
+    public TiledScreenNail(int width, int height) {
+        setSize(width, height);
+    }
+
+    // This gets overridden by bitmap_screennail_placeholder
+    // in GalleryUtils.initialize
+    private static int mPlaceholderColor = 0xFF222222;
+    private static boolean mDrawPlaceholder = true;
+
+    public static void setPlaceholderColor(int color) {
+        mPlaceholderColor = color;
+    }
+
+    private void setSize(int width, int height) {
+        if (width == 0 || height == 0) {
+            width = sMaxSide;
+            height = sMaxSide * 3 / 4;
+        }
+        float scale = Math.min(1, (float) sMaxSide / Math.max(width, height));
+        mWidth = Math.round(scale * width);
+        mHeight = Math.round(scale * height);
+    }
+
+    private static void recycleBitmap(BitmapPool pool, Bitmap bitmap) {
+        if (pool == null || bitmap == null) return;
+        pool.recycle(bitmap);
+    }
+
+    // Combines the two ScreenNails.
+    // Returns the used one and recycle the unused one.
+    public ScreenNail combine(ScreenNail other) {
+        if (other == null) {
+            return this;
+        }
+
+        if (!(other instanceof TiledScreenNail)) {
+            recycle();
+            return other;
+        }
+
+        // Now both are TiledScreenNail. Move over the information about width,
+        // height, and Bitmap, then recycle the other.
+        TiledScreenNail newer = (TiledScreenNail) other;
+        mWidth = newer.mWidth;
+        mHeight = newer.mHeight;
+        if (newer.mTexture != null) {
+            recycleBitmap(MediaItem.getThumbPool(), mBitmap);
+            if (mTexture != null) mTexture.recycle();
+            mBitmap = newer.mBitmap;
+            mTexture = newer.mTexture;
+            newer.mBitmap = null;
+            newer.mTexture = null;
+        }
+        newer.recycle();
+        return this;
+    }
+
+    public void updatePlaceholderSize(int width, int height) {
+        if (mBitmap != null) return;
+        if (width == 0 || height == 0) return;
+        setSize(width, height);
+    }
+
+    @Override
+    public int getWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getHeight() {
+        return mHeight;
+    }
+
+    @Override
+    public void noDraw() {
+    }
+
+    @Override
+    public void recycle() {
+        if (mTexture != null) {
+            mTexture.recycle();
+            mTexture = null;
+        }
+        recycleBitmap(MediaItem.getThumbPool(), mBitmap);
+        mBitmap = null;
+    }
+
+    public static void disableDrawPlaceholder() {
+        mDrawPlaceholder = false;
+    }
+
+    public static void enableDrawPlaceholder() {
+        mDrawPlaceholder = true;
+    }
+
+    @Override
+    public void draw(GLCanvas canvas, int x, int y, int width, int height) {
+        if (mTexture == null || !mTexture.isReady()) {
+            if (mAnimationStartTime == ANIMATION_NOT_NEEDED) {
+                mAnimationStartTime = ANIMATION_NEEDED;
+            }
+            if(mDrawPlaceholder) {
+                canvas.fillRect(x, y, width, height, mPlaceholderColor);
+            }
+            return;
+        }
+
+        if (mAnimationStartTime == ANIMATION_NEEDED) {
+            mAnimationStartTime = AnimationTime.get();
+        }
+
+        if (isAnimating()) {
+            mTexture.drawMixed(canvas, mPlaceholderColor, getRatio(), x, y,
+                    width, height);
+        } else {
+            mTexture.draw(canvas, x, y, width, height);
+        }
+    }
+
+    @Override
+    public void draw(GLCanvas canvas, RectF source, RectF dest) {
+        if (mTexture == null || !mTexture.isReady()) {
+            canvas.fillRect(dest.left, dest.top, dest.width(), dest.height(),
+                    mPlaceholderColor);
+            return;
+        }
+
+        mTexture.draw(canvas, source, dest);
+    }
+
+    public boolean isAnimating() {
+        if (mAnimationStartTime < 0) return false;
+        if (AnimationTime.get() - mAnimationStartTime >= DURATION) {
+            mAnimationStartTime = ANIMATION_DONE;
+            return false;
+        }
+        return true;
+    }
+
+    private float getRatio() {
+        float r = (float) (AnimationTime.get() - mAnimationStartTime) / DURATION;
+        return Utils.clamp(1.0f - r, 0.0f, 1.0f);
+    }
+
+    public boolean isShowingPlaceholder() {
+        return (mBitmap == null) || isAnimating();
+    }
+
+    public TiledTexture getTexture() {
+        return mTexture;
+    }
+
+    public static void setMaxSide(int size) {
+        sMaxSide = size;
+    }
+}
index 1955521..62f2235 100644 (file)
@@ -42,7 +42,7 @@ import com.android.gallery3d.app.PackagesMonitor;
 import com.android.gallery3d.common.ApiHelper;
 import com.android.gallery3d.data.DataManager;
 import com.android.gallery3d.data.MediaItem;
-import com.android.gallery3d.ui.BitmapScreenNail;
+import com.android.gallery3d.ui.TiledScreenNail;
 import com.android.gallery3d.util.ThreadPool.CancelListener;
 import com.android.gallery3d.util.ThreadPool.JobContext;
 
@@ -81,7 +81,7 @@ public class GalleryUtils {
         wm.getDefaultDisplay().getMetrics(metrics);
         sPixelDensity = metrics.density;
         Resources r = context.getResources();
-        BitmapScreenNail.setPlaceholderColor(r.getColor(
+        TiledScreenNail.setPlaceholderColor(r.getColor(
                 R.color.bitmap_screennail_placeholder));
         initializeThumbnailSizes(metrics, r);
     }
@@ -91,7 +91,7 @@ public class GalleryUtils {
         // Never need to completely fill the screen
         maxDimensionPixels = maxDimensionPixels / 2;
         MediaItem.setThumbnailSizes(maxDimensionPixels, 200);
-        BitmapScreenNail.setMaxSide(maxDimensionPixels);
+        TiledScreenNail.setMaxSide(maxDimensionPixels);
     }
 
     public static boolean isHighResolution(Context context) {