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