package org.aisen.weibo.sina.ui.fragment.picture; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.graphics.Rect; import android.opengl.GLES10; import android.os.Bundle; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.webkit.JavascriptInterface; import android.webkit.WebView; import android.widget.ImageView; import com.umeng.analytics.MobclickAgent; import org.aisen.android.common.utils.BitmapUtil; import org.aisen.android.common.utils.BitmapUtil.BitmapType; import org.aisen.android.common.utils.FileUtils; import org.aisen.android.common.utils.SystemUtils; import org.aisen.android.common.utils.Utils; import org.aisen.android.common.utils.ViewUtils; import org.aisen.android.component.bitmaploader.BitmapLoader; import org.aisen.android.component.bitmaploader.core.BitmapDecoder; import org.aisen.android.component.bitmaploader.core.ImageConfig; import org.aisen.android.component.bitmaploader.download.DownloadProcess; import org.aisen.android.network.task.TaskException; import org.aisen.android.network.task.WorkTask; import org.aisen.android.support.action.IAction; import org.aisen.android.support.inject.ViewInject; import org.aisen.android.ui.activity.basic.BaseActivity; import org.aisen.android.ui.fragment.ABaseFragment; import org.aisen.android.ui.fragment.ATabsFragment; import org.aisen.weibo.sina.R; import org.aisen.weibo.sina.base.AppSettings; import org.aisen.weibo.sina.sinasdk.bean.PicUrls; import org.aisen.weibo.sina.support.bean.PictureSize; import org.aisen.weibo.sina.support.permissions.SdcardPermissionAction; import org.aisen.weibo.sina.support.sdk.SDK; import org.aisen.weibo.sina.support.sqlit.SinaDB; import org.aisen.weibo.sina.support.utils.AisenUtils; import org.aisen.weibo.sina.support.utils.ThemeUtils; import org.aisen.weibo.sina.ui.activity.picture.PhotosActivity; import org.aisen.weibo.sina.ui.activity.picture.PicsActivity; import org.aisen.weibo.sina.ui.widget.PictureProgressView; import java.io.File; import java.text.DecimalFormat; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL11; import uk.co.senab.photoview.PhotoView; import uk.co.senab.photoview.PhotoViewAttacher; /** * 部分代码参考自四次元 * * @author Jeff.Wang * * @date 2014年9月18日 */ @SuppressLint("SdCardPath") public class PictureFragment extends ABaseFragment implements ATabsFragment.ITabInitData { public static ABaseFragment newInstance(PicUrls url) { PictureFragment fragment = new PictureFragment(); Bundle args = new Bundle(); args.putSerializable("url", url); fragment.setArguments(args); return fragment; } @ViewInject(idStr = "photoview") PhotoView photoView; @ViewInject(idStr = "webview") WebView mWebView; @ViewInject(idStr = "txtFailure", click = "loadPicture") View viewFailure; @ViewInject(id = R.id.viewProgress) PictureProgressView progressView; private PicUrls image; private File origFile = null; private PictureSize pictureSize; public enum PictureStatus { wait, downloading, success, faild } private PictureStatus mStatus; @Override public int inflateContentView() { return R.layout.ui_picture; } @Override protected void layoutInit(LayoutInflater inflater, Bundle savedInstanceSate) { super.layoutInit(inflater, savedInstanceSate); mStatus = PictureStatus.wait; image = savedInstanceSate == null ? (PicUrls) getArguments().getSerializable("url") : (PicUrls) savedInstanceSate.getSerializable("url"); origFile = BitmapLoader.getInstance().getCacheFile(getOrigImage()); photoView.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() { @Override public void onPhotoTap(View view, float v, float v1) { getActivity().finish(); } }); mWebView.addJavascriptInterface(new PictureJavaScriptInterface(), "picturejs"); loadPicture(viewFailure); setHasOptionsMenu(true); } final class PictureJavaScriptInterface { public PictureJavaScriptInterface() { } @JavascriptInterface public void onClick() { getActivity().finish(); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable("url", image); } private String getImage() { if (AppSettings.isLoadOrigPic()) return getOrigImage(); return image.getThumbnail_pic().replace("thumbnail", "bmiddle"); } private String getOrigImage() { return image.getThumbnail_pic().replace("thumbnail", "large"); } void loadPicture(View v) { String url = null;// 下载路径 ImageConfig config = new ImageConfig(); File file = origFile; // 原图存在,就下载原图 if (file.exists()) { url = getOrigImage(); } // 原图不存在,就下载中图 else { file = BitmapLoader.getInstance().getCacheFile(getImage()); config.setId("Picture"); url = getImage(); pictureSize = SinaDB.getDB().selectById(null, PictureSize.class, getOrigImage()); if (pictureSize == null) new LoadPictureSizeTask().execute(); } if (!file.exists()) { progressView.setVisibility(View.VISIBLE); // 如果网络不是WIFI,且原图和中图都没缓存,那么只加载当前看的那个图片 if (SystemUtils.NetWorkType.wifi != SystemUtils.getNetworkType(getActivity())) { if (getActivity() instanceof PicsActivity) { PicsActivity picsActivity = (PicsActivity) getActivity(); if (!picsActivity.getCurrent().getThumbnail_pic().equalsIgnoreCase(image.getThumbnail_pic())) return; } else if (getActivity() instanceof PhotosActivity) { PhotosActivity picsActivity = (PhotosActivity) getActivity(); if (!picsActivity.getCurrent().getThumbnail_pic().equalsIgnoreCase(image.getThumbnail_pic())) return; } } } viewFailure.setVisibility(View.GONE); ImageView imgView = new ImageView(getActivity()); config.setProgress(new PictureDownloadProgress(file)); BitmapLoader.getInstance().display(null, url, imgView, config); } class PictureDownloadProgress extends DownloadProcess { private long length; private File file; PictureDownloadProgress(File file) { this.file = file; } @Override public void receiveLength(long length) { this.length = length; } @Override public void receiveProgress(long progressed) { if (getActivity() == null) return; progressView.setProgress(Math.round(progressed * 100.0f / length)); } @Override public void prepareDownload(String url) { mStatus = PictureStatus.downloading; } @Override public void finishedDownload(byte[] bytes) { onDownloadPicture(bytes, file); mStatus = PictureStatus.success; } @Override public void downloadFailed(Exception e) { if (getActivity() == null) return; mStatus = PictureStatus.faild; progressView.setVisibility(View.INVISIBLE); viewFailure.setVisibility(View.VISIBLE); } } private void onDownloadPicture(byte[] bytes, File file) { if (getActivity() == null) return; getActivity().invalidateOptionsMenu(); progressView.setVisibility(View.INVISIBLE); Options opts = new Options(); opts.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts); // gif if (BitmapUtil.getType(bytes) == BitmapType.gif) { readGifPicture(mWebView, bytes, file); } // 图片太大 else if (opts.outWidth > 1024 || opts.outHeight > 1024) { readLargePicture(mWebView, file); } // 解析图片 else { readPicture(bytes, file, photoView); } getActivity().invalidateOptionsMenu(); } @SuppressLint("SetJavaScriptEnabled") private void readGifPicture(final WebView webview, byte[] bytes, File file) { Options options = new Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); int picWidth = options.outWidth; int picHeight = options.outHeight; int availableWidth = SystemUtils.getScreenWidth(getActivity()) - getResources().getDimensionPixelOffset(R.dimen.normal_gif_webview_margin_left) - getResources().getDimensionPixelOffset(R.dimen.normal_gif_webview_margin_right); int availableHeight = getAppHeight(getActivity()); int maxPossibleResizeHeight = availableWidth * availableHeight / picWidth; if (picWidth >= availableWidth || picHeight >= availableHeight || maxPossibleResizeHeight >= availableHeight) { readLargePicture(webview, file); return; } webview.getSettings().setJavaScriptEnabled(true); webview.getSettings().setUseWideViewPort(true); webview.getSettings().setLoadWithOverviewMode(true); webview.getSettings().setBuiltInZoomControls(false); webview.getSettings().setDisplayZoomControls(false); webview.getSettings().setSupportZoom(false); webview.setVerticalScrollBarEnabled(false); webview.setHorizontalScrollBarEnabled(false); String str1 = "file://" + file.getAbsolutePath().replace("/mnt/sdcard/", "/sdcard/"); String str2 = "<html>\n<head>\n <style>\n html,body{background:#3b3b3b;margin:0;padding:0;} *{-webkit-tap-highlight-color:rgba(0, 0, 0, 0);}\n </style>\n <script type=\"text/javascript\">\n var imgUrl = \"" + str1 + "\";" + " var objImage = new Image();\n" + " var realWidth = 0;\n" + " var realHeight = 0;\n" + "\n" + " function onLoad() {\n" + " objImage.onload = function() {\n" + " realWidth = objImage.width;\n" + " realHeight = objImage.height;\n" + "\n" + " document.gagImg.src = imgUrl;\n" + " onResize();\n" + " }\n" + " objImage.src = imgUrl;\n" + " }\n" + "\n" + " function imgOnClick() {\n" + " window.picturejs.onClick();" + " }\n" + " function onResize() {\n" + " var scale = 1;\n" + " var newWidth = document.gagImg.width;\n" + " if (realWidth > newWidth) {\n" + " scale = realWidth / newWidth;\n" + " } else {\n" + " scale = newWidth / realWidth;\n" + " }\n" + "\n" + " hiddenHeight = Math.ceil(30 * scale);\n" + " document.getElementById('hiddenBar').style.height = hiddenHeight + \"px\";\n" + " document.getElementById('hiddenBar').style.marginTop = -hiddenHeight + \"px\";\n" + " }\n" + " </script>\n" + "</head>\n" + "<body onload=\"onLoad()\" onresize=\"onResize()\" onclick=\"Android.toggleOverlayDisplay();\">\n" + " <table style=\"width: 100%;height:100%;\">\n" + " <tr style=\"width: 100%;\">\n" + " <td valign=\"middle\" align=\"center\" style=\"width: 100%;\">\n" + " <div style=\"display:block\">\n" + " <img name=\"gagImg\" src=\"\" width=\"100%\" style=\"\" onclick=\"imgOnClick()\" />\n" + " </div>\n" + " <div id=\"hiddenBar\" style=\"position:absolute; width: 0%; background: #3b3b3b;\"></div>\n" + " </td>\n" + " </tr>\n" + " </table>\n" + "</body>\n" + "</html>"; webview.loadDataWithBaseURL("file:///android_asset/", str2, "text/html", "utf-8", null); webview.postDelayed(new Runnable() { @Override public void run() { webview.setVisibility(View.VISIBLE); } }, 500); } @SuppressLint("SetJavaScriptEnabled") private void readLargePicture(final WebView large, File file) { photoView.setImageDrawable(getResources().getDrawable(R.drawable.bg_timeline_loading)); large.getSettings().setJavaScriptEnabled(true); large.getSettings().setUseWideViewPort(true); large.getSettings().setLoadWithOverviewMode(true); large.getSettings().setBuiltInZoomControls(true); large.getSettings().setDisplayZoomControls(false); large.setVerticalScrollBarEnabled(false); large.setHorizontalScrollBarEnabled(false); String str1 = "file://" + file.getAbsolutePath().replace("/mnt/sdcard/", "/sdcard/"); String str2 = "<html>\n<head>\n <style>\n html,body{background:#3b3b3b;margin:0;padding:0;} *{-webkit-tap-highlight-color:rgba(0, 0, 0, 0);}\n </style>\n <script type=\"text/javascript\">\n var imgUrl = \"" + str1 + "\";" + " var objImage = new Image();\n" + " var realWidth = 0;\n" + " var realHeight = 0;\n" + "\n" + " function onLoad() {\n" + " objImage.onload = function() {\n" + " realWidth = objImage.width;\n" + " realHeight = objImage.height;\n" + "\n" + " document.gagImg.src = imgUrl;\n" + " onResize();\n" + " }\n" + " objImage.src = imgUrl;\n" + " }\n" + "\n" + " function imgOnClick() {\n" + " window.picturejs.onClick();" + " }\n" + " function onResize() {\n" + " var scale = 1;\n" + " var newWidth = document.gagImg.width;\n" + " if (realWidth > newWidth) {\n" + " scale = realWidth / newWidth;\n" + " } else {\n" + " scale = newWidth / realWidth;\n" + " }\n" + "\n" + " hiddenHeight = Math.ceil(30 * scale);\n" + " document.getElementById('hiddenBar').style.height = hiddenHeight + \"px\";\n" + " document.getElementById('hiddenBar').style.marginTop = -hiddenHeight + \"px\";\n" + " }\n" + " </script>\n" + "</head>\n" + "<body onload=\"onLoad()\" onresize=\"onResize()\" onclick=\"Android.toggleOverlayDisplay();\">\n" + " <table style=\"width: 100%;height:100%;\">\n" + " <tr style=\"width: 100%;\">\n" + " <td valign=\"middle\" align=\"center\" style=\"width: 100%;\">\n" + " <div style=\"display:block\">\n" + " <img name=\"gagImg\" src=\"\" width=\"100%\" style=\"\" onclick=\"imgOnClick()\" />\n" + " </div>\n" + " <div id=\"hiddenBar\" style=\"position:absolute; width: 0%; background: #3b3b3b;\"></div>\n" + " </td>\n" + " </tr>\n" + " </table>\n" + "</body>\n" + "</html>"; large.loadDataWithBaseURL("file:///android_asset/", str2, "text/html", "utf-8", null); large.setTag(new Object()); large.postDelayed(new Runnable() { @Override public void run() { large.setVisibility(View.VISIBLE); } }, 500); } private void readPicture(byte[] bytes, File file, ImageView imageView) { try { Bitmap bitmap = BitmapDecoder.decodeSampledBitmapFromByte(getActivity(), bytes); imageView.setImageBitmap(bitmap); imageView.setVisibility(View.VISIBLE); } catch (OutOfMemoryError e) { readLargePicture(mWebView, file); } } public static int getBitmapMaxWidthAndMaxHeight() { // 2014-08-26 最大高度改小一点 int[] maxSizeArray = new int[1]; GLES10.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxSizeArray, 0); if (maxSizeArray[0] == 0) { GLES10.glGetIntegerv(GL11.GL_MAX_TEXTURE_SIZE, maxSizeArray, 0); } if (maxSizeArray[0] > 0) return maxSizeArray[0]; return 1280; } public static int getAppHeight(Activity paramActivity) { Rect localRect = new Rect(); paramActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect); return localRect.height(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_picture, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public void onPrepareOptionsMenu(Menu menu) { if (getActivity() != null) { File file = BitmapLoader.getInstance().getCacheFile(getImage()); menu.findItem(R.id.savePicture).setVisible(file.exists()); menu.findItem(R.id.share).setVisible(file.exists()); MenuItem origItem = menu.findItem(R.id.origPicture); if (file.exists()) origItem.setVisible(!origFile.exists()); else origItem.setVisible(false); if (origItem.isVisible()) { if (downloadOrigPicture != null) { String progressed = String.valueOf(Math.round(progress[0] * 100.0f / progress[1])); origItem.setTitle(String.format("%s(%s", getString(R.string.orig_pic), progressed) + "%)"); } else { if (pictureSize != null) { String sizeStr; if (pictureSize.getSize() * 1.0f / 1024 / 1024 > 1) sizeStr = String.format("%s M", new DecimalFormat("#.00").format(pictureSize.getSize() * 1.0d / 1024 / 1024)); else sizeStr = String.format("%d Kb", pictureSize.getSize() / 1024); origItem.setTitle(getString(R.string.orig_pic) + String.format("(%s)", sizeStr)); } else { origItem.setTitle(R.string.orig_pic); } } } // Intent shareIntent = Utils.getShareIntent("", "", getImage()); // MenuItem shareItem = menu.findItem(R.id.share); // ShareActionProvider shareProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem); // shareProvider.setShareHistoryFileName("channe_share.xml"); // shareProvider.setShareIntent(shareIntent); } super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // 下载 if (item.getItemId() == R.id.savePicture) { MobclickAgent.onEvent(getActivity(), "save_picture"); downloadImage(); } // 分享 else if (item.getItemId() == R.id.share) { MobclickAgent.onEvent(getActivity(), "share_picture"); Intent shareIntent = Utils.getShareIntent("", "", getImage()); startActivity(shareIntent); } // 复制链接 else if (item.getItemId() == R.id.copy) { AisenUtils.copyToClipboard(getImage()); ViewUtils.showMessage(getActivity(), R.string.msg_image_copyed); } // 下载原图 else if (item.getItemId() == R.id.origPicture) { if (downloadOrigPicture == null) new DownloadOrigPicture(origFile).execute(); getActivity().invalidateOptionsMenu(); } // 重新下载 else if (item.getItemId() == R.id.downloadAgain) { origFile.delete(); BitmapLoader.getInstance().getCacheFile(getImage()).delete(); loadPicture(null); } return super.onOptionsItemSelected(item); } private void downloadImage() { new IAction(getActivity(), new SdcardPermissionAction((BaseActivity) getActivity(), null)) { @Override public void doAction() { new WorkTask<Void, Void, String>() { @Override protected void onPrepare() { super.onPrepare(); ViewUtils.createProgressDialog(getActivity(), getString(R.string.msg_save_pic_loading), ThemeUtils.getThemeColor()).show(); } private void notifyFileSys(File file) { SystemUtils.scanPhoto(getActivity(), file); } @Override public String workInBackground(Void... params) throws TaskException { File file = origFile; if (!file.exists()) file = BitmapLoader.getInstance().getCacheFile(getImage()); String path = SystemUtils.getSdcardPath() + File.separator + AppSettings.getImageSavePath() + File.separator + file.getName(); File newFile = new File(path); if (!newFile.exists()) { if (!newFile.getParentFile().exists()) newFile.getParentFile().mkdirs(); try { FileUtils.copyFile(file, newFile); notifyFileSys(newFile); return newFile.getParentFile().getAbsolutePath(); } catch (Exception e) { } } else { notifyFileSys(newFile); return newFile.getParentFile().getAbsolutePath(); } return null; } @Override protected void onSuccess(String aBoolean) { super.onSuccess(aBoolean); if (!TextUtils.isEmpty(aBoolean)) { showMessage(String.format(getString(R.string.msg_save_pic_success), aBoolean)); } else { showMessage(R.string.msg_save_pic_faild); } } @Override protected void onFinished() { super.onFinished(); ViewUtils.dismissProgressDialog(); } }.execute(); } }.run(); } DownloadOrigPicture downloadOrigPicture; class DownloadOrigPicture extends WorkTask<Void, Void, Void> { ImageConfig config = new ImageConfig(); DownloadOrigPicture(File file) { downloadOrigPicture = this; config.setProgress(new OrigPictureProgress(file)); } @Override public Void workInBackground(Void... params) throws TaskException { try { BitmapLoader.getInstance().doDownload(getOrigImage(), config); } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onFinished() { super.onFinished(); downloadOrigPicture = null; } } private long[] progress = new long[2]; class OrigPictureProgress extends DownloadProcess { private File file; OrigPictureProgress(File file) { this.file = file; } @Override public void receiveProgress(long progressed) { super.receiveProgress(progressed); progress[0] = progressed; if (getActivity() != null) getActivity().invalidateOptionsMenu(); } @Override public void prepareDownload(String url) { super.prepareDownload(url); progress = new long[2]; if (getActivity() != null) getActivity().invalidateOptionsMenu(); } @Override public void finishedDownload(byte[] bytes) { super.finishedDownload(bytes); if (getActivity() != null) { getActivity().invalidateOptionsMenu(); onDownloadPicture(bytes, file); } } @Override public void downloadFailed(Exception e) { super.downloadFailed(e); if (getActivity() != null) showMessage(R.string.msg_save_orig_faild); } @Override public void receiveLength(long length) { super.receiveLength(length); progress[1] = length; if (getActivity() != null) getActivity().invalidateOptionsMenu(); } } class LoadPictureSizeTask extends WorkTask<Void, Void, PictureSize> { @Override public PictureSize workInBackground(Void... params) throws TaskException { PictureSize size = SDK.newInstance().getPictureSize(getOrigImage()); return size; } @Override protected void onSuccess(PictureSize pictureSize) { super.onSuccess(pictureSize); if (getActivity() != null) getActivity().invalidateOptionsMenu(); PictureFragment.this.pictureSize = pictureSize; } } @Override public void onTabRequestData() { if (mStatus == PictureStatus.wait || mStatus == PictureStatus.faild) { loadPicture(viewFailure); } } @Override public void onDestroy() { super.onDestroy(); if (downloadOrigPicture != null) downloadOrigPicture.cancel(true); } }