package com.daifan.activity.adapter; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.provider.MediaStore; import android.support.v4.content.CursorLoader; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.ImageView; import com.android.volley.toolbox.ImageLoader; import com.android.volley.toolbox.NetworkImageView; import com.daifan.R; import com.daifan.Singleton; import com.daifan.activity.BaseActivity; import com.daifan.activity.ImagesActivity; import java.io.*; import java.util.ArrayList; import java.util.List; public class ThumbnailsLoader extends BaseAdapter { public static final int THUMBNAIL_W_DP = 100; public static final int THUMBNAIL_H_DP = 100; private final int thumbnailW; private final int thumbnailH; private boolean isSupportNew() { return newImgCallback != null; } public String[] getNewImages() { return newImagePaths.toArray(new String[0]); } static public interface NewImageCallback { public void postNewImage(Bitmap previewBm, ImageView imageView); public View.OnClickListener newBtnClickListener(); void postNotANewImage(ImageView imageView); } private Context context; private NewImageCallback newImgCallback; private ArrayList<Bitmap> bitMaps = new ArrayList<Bitmap>(); private ArrayList<String> imageUrls = new ArrayList<String>(); //All thumbnails has a correspond elements private ArrayList<String> fullImages = new ArrayList<String>(); private ArrayList<String> newImagePaths = new ArrayList<String>(); public ThumbnailsLoader(Context context, NewImageCallback newImageCallback) { this.context = context; this.newImgCallback = newImageCallback; this.thumbnailH = dpToPx(THUMBNAIL_H_DP, context); this.thumbnailW = dpToPx(THUMBNAIL_W_DP, context); } public Object getItem(int position) { return position; } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView = null; if (convertView != null) { imageView = (ImageView) convertView; } return setImage(imageView, position); } public void add(Bitmap bm) { this.bitMaps.add(bm); this.notifyDataSetChanged(); } public void addImageUrls(List<String> urls) { this.imageUrls.addAll(urls); this.notifyDataSetChanged(); } public void addNewImage(Uri uri) throws IOException { String path = getRealPathFromURI(uri); Log.d(Singleton.DAIFAN_TAG, "pic url = " + path + " from uri:" + uri); if (path != null) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, options); if (options.outWidth > 640 || options.outHeight > 960) { Log.d(Singleton.DAIFAN_TAG, "try rewrite the image for too big:" + path); options.inSampleSize = calculateInSampleSize(options, 640, 960); options.inJustDecodeBounds = false; Bitmap bm = BitmapFactory.decodeFile(path, options); Log.d(Singleton.DAIFAN_TAG, "image after scaled down: width=" + bm.getWidth() + ", heigh=" + bm.getHeight() + ", size:" + bm.getByteCount()); OutputStream os = null; try { File tmp = Singleton.getFileCache().createTmpImg(); os = new FileOutputStream(tmp); if(bm.compress(Bitmap.CompressFormat.JPEG, 100, os)){ this.newImagePaths.add(tmp.getAbsolutePath()); this.insertPhoto(path); Log.d(Singleton.DAIFAN_TAG, "size after compress:" + tmp.length() +", loc=" + tmp.getAbsolutePath()); } else { throw new IOException(("compress to tmp file failed:" + path)); } } finally { if (os != null) os.close(); } } else { this.newImagePaths.add(path); this.insertPhoto(path); } } } void insertPhoto(String path) { if (path == null) { Log.d(Singleton.DAIFAN_TAG, "insert photo failed for the path is null"); return; } Bitmap bm = decodeSampledBitmapFromUri(path, this.thumbnailW, this.thumbnailH); this.add(bm); } public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight) { Bitmap bm = null; // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; bm = BitmapFactory.decodeFile(path, options); return bm; } public int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; //make sure image size larger than Preview bounds if (height > reqHeight || width > reqWidth) { if (width > height) { inSampleSize = Math.round((float) width / (float) reqWidth); } else { inSampleSize = Math.round((float) height / (float) reqHeight); } } Log.d(Singleton.DAIFAN_TAG, "calculateInSampleSize: orgW=" + width + ", orgH=" + height + ", newW=" + reqWidth + ", newH=" + reqHeight + ", inSampleSize=" + inSampleSize); return inSampleSize; } // And to convert the image URI to the direct file system path of the image file private String getRealPathFromURI(Uri contentUri) { String[] proj = {MediaStore.Images.Media.DATA}; CursorLoader loader = new CursorLoader(context, contentUri, proj, null, null, null); Cursor cursor = loader.loadInBackground(); if (cursor != null) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); } else if ("file".equals(contentUri.getScheme())) { return contentUri.getSchemeSpecificPart(); } return null; } public int getCount() { return this.bitMaps.size() + this.imageUrls.size() + (isSupportNew() ? 1 : 0); } public ImageView setImage(ImageView imageView, final int position) { if (isSupportNew() && (position == this.getCount() - 1)) { if (imageView == null) { imageView = new ImageView(context); decorImageView(imageView, context); } imageView.setImageResource(R.drawable.pic_plus); final ImageView iv = imageView; imageView.setOnClickListener(newImgCallback.newBtnClickListener()); newImgCallback.postNewImage(null, imageView); return imageView; } else if (position < this.bitMaps.size()) { if (imageView == null) { imageView = new ImageView(context); decorImageView(imageView, context); } imageView.setImageBitmap(bitMaps.get(position)); imageView.setOnClickListener(new ThumbnailOnClickListener(context, isSupportNew(), position, this.fullImages)); if (newImgCallback != null) newImgCallback.postNotANewImage(imageView); return imageView; } else { NetworkImageView niv; if (imageView == null || !(imageView instanceof NetworkImageView)) { if (imageView != null) { Log.d(Singleton.DAIFAN_TAG, "image-view to network image isn't NetworkImageView:" + position); imageView = null; } niv = new NetworkImageView(context); decorImageView(niv, context); } else { niv = (NetworkImageView) imageView; } ImageLoader imgLoader = ((BaseActivity) context).getDaifanApplication().getImageLoader(); niv.setImageUrl(this.imageUrls.get(position - this.bitMaps.size()), imgLoader); niv.setOnClickListener(new ThumbnailOnClickListener(context, isSupportNew(), position, this.fullImages)); if (newImgCallback != null) newImgCallback.postNotANewImage(niv); return niv; } } private void decorImageView(ImageView imageView, Context mContext) { int padding = mContext.getResources().getDimensionPixelSize(R.dimen.padding_medium); imageView.setPadding(0, padding, padding, padding); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); //TODO: it should be better to assign by callers imageView.setMaxHeight(thumbnailH); imageView.setMaxWidth(thumbnailW); imageView.setMinimumHeight(thumbnailH); imageView.setMinimumWidth(thumbnailW); Log.d(Singleton.DAIFAN_TAG, "set thunbnail w:"+ thumbnailW + ", h:" + thumbnailH); } public static int dpToPx(int dp, Context context) { DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); int px = Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)); return px; } private static class ThumbnailOnClickListener implements View.OnClickListener { private final Context context; private final int position; private final boolean supportNew; private ArrayList<String> fullImages = new ArrayList<String>(); public ThumbnailOnClickListener(Context context, boolean supportNew, int position, ArrayList<String> imgs) { this.context = context; this.position = position; this.supportNew = supportNew; if (imgs != null) this.fullImages = imgs; } @Override public void onClick(View v) { Log.d(Singleton.DAIFAN_TAG, "clicked on image:" + position); if (supportNew) { } else { Intent login = new Intent(context.getApplicationContext(), ImagesActivity.class); login.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); login.putExtra("images", fullImages.toArray(new String[0])); login.putExtra("currItem", this.position); context.startActivity(login); } } } public void addFullImages(ArrayList<String> fullImgs) { this.fullImages.addAll(fullImgs); } }