/discourse2/src/main/java/org/sufficientlysecure/htmltextview/UrlImageGetter.java
Java | 286 lines | 193 code | 37 blank | 56 comment | 28 complexity | e958dacd2b7abe26c141e30d9100bb0d MD5 | raw file
- /*
- * Copyright (C) 2013 Antarix Tandon
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.sufficientlysecure.htmltextview;
- import android.content.Context;
- import android.content.res.Resources;
- import android.graphics.Canvas;
- import android.graphics.drawable.BitmapDrawable;
- import android.graphics.drawable.Drawable;
- import android.os.AsyncTask;
- import android.text.Html.ImageGetter;
- import android.text.Spannable;
- import android.text.style.ImageSpan;
- import android.widget.TextView;
- import com.android.volley.VolleyError;
- import com.android.volley.toolbox.ImageLoader.ImageContainer;
- import org.apache.http.HttpResponse;
- import org.apache.http.client.methods.HttpGet;
- import org.apache.http.impl.client.DefaultHttpClient;
- import org.goodev.discourse.App;
- import org.goodev.discourse.R;
- import org.goodev.discourse.span.ImageClickableSpan;
- import org.goodev.discourse.utils.ImageLoader;
- import org.goodev.discourse.utils.L;
- import org.goodev.discourse.utils.Utils;
- import java.io.IOException;
- import java.io.InputStream;
- import java.net.MalformedURLException;
- import java.util.ArrayList;
- public class UrlImageGetter implements ImageGetter {
- public ArrayList<ImageContainer> mImageContainers = new ArrayList<ImageLoader.ImageContainer>();
- Context mCtx;
- TextView mTextView;
- Drawable mPlaseHolder;
- int mDefaultHeight;
- int mDefaultWidth;
- ImageLoader mImageLoader;
- /**
- * Construct the URLImageParser which will execute AsyncTask and refresh the container
- */
- public UrlImageGetter(TextView t, Context c, ImageLoader loader) {
- mCtx = c;
- t.setTag(R.id.poste_image_getter, this);
- mTextView = t;
- mImageLoader = loader;
- // TODO 帖子内容中的默认图片
- mPlaseHolder = c.getResources().getDrawable(R.drawable.ic_logo);
- mDefaultHeight = mPlaseHolder.getIntrinsicHeight();
- mDefaultWidth = mPlaseHolder.getIntrinsicWidth();
- mPlaseHolder.setBounds(0, 0, mDefaultWidth, mDefaultHeight);
- }
- @Override
- public Drawable getDrawable(String source) {
- source = checkUrl(source);
- UrlDrawable urlDrawable = new UrlDrawable();
- ImageContainer ic = mImageLoader.getForImageSpan(this, source, mTextView, new ImageCallback(mCtx.getResources(), urlDrawable));
- // TODO 当帖子滚动屏幕外的时候 如何和ImageView一样 取消前面没用的下载请求???
- if (ic != null && ic.getBitmap() != null) {
- BitmapDrawable drawable = new BitmapDrawable(mCtx.getResources(), ic.getBitmap());
- drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
- return drawable;
- }
- if (ic != null) {
- mImageContainers.add(ic);
- }
- // get the actual source
- // ImageGetterAsyncTask asyncTask = new ImageGetterAsyncTask(urlDrawable);
- // asyncTask.execute(source);
- // return reference to URLDrawable where I will change with actual image from
- // the src tag
- return urlDrawable;
- }
- private String checkUrl(String source) {
- if (source.startsWith(Utils.SLASH2)) {
- source = Utils.AVATAR_HTTP_PREFIX + source;
- } else if (source.startsWith(Utils.SLASH)) {
- // 用户上传的图片 地址为相对地址: /upload/ddd.
- source = App.getSiteUrl() + source.substring(1);
- }
- return source;
- }
- class ImageCallback implements com.android.volley.toolbox.ImageLoader.ImageListener {
- private final UrlDrawable mDrawable;
- private final Resources mRes;
- public ImageCallback(Resources res, UrlDrawable d) {
- mDrawable = d;
- mRes = res;
- }
- @Override
- public void onErrorResponse(VolleyError error) {
- // TODO 显示错误图片?
- }
- @Override
- public void onResponse(ImageContainer response, boolean isImmediate) {
- if (mTextView.getTag(R.id.poste_image_getter) == UrlImageGetter.this && response.getBitmap() != null) {
- BitmapDrawable drawable = new BitmapDrawable(mRes, response.getBitmap());
- drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
- String src = response.getRequestUrl();
- // redraw the image by invalidating the container
- // 由于下面重新设置了ImageSpan,所以这里invalidate就不必要了吧
- // urlDrawable.invalidateSelf();
- // UrlImageGetter.this.mTextView.invalidate();
- // TODO 这种方式基本完美解决显示图片问题, blog?
- // 把提取到下面显示的图片在放出来? 然后点击任何图片 进入到 帖子图片浏览界面。。?
- TextView v = UrlImageGetter.this.mTextView;
- CharSequence text = v.getText();
- if (!(text instanceof Spannable)) {
- return;
- }
- Spannable spanText = (Spannable) text;
- @SuppressWarnings("unchecked") ArrayList<String> imgs = (ArrayList<String>) v.getTag(R.id.poste_image_data);
- ImageSpan[] imageSpans = spanText.getSpans(0, spanText.length(), ImageSpan.class);
- L.i("%b X Recycled %b src: %s", isImmediate, response.getBitmap().isRecycled(), src);
- for (ImageSpan imgSpan : imageSpans) {
- int start = spanText.getSpanStart(imgSpan);
- int end = spanText.getSpanEnd(imgSpan);
- L.i("%d-%d :%s", start, end, imgSpan.getSource());
- String url = imgSpan.getSource();
- url = checkUrl(url);
- if (src.equals(url)) {
- spanText.removeSpan(imgSpan);
- ImageSpan is = new ImageSpan(drawable, src, ImageSpan.ALIGN_BASELINE);
- spanText.setSpan(is, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- if (imgs != null && imgs.contains(src)) {
- ImageClickableSpan ics = new ImageClickableSpan(src);
- spanText.setSpan(ics, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- v.setText(spanText);
- }
- }
- }
- public class ImageGetterAsyncTask extends AsyncTask<String, Void, Drawable> {
- private final UrlDrawable urlDrawable;
- private String src;
- public ImageGetterAsyncTask(UrlDrawable d) {
- urlDrawable = d;
- }
- @Override
- protected Drawable doInBackground(String... params) {
- String source = params[0];
- src = source;
- return fetchDrawable(source);
- }
- @Override
- protected void onPostExecute(Drawable result) {
- if (result == null) {
- // TODO 设置默认错误图片?
- return;
- }
- // set the correct bound according to the result from HTTP call
- int w = result.getIntrinsicWidth();
- int h = result.getIntrinsicHeight();
- urlDrawable.setBounds(0, 0, 0 + w, 0 + h);
- L.i("%d X %d", w, h);
- // change the reference of the current drawable to the result
- // from the HTTP call
- urlDrawable.drawable = result;
- // redraw the image by invalidating the container
- // 由于下面重新设置了ImageSpan,所以这里invalidate就不必要了吧
- // urlDrawable.invalidateSelf();
- // UrlImageGetter.this.mTextView.invalidate();
- // TODO 这种方式基本完美解决显示图片问题, blog?
- // 把提取到下面显示的图片在放出来? 然后点击任何图片 进入到 帖子图片浏览界面。。?
- TextView v = UrlImageGetter.this.mTextView;
- Spannable spanText = (Spannable) v.getText();
- @SuppressWarnings("unchecked") ArrayList<String> imgs = (ArrayList<String>) v.getTag(R.id.poste_image_data);
- ImageSpan[] imageSpans = spanText.getSpans(0, spanText.length(), ImageSpan.class);
- for (ImageSpan imgSpan : imageSpans) {
- int start = spanText.getSpanStart(imgSpan);
- int end = spanText.getSpanEnd(imgSpan);
- L.i("%d-%d :%s", start, end, imgSpan.getSource());
- if (src.equals(imgSpan.getSource())) {
- spanText.removeSpan(imgSpan);
- ImageSpan is = new ImageSpan(result, src, ImageSpan.ALIGN_BASELINE);
- spanText.setSpan(is, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- if (imgs != null && imgs.contains(src)) {
- ImageClickableSpan ics = new ImageClickableSpan(src);
- spanText.setSpan(ics, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- // For ICS
- // UrlImageGetter.this.container.setMinimumHeight(
- // (UrlImageGetter.this.container.getHeight() + result.getIntrinsicHeight()));
- // UrlImageGetter.this.container.requestLayout();
- // UrlImageGetter.this.container.invalidate();
- }
- /**
- * Get the Drawable from URL
- *
- * @param urlString
- * @return
- */
- public Drawable fetchDrawable(String urlString) {
- try {
- InputStream is = fetch(urlString);
- Drawable drawable = Drawable.createFromResourceStream(App.getContext().getResources(), null, is, "src");
- L.d("%d----------X------ %d--%s", drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), urlString);
- drawable.setBounds(0, 0, 0 + drawable.getIntrinsicWidth(), 0 + drawable.getIntrinsicHeight());
- return drawable;
- } catch (Exception e) {
- return null;
- }
- }
- private InputStream fetch(String urlString) throws MalformedURLException, IOException {
- DefaultHttpClient httpClient = new DefaultHttpClient();
- HttpGet request = new HttpGet(urlString);
- HttpResponse response = httpClient.execute(request);
- return response.getEntity().getContent();
- }
- }
- @SuppressWarnings("deprecation")
- public class UrlDrawable extends BitmapDrawable {
- public UrlDrawable() {
- setBounds(0, 0, mDefaultWidth, mDefaultHeight);
- } // the drawable that you need to set, you could set the initial drawing
- // with the loading image if you need to
- protected Drawable drawable = mPlaseHolder;
- @Override
- public void draw(Canvas canvas) {
- // override the draw to facilitate refresh function later
- if (drawable != null) {
- drawable.draw(canvas);
- }
- }
- @Override
- public int getIntrinsicWidth() {
- return drawable.getIntrinsicWidth();
- }
- @Override
- public int getIntrinsicHeight() {
- return drawable.getIntrinsicHeight();
- }
- }
- }