• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.providers.media.photopicker.ui;
18 
19 import static android.view.View.GONE;
20 import static android.view.View.VISIBLE;
21 
22 import android.content.Context;
23 import android.graphics.Color;
24 import android.graphics.drawable.GradientDrawable;
25 import android.graphics.drawable.LayerDrawable;
26 import android.graphics.drawable.StateListDrawable;
27 import android.graphics.drawable.VectorDrawable;
28 import android.view.View;
29 import android.widget.ImageView;
30 import android.widget.TextView;
31 
32 import androidx.annotation.NonNull;
33 import androidx.lifecycle.LifecycleOwner;
34 import androidx.lifecycle.LiveData;
35 import androidx.recyclerview.widget.RecyclerView;
36 
37 import com.android.providers.media.R;
38 import com.android.providers.media.photopicker.data.model.Item;
39 import com.android.providers.media.photopicker.util.AccentColorResources;
40 import com.android.providers.media.photopicker.viewmodel.PickerViewModel;
41 
42 /**
43  * {@link RecyclerView.ViewHolder} of a {@link View} representing a (media) {@link Item} (a photo or
44  * a video).
45  */
46 class MediaItemGridViewHolder extends RecyclerView.ViewHolder {
47     private final LifecycleOwner mLifecycleOwner;
48     private final ImageLoader mImageLoader;
49     private final ImageView mIconThumb;
50     private final ImageView mIconGif;
51     private final ImageView mIconMotionPhoto;
52     private final View mVideoBadgeContainer;
53     private final TextView mVideoDuration;
54     private final View mOverlayGradient;
55     private final boolean mCanSelectMultiple;
56     private final boolean mShowOrderedSelectionLabel;
57     private final TextView mSelectedOrderText;
58     private LiveData<Integer> mSelectionOrder;
59     private final ImageView mCheckIcon;
60 
61     private final View.OnHoverListener mOnMediaItemHoverListener;
62     private final PhotosTabAdapter.OnMediaItemClickListener mOnMediaItemClickListener;
63     private final PickerViewModel mPickerViewModel;
64 
MediaItemGridViewHolder( @onNull LifecycleOwner lifecycleOwner, @NonNull View itemView, @NonNull ImageLoader imageLoader, @NonNull PhotosTabAdapter.OnMediaItemClickListener onMediaItemClickListener, View.OnHoverListener onMediaItemHoverListener, PickerViewModel pickerViewModel, boolean canSelectMultiple, boolean isOrderedSelection)65     MediaItemGridViewHolder(
66             @NonNull LifecycleOwner lifecycleOwner,
67             @NonNull View itemView,
68             @NonNull ImageLoader imageLoader,
69             @NonNull PhotosTabAdapter.OnMediaItemClickListener onMediaItemClickListener,
70             View.OnHoverListener onMediaItemHoverListener,
71             PickerViewModel pickerViewModel,
72             boolean canSelectMultiple,
73             boolean isOrderedSelection) {
74         super(itemView);
75         mLifecycleOwner = lifecycleOwner;
76         mIconThumb = itemView.findViewById(R.id.icon_thumbnail);
77         mIconGif = itemView.findViewById(R.id.icon_gif);
78         mIconMotionPhoto = itemView.findViewById(R.id.icon_motion_photo);
79         mVideoBadgeContainer = itemView.findViewById(R.id.video_container);
80         mVideoDuration = mVideoBadgeContainer.findViewById(R.id.video_duration);
81         mOverlayGradient = itemView.findViewById(R.id.overlay_gradient);
82         mImageLoader = imageLoader;
83         mOnMediaItemClickListener = onMediaItemClickListener;
84         mCanSelectMultiple = canSelectMultiple;
85         mShowOrderedSelectionLabel = isOrderedSelection;
86         mOnMediaItemHoverListener = onMediaItemHoverListener;
87         mPickerViewModel = pickerViewModel;
88         mSelectedOrderText = itemView.findViewById(R.id.selected_order);
89         mCheckIcon = itemView.findViewById(R.id.icon_check);
90         mCheckIcon.setVisibility(
91                 (mCanSelectMultiple && !mShowOrderedSelectionLabel) ? VISIBLE : GONE);
92         mSelectedOrderText.setVisibility(
93                 (mCanSelectMultiple && mShowOrderedSelectionLabel) ? VISIBLE : GONE);
94 
95         if (mPickerViewModel.getPickerAccentColorParameters().isCustomPickerColorSet()) {
96             setCustomSelectedMediaIconColors(
97                     mPickerViewModel.getPickerAccentColorParameters().getPickerAccentColor(),
98                     mPickerViewModel.getPickerAccentColorParameters().getThemeBasedColor(
99                             AccentColorResources.SURFACE_CONTAINER_COLOR_LIGHT,
100                             AccentColorResources.SURFACE_CONTAINER_COLOR_DARK
101                     ));
102         }
103     }
104 
bind(@onNull Item item, boolean isSelected)105     public void bind(@NonNull Item item, boolean isSelected) {
106         int position = getAbsoluteAdapterPosition();
107         itemView.setOnClickListener(v -> mOnMediaItemClickListener.onItemClick(v, position, this));
108         itemView.setOnLongClickListener(v ->
109                 mOnMediaItemClickListener.onItemLongClick(v, position));
110         itemView.setOnHoverListener(mOnMediaItemHoverListener);
111 
112         mImageLoader.loadPhotoThumbnail(item, mIconThumb);
113 
114         mIconGif.setVisibility(item.isGifOrAnimatedWebp() ? VISIBLE : GONE);
115         mIconMotionPhoto.setVisibility(item.isMotionPhoto() ? VISIBLE : GONE);
116 
117         if (item.isVideo()) {
118             mVideoBadgeContainer.setVisibility(VISIBLE);
119             mVideoDuration.setText(item.getDurationText());
120         } else {
121             mVideoBadgeContainer.setVisibility(GONE);
122         }
123 
124         if (showShowOverlayGradient(item)) {
125             mOverlayGradient.setVisibility(VISIBLE);
126         } else {
127             mOverlayGradient.setVisibility(GONE);
128         }
129 
130         final Context context = getContext();
131         itemView.setContentDescription(item.getContentDescription(context));
132 
133         if (mCanSelectMultiple) {
134             itemView.setSelected(isSelected);
135             mSelectedOrderText.setText("");
136             // There is an issue b/223695510 about not selected in Accessibility mode. It only
137             // says selected state, but it doesn't say not selected state. Add the not selected
138             // only to avoid that it says selected twice.
139             itemView.setStateDescription(
140                     isSelected ? null : context.getString(R.string.not_selected));
141         }
142     }
143 
144     /** Sets the LiveData selection order for the current grid item view. */
setSelectionOrder(LiveData<Integer> selectionOrder)145     public void setSelectionOrder(LiveData<Integer> selectionOrder) {
146         if (selectionOrder == null) {
147             mSelectedOrderText.setText("");
148             if (mSelectionOrder != null) {
149                 mSelectionOrder.removeObservers(mLifecycleOwner);
150             }
151         } else {
152             mSelectedOrderText.setText(selectionOrder.getValue().toString());
153             selectionOrder.observe(
154                     mLifecycleOwner,
155                     val -> {
156                         mSelectedOrderText.setText(val.toString());
157                     });
158         }
159         mSelectionOrder = selectionOrder;
160     }
161 
setCustomSelectedMediaIconColors( int checkIconColor, int uncheckedIconColor)162     private void setCustomSelectedMediaIconColors(
163             int checkIconColor, int uncheckedIconColor) {
164         // Selected Media icon colors for unordered selection
165         StateListDrawable drawableCheckIcon = (StateListDrawable) mCheckIcon.getDrawable();
166         // Set color of the selected media icon
167         LayerDrawable checkIcon = (LayerDrawable) drawableCheckIcon.getStateDrawable(0);
168         VectorDrawable selectedMediaBaseCircle = (VectorDrawable) checkIcon.findDrawableByLayerId(
169                 R.id.selected_radio_button_selected_mark);
170         selectedMediaBaseCircle.setTint(checkIconColor);
171         // Set color of the unselected media icon
172         VectorDrawable uncheckedIcon = (VectorDrawable) drawableCheckIcon.getStateDrawable(1);
173         uncheckedIcon.setTint(uncheckedIconColor);
174         mCheckIcon.setImageDrawable(drawableCheckIcon);
175 
176         // Selected Media icon for ordered selection
177         StateListDrawable drawableOrderedSelection =
178                 (StateListDrawable) mSelectedOrderText.getBackground();
179         // Set color of selected media icon
180         LayerDrawable orderedIcon = (LayerDrawable) drawableOrderedSelection.getStateDrawable(0);
181         GradientDrawable orderedIconBaseCircle =
182                 (GradientDrawable) orderedIcon.findDrawableByLayerId(
183                         R.id.ordered_selection_selected_icon);
184         orderedIconBaseCircle.setColor(checkIconColor);
185         // Set color of the unselected media icon
186         VectorDrawable orderedSelectionSelectedItem =
187                 (VectorDrawable) drawableOrderedSelection.getStateDrawable(1);
188         orderedSelectionSelectedItem.setTint(uncheckedIconColor);
189         mSelectedOrderText.setBackground(drawableOrderedSelection);
190         mSelectedOrderText.setTextColor(Color.parseColor(
191                 mPickerViewModel.getPickerAccentColorParameters().isAccentColorBright()
192                         ? AccentColorResources.DARK_TEXT_COLOR
193                         : AccentColorResources.LIGHT_TEXT_COLOR));
194     }
195 
196     @NonNull
getContext()197     private Context getContext() {
198         return itemView.getContext();
199     }
200 
201     /**
202      * Get the {@link ImageView} for the thumbnail image representing this MediaItem.
203      * @return the image view for the thumbnail.
204      */
getThumbnailImageView()205     public ImageView getThumbnailImageView() {
206         return mIconThumb;
207     }
208 
showShowOverlayGradient(@onNull Item item)209     private boolean showShowOverlayGradient(@NonNull Item item) {
210         return mCanSelectMultiple
211                 || item.isGifOrAnimatedWebp()
212                 || item.isVideo()
213                 || item.isMotionPhoto();
214     }
215 
216     /** Release any non-reusable resources, as the view is being recycled. */
release()217     public void release() {
218         if (mSelectionOrder != null) {
219             mSelectionOrder.removeObservers(mLifecycleOwner);
220             mSelectionOrder = null;
221         }
222     }
223 }
224