chromium/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PickerBitmapViewHolder.java

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.components.browser_ui.photo_picker;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.os.SystemClock;
import android.text.TextUtils;

import androidx.recyclerview.widget.RecyclerView.ViewHolder;

import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.task.AsyncTask;

import java.util.ArrayList;
import java.util.List;

/** Holds on to a {@link PickerBitmapView} that displays information about a picker bitmap. */
public class PickerBitmapViewHolder extends ViewHolder
        implements DecoderServiceHost.ImagesDecodedCallback {
    // Our parent category.
    private PickerCategoryView mCategoryView;

    // The bitmap view we are holding on to.
    private final PickerBitmapView mItemView;

    // The request we are showing the bitmap for.
    private PickerBitmap mBitmapDetails;

    /**
     * The PickerBitmapViewHolder.
     *
     * @param itemView The {@link PickerBitmapView} view for showing the image.
     */
    public PickerBitmapViewHolder(PickerBitmapView itemView) {
        super(itemView);
        mItemView = itemView;
    }

    // DecoderServiceHost.ImageDecodedCallback

    @Override
    public void imagesDecodedCallback(
            String filePath,
            boolean isVideo,
            boolean fullWidth,
            List<Bitmap> bitmaps,
            String videoDuration,
            float ratio) {
        if (bitmaps == null || bitmaps.size() == 0) return;

        if (!isVideo) {
            Bitmap bitmap = bitmaps.get(0);
            if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) return;
        }

        PickerCategoryView.Thumbnail cachedThumbnail =
                fullWidth
                        ? mCategoryView.getFullScreenBitmaps().get(filePath)
                        : mCategoryView.getHighResThumbnails().get(filePath);
        if (cachedThumbnail == null
                || (cachedThumbnail.bitmaps != null
                        && cachedThumbnail.bitmaps.size() < bitmaps.size())) {
            if (fullWidth) {
                mCategoryView
                        .getFullScreenBitmaps()
                        .put(
                                filePath,
                                new PickerCategoryView.Thumbnail(
                                        bitmaps, videoDuration, fullWidth, ratio));
            } else {
                mCategoryView
                        .getHighResThumbnails()
                        .put(
                                filePath,
                                new PickerCategoryView.Thumbnail(
                                        bitmaps, videoDuration, fullWidth, ratio));
            }
        }

        if (mCategoryView.getLowResThumbnails().get(filePath) == null) {
            Resources resources = mItemView.getContext().getResources();
            new BitmapScalerTask(
                            mCategoryView.getLowResThumbnails(),
                            bitmaps.get(0),
                            filePath,
                            videoDuration,
                            resources.getDimensionPixelSize(
                                    R.dimen.photo_picker_grainy_thumbnail_size),
                            ratio)
                    .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        }

        if (!TextUtils.equals(getFilePath(), filePath)) {
            return;
        }

        if (mItemView.setThumbnailBitmap(bitmaps, videoDuration, ratio)) {
            mItemView.fadeInThumbnail();
        }
    }

    /**
     * Display a single item from |position| in the PickerCategoryView.
     *
     * @param categoryView The PickerCategoryView to use to fetch the image.
     * @param position The position of the item to fetch.
     * @return The decoding action required to display the item.
     */
    public @PickerAdapter.DecodeActions int displayItem(
            PickerCategoryView categoryView, int position) {
        mCategoryView = categoryView;

        List<PickerBitmap> pickerBitmaps = mCategoryView.getPickerBitmaps();
        mBitmapDetails = pickerBitmaps.get(position);

        if (mBitmapDetails.type() == PickerBitmap.TileTypes.CAMERA
                || mBitmapDetails.type() == PickerBitmap.TileTypes.GALLERY) {
            mItemView.initialize(mBitmapDetails, null, null, false, -1);
            return PickerAdapter.DecodeActions.NO_ACTION;
        }

        String filePath = mBitmapDetails.getUri().getPath();
        PickerCategoryView.Thumbnail original =
                mCategoryView.isInMagnifyingMode()
                        ? mCategoryView.getFullScreenBitmaps().get(filePath)
                        : mCategoryView.getHighResThumbnails().get(filePath);
        if (original != null) {
            mItemView.initialize(
                    mBitmapDetails,
                    original.bitmaps,
                    original.videoDuration,
                    false,
                    original.ratioOriginal);
            return PickerAdapter.DecodeActions.FROM_CACHE;
        }

        int width = mCategoryView.getImageWidth();
        PickerCategoryView.Thumbnail payload = null;
        if (mCategoryView.isInMagnifyingMode()) {
            payload = mCategoryView.getHighResThumbnails().get(filePath);
        }
        if (payload == null) {
            payload = mCategoryView.getLowResThumbnails().get(filePath);
        }

        if (payload != null) {
            Bitmap placeholder = payload.bitmaps.get(0);
            // For performance stats see http://crbug.com/719919.
            long begin = SystemClock.elapsedRealtime();
            placeholder = BitmapUtils.scale(placeholder, width, false);
            long scaleTime = SystemClock.elapsedRealtime() - begin;
            RecordHistogram.recordTimesHistogram(
                    "Android.PhotoPicker.UpscaleLowResBitmap", scaleTime);
            List<Bitmap> bitmaps = new ArrayList<>(1);
            bitmaps.add(placeholder);

            mItemView.initialize(
                    mBitmapDetails, bitmaps, payload.videoDuration, true, payload.ratioOriginal);
        } else {
            mItemView.initialize(mBitmapDetails, null, null, true, -1);
        }

        mCategoryView
                .getDecoderServiceHost()
                .decodeImage(
                        mBitmapDetails.getUri(),
                        mBitmapDetails.type(),
                        width,
                        mCategoryView.isInMagnifyingMode(),
                        this);
        return PickerAdapter.DecodeActions.DECODE;
    }

    /**
     * Returns the file path of the current request, or null if no request is in progress for this
     * holder.
     */
    public String getFilePath() {
        if (mBitmapDetails == null
                || (mBitmapDetails.type() != PickerBitmap.TileTypes.PICTURE
                        && mBitmapDetails.type() != PickerBitmap.TileTypes.VIDEO)) {
            return null;
        }
        return mBitmapDetails.getUri().getPath();
    }
}