Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.chrome.browser.photo_picker; | |
| 6 | |
| 7 import android.app.Activity; | |
| 8 import android.content.Context; | |
| 9 import android.graphics.Bitmap; | |
| 10 import android.graphics.Canvas; | |
| 11 import android.graphics.Paint; | |
| 12 import android.graphics.PorterDuff; | |
| 13 import android.graphics.PorterDuffColorFilter; | |
| 14 import android.support.v7.widget.GridLayoutManager; | |
| 15 import android.support.v7.widget.RecyclerView; | |
| 16 import android.support.v7.widget.Toolbar.OnMenuItemClickListener; | |
| 17 import android.util.AttributeSet; | |
| 18 import android.view.LayoutInflater; | |
| 19 import android.view.MenuItem; | |
| 20 import android.view.View; | |
| 21 import android.widget.RelativeLayout; | |
| 22 | |
| 23 import org.chromium.chrome.R; | |
| 24 import org.chromium.chrome.browser.widget.selection.SelectableListLayout; | |
| 25 import org.chromium.chrome.browser.widget.selection.SelectionDelegate; | |
| 26 import org.chromium.ui.PhotoPickerListener; | |
| 27 | |
| 28 import java.util.ArrayList; | |
| 29 import java.util.List; | |
| 30 | |
| 31 /** | |
| 32 * A class for keeping track of common data associated with showing photos in | |
| 33 * the photo picker, for example the RecyclerView and the bitmap caches. | |
| 34 */ | |
| 35 public class PickerCategoryView extends RelativeLayout implements OnMenuItemClic kListener { | |
| 36 private static final int KILOBYTE = 1024; | |
| 37 | |
| 38 // The dialog that owns us. | |
| 39 private PhotoPickerDialog mDialog; | |
| 40 | |
| 41 // The view containing the recycler view and the toolbar, etc. | |
| 42 private SelectableListLayout<PickerBitmap> mSelectableListLayout; | |
| 43 | |
| 44 // Our context. | |
| 45 private Context mContext; | |
| 46 | |
| 47 // The list of images on disk, sorted by last-modified first. | |
| 48 private List<PickerBitmap> mPickerBitmaps; | |
| 49 | |
| 50 // True if multi-selection is allowed in the picker. | |
| 51 private boolean mMultiSelectionAllowed; | |
| 52 | |
| 53 // The callback to notify the listener of decisions reached in the picker. | |
| 54 private PhotoPickerListener mListener; | |
| 55 | |
| 56 // The recycler view showing the images. | |
| 57 private RecyclerView mRecyclerView; | |
| 58 | |
| 59 // The picker adapter for the RecyclerView. | |
| 60 private PickerAdapter mPickerAdapter; | |
| 61 | |
| 62 // The selection delegate keeping track of which images are selected. | |
| 63 private SelectionDelegate<PickerBitmap> mSelectionDelegate; | |
| 64 | |
| 65 /** | |
| 66 * The number of columns to show. Note: mColumns and mPadding (see below) sh ould both be even | |
| 67 * numbers or both odd, not a mix (the column padding will not be of uniform thickness if they | |
| 68 * are a mix). | |
| 69 */ | |
| 70 private int mColumns; | |
| 71 | |
| 72 // The padding between columns. See also comment for mColumns. | |
| 73 private int mPadding; | |
| 74 | |
| 75 // The size of the bitmaps (equal length for width and height). | |
| 76 private int mImageSize; | |
| 77 | |
| 78 public PickerCategoryView(Context context) { | |
| 79 super(context); | |
| 80 init(context); | |
| 81 } | |
| 82 | |
| 83 public PickerCategoryView(Context context, AttributeSet attrs) { | |
| 84 super(context, attrs); | |
| 85 init(context); | |
| 86 } | |
| 87 | |
| 88 public PickerCategoryView(Context context, AttributeSet attrs, int defStyle) { | |
| 89 super(context, attrs, defStyle); | |
| 90 init(context); | |
| 91 } | |
| 92 | |
| 93 /** | |
| 94 * A helper function for initializing the PickerCategoryView. | |
| 95 * @param context The context to use. | |
| 96 */ | |
| 97 @SuppressWarnings("unchecked") // mSelectableListLayout | |
| 98 private void init(Context context) { | |
| 99 mContext = context; | |
| 100 | |
| 101 mSelectionDelegate = new SelectionDelegate<PickerBitmap>(); | |
| 102 | |
| 103 View root = LayoutInflater.from(context).inflate(R.layout.photo_picker_d ialog, this); | |
| 104 mSelectableListLayout = | |
| 105 (SelectableListLayout<PickerBitmap>) root.findViewById(R.id.sele ctable_list); | |
| 106 | |
| 107 mPickerAdapter = new PickerAdapter(this); | |
| 108 mRecyclerView = mSelectableListLayout.initializeRecyclerView(mPickerAdap ter); | |
| 109 mSelectableListLayout.initializeToolbar(R.layout.photo_picker_toolbar, m SelectionDelegate, | |
| 110 R.string.menu_history, null, R.id.file_picker_normal_menu_group, | |
| 111 R.id.file_picker_selection_mode_menu_group, R.color.default_prim ary_color, false, | |
| 112 this); | |
| 113 | |
| 114 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.
| |
| 115 int width = view.getWidth() - view.getPaddingLeft() - view.getPaddingRig ht(); | |
| 116 | |
| 117 calculateGridMetrics(width); | |
| 118 | |
| 119 RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(mConte xt, mColumns); | |
| 120 mRecyclerView.setHasFixedSize(true); | |
| 121 mRecyclerView.setLayoutManager(mLayoutManager); | |
| 122 // TODO(finnur): Implement grid spacing. | |
| 123 // TODO(finnur): Implement caching. | |
| 124 // TODO(finnur): Remove this once the decoder service is in place. | |
| 125 prepareBitmaps(); | |
| 126 } | |
| 127 | |
| 128 /** | |
| 129 * Sets the starting state for the PickerCategoryView object. | |
| 130 * @param dialog The dialog showing us. | |
| 131 * @param listener The listener who should be notified of actions. | |
| 132 * @param multiSelection Whether to allow the user to select more than one i mage. | |
| 133 */ | |
| 134 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.
| |
| 135 PhotoPickerDialog dialog, PhotoPickerListener listener, boolean mult iSelection) { | |
|
Theresa
2017/03/31 18:05:56
Please rename this parameter to match mMultiSelect
Finnur
2017/04/03 17:30:30
Done.
| |
| 136 // TODO(finnur): Change selection delegate to support single-selection. | |
| 137 | |
| 138 mDialog = dialog; | |
| 139 mMultiSelectionAllowed = multiSelection; | |
| 140 mListener = listener; | |
| 141 } | |
| 142 | |
| 143 // OnMenuItemClickListener: | |
| 144 | |
| 145 @Override | |
| 146 public boolean onMenuItemClick(MenuItem item) { | |
| 147 if (item.getItemId() == R.id.close_menu_id | |
| 148 || item.getItemId() == R.id.selection_mode_done_menu_id) { | |
| 149 tryNotifyPhotoSet(); | |
| 150 mDialog.dismiss(); | |
| 151 return true; | |
| 152 } | |
| 153 return false; | |
| 154 } | |
| 155 | |
| 156 // Simple accessors: | |
| 157 | |
| 158 public int getImageSize() { | |
| 159 return mImageSize; | |
| 160 } | |
| 161 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.
| |
| 162 return mSelectionDelegate; | |
| 163 } | |
| 164 public List<PickerBitmap> getPickerBitmaps() { | |
| 165 return mPickerBitmaps; | |
| 166 } | |
| 167 public boolean isMultiSelect() { | |
|
Theresa
2017/03/31 18:05:56
Please rename this method as well.
Finnur
2017/04/03 17:30:30
Done.
| |
| 168 return mMultiSelectionAllowed; | |
| 169 } | |
| 170 | |
| 171 /** | |
| 172 * Notifies the caller that the user selected to launch the gallery. | |
| 173 */ | |
| 174 public void showGallery() { | |
| 175 mListener.onPickerUserAction(PhotoPickerListener.Action.LAUNCH_GALLERY, null); | |
| 176 } | |
| 177 | |
| 178 /** | |
| 179 * Notifies the caller that the user selected to launch the camera intent. | |
| 180 */ | |
| 181 public void showCamera() { | |
| 182 mListener.onPickerUserAction(PhotoPickerListener.Action.LAUNCH_CAMERA, n ull); | |
| 183 } | |
| 184 | |
| 185 /** | |
| 186 * Applies a color filter to a bitmap. | |
| 187 * @param original The bitmap to color. | |
| 188 * @param color The color to apply. | |
| 189 * @return A colored bitmap. | |
| 190 */ | |
| 191 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.
| |
| 192 Bitmap mutable = original.copy(Bitmap.Config.ARGB_8888, true); | |
| 193 Canvas canvas = new Canvas(mutable); | |
| 194 Paint paint = new Paint(); | |
| 195 paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SR C_IN)); | |
| 196 canvas.drawBitmap(mutable, 0.f, 0.f, paint); | |
| 197 return mutable; | |
| 198 } | |
| 199 | |
| 200 /** | |
| 201 * Calculates image size and how many columns can fit on-screen. | |
| 202 * @param width The total width of the boundary to show the images in. | |
| 203 */ | |
| 204 private void calculateGridMetrics(int width) { | |
| 205 int minSize = | |
| 206 mContext.getResources().getDimensionPixelSize(R.dimen.file_picke r_tile_min_size); | |
| 207 mPadding = mContext.getResources().getDimensionPixelSize(R.dimen.file_pi cker_tile_gap); | |
| 208 mColumns = Math.max(1, (width - mPadding) / (minSize + mPadding)); | |
| 209 mImageSize = (width - mPadding * (mColumns + 1)) / (mColumns); | |
| 210 | |
| 211 // Make sure columns and padding are either both even or both odd. | |
| 212 if (((mColumns % 2) == 0) != ((mPadding % 2) == 0)) { | |
| 213 mPadding++; | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 /** | |
| 218 * Prepares bitmaps for loading. | |
| 219 */ | |
| 220 private void prepareBitmaps() { | |
| 221 // TODO(finnur): Use worker thread to fetch bitmaps instead of hard-codi ng. | |
| 222 mPickerBitmaps = new ArrayList<>(); | |
| 223 mPickerBitmaps.add(0, new PickerBitmap("", 0, PickerBitmap.TileTypes.GAL LERY)); | |
| 224 mPickerBitmaps.add(0, new PickerBitmap("", 0, PickerBitmap.TileTypes.CAM ERA)); | |
| 225 mPickerBitmaps.add(new PickerBitmap("foo/bar1.jpg", 1, PickerBitmap.Tile Types.PICTURE)); | |
| 226 mPickerBitmaps.add(new PickerBitmap("foo/bar2.jpg", 2, PickerBitmap.Tile Types.PICTURE)); | |
| 227 mPickerBitmaps.add(new PickerBitmap("foo/bar3.jpg", 3, PickerBitmap.Tile Types.PICTURE)); | |
| 228 mPickerBitmaps.add(new PickerBitmap("foo/bar4.jpg", 4, PickerBitmap.Tile Types.PICTURE)); | |
| 229 mPickerAdapter.notifyDataSetChanged(); | |
| 230 } | |
| 231 | |
| 232 /** | |
| 233 * 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
| |
| 234 */ | |
| 235 private void tryNotifyPhotoSet() { | |
| 236 List<PickerBitmap> selectedFiles = mSelectionDelegate.getSelectedItems() ; | |
| 237 String[] photos = new String[selectedFiles.size()]; | |
| 238 int i = 0; | |
| 239 for (PickerBitmap bitmap : selectedFiles) { | |
| 240 photos[i++] = bitmap.getFilePath(); | |
| 241 } | |
| 242 | |
| 243 mListener.onPickerUserAction(PhotoPickerListener.Action.PHOTOS_SELECTED, photos); | |
| 244 } | |
| 245 } | |
| OLD | NEW |