Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4ace3a92e31fb563ef57dd033539b09ffb8fde5d |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java |
| @@ -0,0 +1,245 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.chrome.browser.photo_picker; |
| + |
| +import android.app.Activity; |
| +import android.content.Context; |
| +import android.graphics.Bitmap; |
| +import android.graphics.Canvas; |
| +import android.graphics.Paint; |
| +import android.graphics.PorterDuff; |
| +import android.graphics.PorterDuffColorFilter; |
| +import android.support.v7.widget.GridLayoutManager; |
| +import android.support.v7.widget.RecyclerView; |
| +import android.support.v7.widget.Toolbar.OnMenuItemClickListener; |
| +import android.util.AttributeSet; |
| +import android.view.LayoutInflater; |
| +import android.view.MenuItem; |
| +import android.view.View; |
| +import android.widget.RelativeLayout; |
| + |
| +import org.chromium.chrome.R; |
| +import org.chromium.chrome.browser.widget.selection.SelectableListLayout; |
| +import org.chromium.chrome.browser.widget.selection.SelectionDelegate; |
| +import org.chromium.ui.PhotoPickerListener; |
| + |
| +import java.util.ArrayList; |
| +import java.util.List; |
| + |
| +/** |
| + * A class for keeping track of common data associated with showing photos in |
| + * the photo picker, for example the RecyclerView and the bitmap caches. |
| + */ |
| +public class PickerCategoryView extends RelativeLayout implements OnMenuItemClickListener { |
| + private static final int KILOBYTE = 1024; |
| + |
| + // The dialog that owns us. |
| + private PhotoPickerDialog mDialog; |
| + |
| + // The view containing the recycler view and the toolbar, etc. |
| + private SelectableListLayout<PickerBitmap> mSelectableListLayout; |
| + |
| + // Our context. |
| + private Context mContext; |
| + |
| + // The list of images on disk, sorted by last-modified first. |
| + private List<PickerBitmap> mPickerBitmaps; |
| + |
| + // True if multi-selection is allowed in the picker. |
| + private boolean mMultiSelectionAllowed; |
| + |
| + // The callback to notify the listener of decisions reached in the picker. |
| + private PhotoPickerListener mListener; |
| + |
| + // The recycler view showing the images. |
| + private RecyclerView mRecyclerView; |
| + |
| + // The picker adapter for the RecyclerView. |
| + private PickerAdapter mPickerAdapter; |
| + |
| + // The selection delegate keeping track of which images are selected. |
| + private SelectionDelegate<PickerBitmap> mSelectionDelegate; |
| + |
| + /** |
| + * The number of columns to show. Note: mColumns and mPadding (see below) should both be even |
| + * numbers or both odd, not a mix (the column padding will not be of uniform thickness if they |
| + * are a mix). |
| + */ |
| + private int mColumns; |
| + |
| + // The padding between columns. See also comment for mColumns. |
| + private int mPadding; |
| + |
| + // The size of the bitmaps (equal length for width and height). |
| + private int mImageSize; |
| + |
| + public PickerCategoryView(Context context) { |
| + super(context); |
| + init(context); |
| + } |
| + |
| + public PickerCategoryView(Context context, AttributeSet attrs) { |
| + super(context, attrs); |
| + init(context); |
| + } |
| + |
| + public PickerCategoryView(Context context, AttributeSet attrs, int defStyle) { |
| + super(context, attrs, defStyle); |
| + init(context); |
| + } |
| + |
| + /** |
| + * A helper function for initializing the PickerCategoryView. |
| + * @param context The context to use. |
| + */ |
| + @SuppressWarnings("unchecked") // mSelectableListLayout |
| + private void init(Context context) { |
| + mContext = context; |
| + |
| + mSelectionDelegate = new SelectionDelegate<PickerBitmap>(); |
| + |
| + View root = LayoutInflater.from(context).inflate(R.layout.photo_picker_dialog, this); |
| + mSelectableListLayout = |
| + (SelectableListLayout<PickerBitmap>) root.findViewById(R.id.selectable_list); |
| + |
| + mPickerAdapter = new PickerAdapter(this); |
| + mRecyclerView = mSelectableListLayout.initializeRecyclerView(mPickerAdapter); |
| + mSelectableListLayout.initializeToolbar(R.layout.photo_picker_toolbar, mSelectionDelegate, |
| + R.string.menu_history, null, R.id.file_picker_normal_menu_group, |
| + R.id.file_picker_selection_mode_menu_group, R.color.default_primary_color, false, |
| + this); |
| + |
| + View view = ((Activity) context).getWindow().getDecorView(); |
|
Theresa
2017/03/31 18:05:56
getDecorView() contains all of the window decorati
Finnur
2017/04/03 17:30:30
We only care about the width here.
Theresa
2017/04/04 15:48:32
Sometimes the width contains the window decoration
Finnur
2017/04/04 18:05:36
Done.
|
| + int width = view.getWidth() - view.getPaddingLeft() - view.getPaddingRight(); |
| + |
| + calculateGridMetrics(width); |
| + |
| + RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(mContext, mColumns); |
| + mRecyclerView.setHasFixedSize(true); |
| + mRecyclerView.setLayoutManager(mLayoutManager); |
| + // TODO(finnur): Implement grid spacing. |
| + // TODO(finnur): Implement caching. |
| + // TODO(finnur): Remove this once the decoder service is in place. |
| + prepareBitmaps(); |
| + } |
| + |
| + /** |
| + * Sets the starting state for the PickerCategoryView object. |
| + * @param dialog The dialog showing us. |
| + * @param listener The listener who should be notified of actions. |
| + * @param multiSelection Whether to allow the user to select more than one image. |
| + */ |
| + public void setStartingState( |
|
Theresa
2017/03/31 18:05:56
The values set in this don't appear to change so #
Finnur
2017/04/03 17:30:30
Yeah, I struggled with this as well. All I can thi
Theresa
2017/04/04 15:48:32
What about something like postConstruction() for t
Finnur
2017/04/04 18:05:36
Sounds reasonable.
|
| + PhotoPickerDialog dialog, PhotoPickerListener listener, boolean multiSelection) { |
|
Theresa
2017/03/31 18:05:56
Please rename this parameter to match mMultiSelect
Finnur
2017/04/03 17:30:30
Done.
|
| + // TODO(finnur): Change selection delegate to support single-selection. |
| + |
| + mDialog = dialog; |
| + mMultiSelectionAllowed = multiSelection; |
| + mListener = listener; |
| + } |
| + |
| + // OnMenuItemClickListener: |
| + |
| + @Override |
| + public boolean onMenuItemClick(MenuItem item) { |
| + if (item.getItemId() == R.id.close_menu_id |
| + || item.getItemId() == R.id.selection_mode_done_menu_id) { |
| + tryNotifyPhotoSet(); |
| + mDialog.dismiss(); |
| + return true; |
| + } |
| + return false; |
| + } |
| + |
| + // Simple accessors: |
| + |
| + public int getImageSize() { |
| + return mImageSize; |
| + } |
| + public SelectionDelegate<PickerBitmap> getSelectionDelegate() { |
|
Theresa
2017/03/31 18:05:56
nit: add a blank space above this method and the o
Finnur
2017/04/03 17:30:30
Done.
|
| + return mSelectionDelegate; |
| + } |
| + public List<PickerBitmap> getPickerBitmaps() { |
| + return mPickerBitmaps; |
| + } |
| + public boolean isMultiSelect() { |
|
Theresa
2017/03/31 18:05:56
Please rename this method as well.
Finnur
2017/04/03 17:30:30
Done.
|
| + return mMultiSelectionAllowed; |
| + } |
| + |
| + /** |
| + * Notifies the caller that the user selected to launch the gallery. |
| + */ |
| + public void showGallery() { |
| + mListener.onPickerUserAction(PhotoPickerListener.Action.LAUNCH_GALLERY, null); |
| + } |
| + |
| + /** |
| + * Notifies the caller that the user selected to launch the camera intent. |
| + */ |
| + public void showCamera() { |
| + mListener.onPickerUserAction(PhotoPickerListener.Action.LAUNCH_CAMERA, null); |
| + } |
| + |
| + /** |
| + * Applies a color filter to a bitmap. |
| + * @param original The bitmap to color. |
| + * @param color The color to apply. |
| + * @return A colored bitmap. |
| + */ |
| + private Bitmap colorBitmap(Bitmap original, int color) { |
|
Theresa
2017/03/31 18:05:56
It looks like this is no longer used.
Finnur
2017/04/03 17:30:30
Correct.
|
| + Bitmap mutable = original.copy(Bitmap.Config.ARGB_8888, true); |
| + Canvas canvas = new Canvas(mutable); |
| + Paint paint = new Paint(); |
| + paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); |
| + canvas.drawBitmap(mutable, 0.f, 0.f, paint); |
| + return mutable; |
| + } |
| + |
| + /** |
| + * Calculates image size and how many columns can fit on-screen. |
| + * @param width The total width of the boundary to show the images in. |
| + */ |
| + private void calculateGridMetrics(int width) { |
| + int minSize = |
| + mContext.getResources().getDimensionPixelSize(R.dimen.file_picker_tile_min_size); |
| + mPadding = mContext.getResources().getDimensionPixelSize(R.dimen.file_picker_tile_gap); |
| + mColumns = Math.max(1, (width - mPadding) / (minSize + mPadding)); |
| + mImageSize = (width - mPadding * (mColumns + 1)) / (mColumns); |
| + |
| + // Make sure columns and padding are either both even or both odd. |
| + if (((mColumns % 2) == 0) != ((mPadding % 2) == 0)) { |
| + mPadding++; |
| + } |
| + } |
| + |
| + /** |
| + * Prepares bitmaps for loading. |
| + */ |
| + private void prepareBitmaps() { |
| + // TODO(finnur): Use worker thread to fetch bitmaps instead of hard-coding. |
| + mPickerBitmaps = new ArrayList<>(); |
| + mPickerBitmaps.add(0, new PickerBitmap("", 0, PickerBitmap.TileTypes.GALLERY)); |
| + mPickerBitmaps.add(0, new PickerBitmap("", 0, PickerBitmap.TileTypes.CAMERA)); |
| + mPickerBitmaps.add(new PickerBitmap("foo/bar1.jpg", 1, PickerBitmap.TileTypes.PICTURE)); |
| + mPickerBitmaps.add(new PickerBitmap("foo/bar2.jpg", 2, PickerBitmap.TileTypes.PICTURE)); |
| + mPickerBitmaps.add(new PickerBitmap("foo/bar3.jpg", 3, PickerBitmap.TileTypes.PICTURE)); |
| + mPickerBitmaps.add(new PickerBitmap("foo/bar4.jpg", 4, PickerBitmap.TileTypes.PICTURE)); |
| + mPickerAdapter.notifyDataSetChanged(); |
| + } |
| + |
| + /** |
| + * Tries to notify any listeners that one or more photos have been selected. |
|
Theresa
2017/03/31 18:05:56
When would it not successfully notify the listener
Finnur
2017/04/03 17:30:30
Yes, in an old revision this could actually result
|
| + */ |
| + private void tryNotifyPhotoSet() { |
| + List<PickerBitmap> selectedFiles = mSelectionDelegate.getSelectedItems(); |
| + String[] photos = new String[selectedFiles.size()]; |
| + int i = 0; |
| + for (PickerBitmap bitmap : selectedFiles) { |
| + photos[i++] = bitmap.getFilePath(); |
| + } |
| + |
| + mListener.onPickerUserAction(PhotoPickerListener.Action.PHOTOS_SELECTED, photos); |
| + } |
| +} |