package net.hockeyapp.android.views; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import net.hockeyapp.android.Constants; import net.hockeyapp.android.R; import net.hockeyapp.android.objects.FeedbackAttachment; import net.hockeyapp.android.utils.ImageUtils; import java.io.File; /** * <h3>Description</h3> * * The view for an attachment. */ @SuppressLint("ViewConstructor") public class AttachmentView extends FrameLayout { private final static int IMAGES_PER_ROW_PORTRAIT = 3; private final static int IMAGES_PER_ROW_LANDSCAPE = 2; private final Context mContext; private final ViewGroup mParent; private final FeedbackAttachment mAttachment; private final Uri mAttachmentUri; private final String mFilename; private ImageView mImageView; private TextView mTextView; private int mWidthPortrait; private int mMaxHeightPortrait; private int mWidthLandscape; private int mMaxHeightLandscape; private int mGap; private int mOrientation; public AttachmentView(Context context, ViewGroup parent, Uri attachmentUri, boolean removable) { super(context); this.mContext = context; this.mParent = parent; this.mAttachment = null; this.mAttachmentUri = attachmentUri; this.mFilename = attachmentUri.getLastPathSegment(); calculateDimensions(20); initializeView(context, removable); mTextView.setText(mFilename); mTextView.setContentDescription(mFilename); new AsyncTask<Void, Void, Bitmap>() { @Override protected Bitmap doInBackground(Void... args) { return loadImageThumbnail(); } @Override protected void onPostExecute(Bitmap bitmap) { if (bitmap != null) { configureViewForThumbnail(bitmap, false); } else { configureViewForPlaceholder(false); } } }.execute(); } public AttachmentView(Context context, ViewGroup parent, FeedbackAttachment attachment, boolean removable) { super(context); this.mContext = context; this.mParent = parent; this.mAttachment = attachment; this.mAttachmentUri = Uri.fromFile(new File(Constants.getHockeyAppStorageDir(), attachment .getCacheId())); this.mFilename = attachment.getFilename(); calculateDimensions(30); initializeView(context, removable); mOrientation = ImageUtils.ORIENTATION_PORTRAIT; mTextView.setText(R.string.hockeyapp_feedback_attachment_loading); mTextView.setContentDescription(mTextView.getText()); configureViewForPlaceholder(false); } public FeedbackAttachment getAttachment() { return mAttachment; } public Uri getAttachmentUri() { return mAttachmentUri; } public int getWidthPortrait() { return mWidthPortrait; } public int getMaxHeightPortrait() { return mMaxHeightPortrait; } public int getWidthLandscape() { return mWidthLandscape; } public int getMaxHeightLandscape() { return mMaxHeightLandscape; } public int getGap() { return mGap; } public int getEffectiveMaxHeight() { return mOrientation == ImageUtils.ORIENTATION_LANDSCAPE ? mMaxHeightLandscape : mMaxHeightPortrait; } public void remove() { mParent.removeView(this); } public void setImage(Bitmap bitmap, int orientation) { this.mTextView.setText(mFilename); this.mOrientation = orientation; if (bitmap == null) { configureViewForPlaceholder(true); } else { configureViewForThumbnail(bitmap, true); } } public void signalImageLoadingError() { mTextView.setText(R.string.hockeyapp_feedback_attachment_error); } private void calculateDimensions(int marginDip) { DisplayMetrics metrics = getResources().getDisplayMetrics(); this.mGap = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10.0f, metrics)); int layoutMargin = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, marginDip, metrics)); int displayWidth = metrics.widthPixels; int parentWidthPortrait = displayWidth - (2 * layoutMargin) - ((IMAGES_PER_ROW_PORTRAIT - 1) * this.mGap); // (IMAGES_PER_ROW_LANDSCAPE - 1) * this.gap == 1, so just using this.gap int parentWidthLandscape = displayWidth - (2 * layoutMargin) - this.mGap; this.mWidthPortrait = parentWidthPortrait / IMAGES_PER_ROW_PORTRAIT; this.mWidthLandscape = parentWidthLandscape / IMAGES_PER_ROW_LANDSCAPE; this.mMaxHeightPortrait = mWidthPortrait * 2; //noinspection SuspiciousNameCombination this.mMaxHeightLandscape = mWidthLandscape; } @SuppressWarnings("deprecation") private void initializeView(Context context, boolean removable) { setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.BOTTOM)); setPadding(0, mGap, 0, 0); // ImageView mImageView = new ImageView(context); // LinearLayout LinearLayout bottomView = new LinearLayout(context); bottomView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams .WRAP_CONTENT, Gravity.BOTTOM)); bottomView.setGravity(Gravity.START); bottomView.setOrientation(LinearLayout.VERTICAL); bottomView.setBackgroundColor(Color.parseColor("#80262626")); // TextView mTextView = new TextView(context); mTextView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams .WRAP_CONTENT, Gravity.CENTER)); mTextView.setGravity(Gravity.CENTER); mTextView.setTextColor(context.getResources().getColor(R.color.hockeyapp_text_white)); mTextView.setSingleLine(); mTextView.setEllipsize(TextUtils.TruncateAt.MIDDLE); // Remove Button if (removable) { ImageButton imageButton = new ImageButton(context); imageButton.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams .WRAP_CONTENT, Gravity.BOTTOM)); imageButton.setAdjustViewBounds(true); imageButton.setImageDrawable(getSystemIcon("ic_menu_delete")); imageButton.setBackgroundResource(0); imageButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { AttachmentView.this.remove(); } }); bottomView.addView(imageButton); } bottomView.addView(mTextView); addView(mImageView); addView(bottomView); } private void configureViewForThumbnail(Bitmap bitmap, final boolean openOnClick) { int width = mOrientation == ImageUtils.ORIENTATION_LANDSCAPE ? mWidthLandscape : mWidthPortrait; int height = mOrientation == ImageUtils.ORIENTATION_LANDSCAPE ? mMaxHeightLandscape : mMaxHeightPortrait; mTextView.setMaxWidth(width); mTextView.setMinWidth(width); mImageView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams .WRAP_CONTENT)); mImageView.setAdjustViewBounds(true); mImageView.setMinimumWidth(width); mImageView.setMaxWidth(width); mImageView.setMaxHeight(height); mImageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); mImageView.setImageBitmap(bitmap); mImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (!openOnClick) { return; } Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(mAttachmentUri, "image/*"); mContext.startActivity(intent); } }); } private void configureViewForPlaceholder(final boolean openOnClick) { mTextView.setMaxWidth(mWidthPortrait); mTextView.setMinWidth(mWidthPortrait); mImageView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams .WRAP_CONTENT)); mImageView.setAdjustViewBounds(false); mImageView.setBackgroundColor(Color.parseColor("#eeeeee")); mImageView.setMinimumHeight((int) (mWidthPortrait * 1.2f)); mImageView.setMinimumWidth(mWidthPortrait); mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); mImageView.setImageDrawable(getSystemIcon("ic_menu_attachment")); mImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (!openOnClick) { return; } Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(mAttachmentUri, "*/*"); mContext.startActivity(intent); } }); } private Bitmap loadImageThumbnail() { try { mOrientation = ImageUtils.determineOrientation(mContext, mAttachmentUri); int width = mOrientation == ImageUtils.ORIENTATION_LANDSCAPE ? mWidthLandscape : mWidthPortrait; int height = mOrientation == ImageUtils.ORIENTATION_LANDSCAPE ? mMaxHeightLandscape : mMaxHeightPortrait; return ImageUtils.decodeSampledBitmap(mContext, mAttachmentUri, width, height); } catch (Throwable t) { return null; } } @SuppressWarnings("deprecation") private Drawable getSystemIcon(String name) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return getResources().getDrawable(getResources().getIdentifier(name, "drawable", "android") , mContext.getTheme()); } else { return getResources().getDrawable(getResources().getIdentifier(name, "drawable", "android")); } } }