Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 030f8dad authored by Owen Lin's avatar Owen Lin
Browse files

Fixes bugs in TiledTexture.

1. Upload tiles in SinglePhotoDataAdapter
2. Rebuild the upload queue after the screen nails being recycled

bug: 6399444

Change-Id: I57e756f8d1d84742bf82dd34c83baf8df89ae4cc
parent ff025412
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -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();
+11 −10
Original line number Diff line number Diff line
@@ -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
+3 −3
Original line number Diff line number Diff line
@@ -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) :
+11 −0
Original line number Diff line number Diff line
@@ -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
+11 −169
Original line number Diff line number Diff line
@@ -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);
    }
}
Loading