Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(186)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapView.java

Issue 2758313002: Implement the new Photo picker, part two. (Closed)
Patch Set: Fix scrim color Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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.content.Context;
8 import android.content.res.Resources;
9 import android.graphics.Bitmap;
10 import android.graphics.BitmapFactory;
11 import android.graphics.Color;
12 import android.graphics.PorterDuff;
13 import android.graphics.drawable.BitmapDrawable;
14 import android.graphics.drawable.Drawable;
15 import android.support.annotation.Nullable;
16 import android.support.v4.content.ContextCompat;
17 import android.util.AttributeSet;
18 import android.util.DisplayMetrics;
19 import android.view.View;
20 import android.view.ViewGroup;
21 import android.view.animation.Animation;
22 import android.view.animation.Transformation;
23 import android.widget.ImageView;
24 import android.widget.TextView;
25
26 import org.chromium.base.ApiCompatibilityUtils;
27 import org.chromium.chrome.R;
28 import org.chromium.chrome.browser.widget.selection.SelectableItemView;
29 import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
30
31 import java.util.List;
32
33 /**
34 * A container class for a view showing a photo in the photo picker.
35 */
36 public class PickerBitmapView extends SelectableItemView<PickerBitmap> {
37 // Our context.
38 private Context mContext;
39
40 // Our parent category.
41 private PickerCategoryView mCategoryView;
42
43 // Our selection delegate.
44 private SelectionDelegate<PickerBitmap> mSelectionDelegate;
45
46 // The request details (meta-data) for the bitmap shown.
47 private PickerBitmap mRequest;
48
49 // The image view containing the bitmap.
50 private ImageView mIconView;
51
52 // The little shader in the top left corner (provides backdrop for selection ring for
53 // unfavorable image backgrounds).
54 private View mScrim;
55
56 // The view behind the image, representing the selection border.
57 private View mBorderView;
58
59 // The control that signifies the image has been selected.
60 private ImageView mSelectedView;
61
62 // The control that signifies the image has not been selected.
63 private ImageView mUnselectedView;
64
65 // The camera/gallery special tile (with icon as drawable).
66 private TextView mSpecialTile;
67
68 // Whether the image has been loaded already.
69 private boolean mImageLoaded;
70
71 // The amount to use for the border.
72 private int mBorder;
73
74 /**
75 * A resize animation class for the images (shrinks the image on selection).
76 */
77 private static class ResizeWidthAnimation extends Animation {
78 // The view to animate size changes for.
79 private View mView;
80
81 // The starting size of the view.
82 private int mStartingSize;
83
84 // The target size we want to achieve.
85 private int mTargetSize;
86
87 /**
88 * The ResizeWidthAnimation constructor.
89 * @param view The view to animate size changes for.
90 * @param size The target size we want to achieve.
91 */
92 public ResizeWidthAnimation(View view, int size) {
93 mView = view;
94 mStartingSize = view.getWidth();
95 mTargetSize = size;
96 }
97
98 @Override
99 protected void applyTransformation(float interpolatedTime, Transformatio n transformation) {
100 int newSize = mStartingSize + (int) ((mTargetSize - mStartingSize) * interpolatedTime);
101 int padding = (Math.max(mStartingSize, mTargetSize) - newSize) / 2;
102
103 mView.getLayoutParams().height = newSize;
104 mView.getLayoutParams().width = newSize;
105 // Create a border around the image.
106 if (mView instanceof ImageView) {
107 addPaddingToParent(mView, padding);
108 }
109 }
110
111 @Override
112 public boolean willChangeBounds() {
113 return true;
114 }
115 }
116
117 /**
118 * Constructor for inflating from XML.
119 */
120 public PickerBitmapView(Context context, AttributeSet attrs) {
121 super(context, attrs);
122 mContext = context;
123 }
124
125 @Override
126 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
127 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
128
129 if (mCategoryView == null) return; // Android Studio calls onMeasure to draw the widget.
Theresa 2017/03/28 20:40:28 Why does it matter if Android Studio calls onMeasu
Finnur 2017/03/31 14:26:50 Excellent. I worried it would not make sense witho
130 int width = mCategoryView.getImageSize();
131 int height = mCategoryView.getImageSize();
132 setMeasuredDimension(width, height);
133 }
134
135 @Override
136 protected void onFinishInflate() {
137 super.onFinishInflate();
138 mIconView = (ImageView) findViewById(R.id.bitmap_view);
139 mScrim = findViewById(R.id.scrim);
140 mBorderView = findViewById(R.id.border);
141 mSelectedView = (ImageView) findViewById(R.id.selected);
142 mUnselectedView = (ImageView) findViewById(R.id.unselected);
143 mSpecialTile = (TextView) findViewById(R.id.special_tile);
144 }
145
146 @Override
147 public void onClick() {
Theresa 2017/03/28 20:40:28 We had to introduce some special handling for book
Finnur 2017/03/31 14:26:50 Acknowledged.
Theresa 2017/03/31 18:05:55 I was thinking about this incorrectly -- this actu
Finnur 2017/04/03 17:30:29 Acknowledged.
148 if (mRequest.type() == PickerBitmap.TileTypes.GALLERY) {
149 mCategoryView.showGallery();
150 return;
151 } else if (mRequest.type() == PickerBitmap.TileTypes.CAMERA) {
152 mCategoryView.showCamera();
153 return;
154 }
155
156 mSelectionDelegate.toggleSelectionForItem(mRequest);
157 setChecked(!super.isChecked());
158 }
159
160 @Override
161 public void setChecked(boolean checked) {
162 if (mRequest.type() != PickerBitmap.TileTypes.PICTURE) {
163 return;
164 }
165
166 super.setChecked(checked);
167 updateSelectionState();
168 }
169
170 @Override
171 public void onSelectionStateChange(List<PickerBitmap> selectedItems) {
172 boolean selected = selectedItems.contains(mRequest);
173
174 if (mRequest.type() != PickerBitmap.TileTypes.PICTURE) {
175 if (selected) mSelectionDelegate.toggleSelectionForItem(mRequest);
176 updateSelectionState();
177 return;
178 }
179
180 boolean checked = super.isChecked();
181
182 if (!mCategoryView.isMultiSelect() && !selected && checked) {
183 super.toggle();
184 }
185
186 updateSelectionState();
187
188 if (!mImageLoaded || selected == checked) {
189 return;
190 }
191
192 int size = selected && !checked ? mCategoryView.getImageSize() - 2 * mBo rder
193 : mCategoryView.getImageSize();
194 if (size != mIconView.getWidth()) {
195 ResizeWidthAnimation animation = new ResizeWidthAnimation(mIconView, size);
196 animation.setDuration(100);
Theresa 2017/03/28 20:40:28 nit: define this as a constant somewhere In the
Finnur 2017/03/31 14:26:50 Done.
197 // TODO: Add MD interpolator
198 // animation.setInterpolator((mContext, R.interpolator.fast_out_line ar_in);
199 mIconView.startAnimation(animation);
200 }
201 }
202
203 /**
204 * Pre-initializes the PickerBitmapView.
205 * @param categoryView The category view showing the images.
206 */
207 public void preInitialize(PickerCategoryView categoryView) {
208 mCategoryView = categoryView;
209 mSelectionDelegate = mCategoryView.getSelectionDelegate();
210 super.setSelectionDelegate(mSelectionDelegate);
211
212 mSelectedView.setImageBitmap(mCategoryView.getSelectionBitmap(true));
213 mUnselectedView.setImageBitmap(mCategoryView.getSelectionBitmap(false));
214
215 mBorder = (int) getResources().getDimension(R.dimen.file_picker_selected _padding);
216 }
217
218 /**
219 * Completes the initialization of the PickerBitmapView. Must be called befo re the image can
220 * respond to click events.
221 * @param request The request represented by this PickerBitmapView.
222 * @param thumbnail The Bitmap to use for the thumbnail (or null).
223 * @param placeholder Whether the image given is a placeholder or the actual image.
224 */
225 public void initialize(PickerBitmap request, @Nullable Bitmap thumbnail, boo lean placeholder) {
226 resetTile();
227
228 mRequest = request;
229 setItem(request);
230 setThumbnailBitmap(thumbnail);
231 mImageLoaded = !placeholder;
232
233 updateSelectionState();
234
235 setOnClickListener(this);
236 }
237
238 /**
239 * Initialization for the special tiles (camera/gallery icon).
240 */
241 public void initializeSpecialTile() {
242 int size = mCategoryView.getImageSize();
243 Bitmap tile = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
244 tile.eraseColor(Color.argb(0, 0, 0, 0));
245
246 int iconBitmapId, labelStringId;
247 if (mRequest.type() == PickerBitmap.TileTypes.CAMERA) {
248 iconBitmapId = R.drawable.ic_photo_camera;
249 labelStringId = R.string.file_picker_camera;
250 } else {
251 iconBitmapId = R.drawable.ic_collections_black_24dp;
252 labelStringId = R.string.file_picker_browse;
253 }
254
255 Resources resources = mContext.getResources();
256 mSpecialTile.setText(labelStringId);
257 Bitmap icon = BitmapFactory.decodeResource(resources, iconBitmapId);
258 DisplayMetrics metrics = resources.getDisplayMetrics();
259 float pixels = 48 * ((float) metrics.densityDpi / DisplayMetrics.DENSITY _DEFAULT);
Theresa 2017/03/28 20:40:28 Define a dimension in dimens.xml rather than progr
Finnur 2017/03/31 14:26:50 Done.
260 BitmapDrawable drawable = new BitmapDrawable(
261 resources, Bitmap.createScaledBitmap(icon, (int) pixels, (int) p ixels, true));
Theresa 2017/03/28 20:40:28 Android will automatically scale for you if the Im
Finnur 2017/03/31 14:26:50 It is not obvious to me how to interpret this comm
262 ApiCompatibilityUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
263 mSpecialTile, null, drawable, null, null);
264
265 initialize(mRequest, tile, false);
266
267 mSpecialTile.setVisibility(View.VISIBLE);
268 }
269
270 /**
271 * Sets a thumbnail bitmap for the current view and ensures the selection bo rder and scrim is
272 * showing, if the image has already been selected.
273 * @param thumbnail The Bitmap to use for the icon ImageView.
274 * @return true if no image was loaded before (e.g. not even a low-res image ).
Theresa 2017/03/28 20:40:28 nit:s/true/True
Finnur 2017/03/31 14:26:50 Done.
275 */
276 public boolean setThumbnailBitmap(Bitmap thumbnail) {
277 mIconView.setImageBitmap(thumbnail);
278
279 // If the tile has been selected before the bitmap has loaded, make sure it shows up with
280 // a selection border and scrim on load.
281 if (super.isChecked()) {
282 mIconView.getLayoutParams().height = mCategoryView.getImageSize() - 2 * mBorder;
283 mIconView.getLayoutParams().width = mCategoryView.getImageSize() - 2 * mBorder;
Theresa 2017/03/28 20:40:28 nit: extract this calculation into a helper method
Finnur 2017/03/31 14:26:50 Done.
284 addPaddingToParent(mIconView, mBorder);
285 mScrim.setVisibility(View.VISIBLE);
286 }
287
288 boolean noImageWasLoaded = !mImageLoaded;
289 mImageLoaded = true;
290 updateSelectionState();
291
292 return noImageWasLoaded;
293 }
294
295 /**
296 * Initiates fading in of the thumbnail. Note, this should not be called if a grainy version of
297 * the thumbnail was loaded from cache. Otherwise a flash will appear.
298 */
299 public void fadeInThumbnail() {
300 mIconView.setAlpha(0.0f);
301 mIconView.animate().alpha(1.0f).setDuration(200).start();
Theresa 2017/03/28 20:40:28 nit: define 200 as a constant somewhere.
Finnur 2017/03/31 14:26:50 Done.
302 }
303
304 /**
305 * Resets the view to its starting state, which is necessary when the view i s about to be
306 * re-used.
307 */
308 private void resetTile() {
309 mUnselectedView.setVisibility(View.GONE);
310 mSelectedView.setVisibility(View.GONE);
311 mScrim.setVisibility(View.GONE);
312 mSpecialTile.setVisibility(View.GONE);
313 }
314
315 /**
316 * Adds padding to the parent of the |view|.
317 * @param view The child view of the view to receive the padding.
318 * @param padding The amount of padding to use (in pixels).
319 */
320 private static void addPaddingToParent(View view, int padding) {
321 ViewGroup layout = (ViewGroup) view.getParent();
322 layout.setPadding(padding, padding, padding, padding);
323 layout.requestLayout();
324 }
325
326 /**
327 * Updates the selection controls for this view.
328 */
329 private void updateSelectionState() {
330 boolean special = mRequest.type() != PickerBitmap.TileTypes.PICTURE;
331 boolean checked = super.isChecked();
332 boolean anySelection =
333 mSelectionDelegate != null && mSelectionDelegate.isSelectionEnab led();
334 boolean multiSelect = mCategoryView.isMultiSelect();
335 int bgColorId, fgColorId;
336 if (!special) {
337 bgColorId = R.color.file_picker_tile_bg_color;
338 fgColorId = R.color.file_picker_special_tile_color;
339 } else if (!anySelection || !multiSelect) {
340 bgColorId = R.color.file_picker_special_tile_bg_color;
341 fgColorId = R.color.file_picker_special_tile_color;
342 } else {
343 bgColorId = R.color.file_picker_special_tile_disabled_bg_color;
344 fgColorId = R.color.file_picker_special_tile_disabled_color;
345 }
346
347 mBorderView.setBackgroundColor(ContextCompat.getColor(mContext, bgColorI d));
348 mSpecialTile.setTextColor(ContextCompat.getColor(mContext, fgColorId));
349 Drawable[] drawables = mSpecialTile.getCompoundDrawables();
350 // The textview only has a top compound drawable (2nd element).
351 if (drawables[1] != null) {
352 int color = ContextCompat.getColor(mContext, fgColorId);
353 drawables[1].setColorFilter(color, PorterDuff.Mode.SRC_IN);
354 }
355
356 // The visibility of the unselected image is a little more complex becau se we don't want
357 // to show it when nothing is selected and also not on a blank canvas.
358 mSelectedView.setVisibility(!special && checked ? View.VISIBLE : View.GO NE);
359 mUnselectedView.setVisibility(
360 !special && !checked && anySelection ? View.VISIBLE : View.GONE) ;
361 mScrim.setVisibility(!special && !checked && anySelection ? View.VISIBLE : View.GONE);
362 }
363 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698