1 /*
2  * Copyright (C) 2015 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 package com.android.messaging.ui.mediapicker;
17 
18 import android.content.Context;
19 import android.database.Cursor;
20 import android.graphics.PorterDuff;
21 import android.graphics.Rect;
22 import android.util.AttributeSet;
23 import android.view.MotionEvent;
24 import android.view.TouchDelegate;
25 import android.view.View;
26 import android.widget.CheckBox;
27 import android.widget.FrameLayout;
28 import android.widget.ImageView;
29 import android.widget.LinearLayout;
30 import android.widget.RelativeLayout;
31 import android.widget.TextView;
32 
33 import com.android.messaging.R;
34 import com.android.messaging.datamodel.DataModel;
35 import com.android.messaging.datamodel.data.GalleryGridItemData;
36 import com.android.messaging.ui.AsyncImageView;
37 import com.android.messaging.ui.ConversationDrawables;
38 import com.android.messaging.util.ContentType;
39 import com.google.common.annotations.VisibleForTesting;
40 
41 import java.util.concurrent.TimeUnit;
42 
43 /**
44  * Shows an item in the gallery picker grid view. Hosts an FileImageView with a checkbox.
45  */
46 public class GalleryGridItemView extends FrameLayout {
47     /**
48      * Implemented by the owner of this GalleryGridItemView instance to communicate on media
49      * picking and selection events.
50      */
51     public interface HostInterface {
onItemClicked(View view, GalleryGridItemData data, boolean longClick)52         void onItemClicked(View view, GalleryGridItemData data, boolean longClick);
isItemSelected(GalleryGridItemData data)53         boolean isItemSelected(GalleryGridItemData data);
isMultiSelectEnabled()54         boolean isMultiSelectEnabled();
55     }
56 
57     @VisibleForTesting
58     GalleryGridItemData mData;
59     private AsyncImageView mImageView;
60     private CheckBox mCheckBox;
61     private RelativeLayout mAdditionalInfo;
62     private ImageView mIcon;
63     private LinearLayout mFileInfo;
64     private TextView mFileName;
65     private TextView mFileType;
66     private HostInterface mHostInterface;
67     private final OnClickListener mOnClickListener = new OnClickListener() {
68         @Override
69         public void onClick(final View v) {
70             mHostInterface.onItemClicked(GalleryGridItemView.this, mData, false /*longClick*/);
71         }
72     };
73 
GalleryGridItemView(final Context context, final AttributeSet attrs)74     public GalleryGridItemView(final Context context, final AttributeSet attrs) {
75         super(context, attrs);
76         mData = DataModel.get().createGalleryGridItemData();
77     }
78 
79     @Override
onFinishInflate()80     protected void onFinishInflate() {
81         super.onFinishInflate();
82         mImageView = (AsyncImageView) findViewById(R.id.thumbnail);
83         mCheckBox = (CheckBox) findViewById(R.id.checkbox);
84         mCheckBox.setOnClickListener(mOnClickListener);
85         mAdditionalInfo = (RelativeLayout) findViewById(R.id.additional_info);
86         mIcon = (ImageView) findViewById(R.id.icon);
87         mFileInfo = (LinearLayout) findViewById(R.id.file_info);
88         mFileName = (TextView) findViewById(R.id.file_name);
89         mFileType = (TextView) findViewById(R.id.file_type);
90         setOnClickListener(mOnClickListener);
91         final OnLongClickListener longClickListener = new OnLongClickListener() {
92             @Override
93             public boolean onLongClick(final View v) {
94                 mHostInterface.onItemClicked(v, mData, true /* longClick */);
95                 return true;
96             }
97         };
98         setOnLongClickListener(longClickListener);
99         mCheckBox.setOnLongClickListener(longClickListener);
100         addOnLayoutChangeListener(new OnLayoutChangeListener() {
101             @Override
102             public void onLayoutChange(View v, int left, int top, int right, int bottom,
103                     int oldLeft, int oldTop, int oldRight, int oldBottom) {
104                 // Enlarge the clickable region for the checkbox to fill the entire view.
105                 final Rect region = new Rect(0, 0, getWidth(), getHeight());
106                 setTouchDelegate(new TouchDelegate(region, mCheckBox) {
107                     @Override
108                     public boolean onTouchEvent(MotionEvent event) {
109                         switch (event.getAction()) {
110                             case MotionEvent.ACTION_DOWN:
111                                 setPressed(true);
112                                 break;
113                             case MotionEvent.ACTION_UP:
114                             case MotionEvent.ACTION_CANCEL:
115                                 setPressed(false);
116                                 break;
117                         }
118                         return super.onTouchEvent(event);
119                     }
120                 });
121             }
122         });
123     }
124 
125     @Override
onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)126     protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
127         // The grid view auto-fit the columns, so we want to let the height match the width
128         // to make the image square.
129         super.onMeasure(widthMeasureSpec, widthMeasureSpec);
130     }
131 
bind(final Cursor cursor, final HostInterface hostInterface)132     public void bind(final Cursor cursor, final HostInterface hostInterface) {
133         final int desiredSize = getResources()
134                 .getDimensionPixelSize(R.dimen.gallery_image_cell_size);
135         mData.bind(cursor, desiredSize, desiredSize);
136         mHostInterface = hostInterface;
137         updateViewState();
138     }
139 
updateViewState()140     private void updateViewState() {
141         updateImageView();
142         if (mHostInterface.isMultiSelectEnabled() && !mData.isDocumentPickerItem()) {
143             mCheckBox.setVisibility(VISIBLE);
144             mCheckBox.setClickable(true);
145             mCheckBox.setChecked(mHostInterface.isItemSelected(mData));
146         } else {
147             mCheckBox.setVisibility(GONE);
148             mCheckBox.setClickable(false);
149         }
150     }
151 
updateImageView()152     private void updateImageView() {
153         if (mData.isDocumentPickerItem()) {
154             setBackgroundColor(ConversationDrawables.get().getConversationThemeColor());
155             mIcon.setImageResource(R.drawable.ic_photo_library_light);
156             mIcon.clearColorFilter();
157             mImageView.setVisibility(GONE);
158             mIcon.setVisibility(VISIBLE);
159             mFileInfo.setVisibility(GONE);
160             mAdditionalInfo.setVisibility(VISIBLE);
161         } else {
162             final String contentType = mData.getContentType();
163             if (ContentType.isAudioType(contentType)) {
164                 final Context context = getContext();
165                 setBackgroundColor(
166                         getResources().getColor(R.color.gallery_image_default_background));
167                 mIcon.setImageDrawable(
168                         context.getContentResolver()
169                                 .getTypeInfo(contentType)
170                                 .getIcon()
171                                 .loadDrawable(context));
172                 mIcon.setColorFilter(
173                         ConversationDrawables.get().getConversationThemeColor(),
174                         PorterDuff.Mode.SRC_IN);
175                 mFileName.setText(mData.getFileName());
176                 String[] type = contentType.split("/");
177                 mFileType.setText(type[1].toUpperCase() + " " + type[0]);
178                 mImageView.setVisibility(GONE);
179                 mIcon.setVisibility(VISIBLE);
180                 mFileInfo.setVisibility(VISIBLE);
181                 mAdditionalInfo.setVisibility(VISIBLE);
182             } else { // For image and video types
183                 mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
184                 setBackgroundColor(
185                         getResources().getColor(R.color.gallery_image_default_background));
186                 mImageView.setImageResourceId(mData.getImageRequestDescriptor());
187                 mImageView.setVisibility(VISIBLE);
188                 if (ContentType.isVideoType(mData.getContentType())) {
189                     mIcon.setImageResource(R.drawable.ic_video_play_light);
190                     mIcon.clearColorFilter();
191                     mIcon.setVisibility(VISIBLE);
192                 } else {
193                     mIcon.setVisibility(GONE);
194                 }
195                 mFileInfo.setVisibility(GONE);
196                 mAdditionalInfo.setVisibility(VISIBLE);
197                 final long dateSeconds = mData.getDateSeconds();
198                 final boolean isValidDate = (dateSeconds > 0);
199                 final int templateId = isValidDate ?
200                         R.string.mediapicker_gallery_image_item_description :
201                         R.string.mediapicker_gallery_image_item_description_no_date;
202                 String contentDescription = String.format(getResources().getString(templateId),
203                         dateSeconds * TimeUnit.SECONDS.toMillis(1));
204                 mImageView.setContentDescription(contentDescription);
205             }
206         }
207     }
208 }
209