Browse Source

Support for SVG icons with Glide and Android SVG

alejandro 8 years ago
parent
commit
8a0974c656

+ 2 - 0
build.gradle

@@ -183,6 +183,8 @@ dependencies {
     compile 'com.jakewharton:butterknife:8.4.0'
     annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
 
+    compile 'com.github.bumptech.glide:glide:3.7.0'
+    compile 'com.caverock:androidsvg:1.2.1'
     /// dependencies for local unit tests
     testCompile 'junit:junit:4.12'
     testCompile 'org.mockito:mockito-core:1.10.19'

+ 37 - 0
src/main/java/com/owncloud/android/ui/adapter/ActivityListAdapter.java

@@ -1,6 +1,8 @@
 package com.owncloud.android.ui.adapter;
 
 import android.content.Context;
+import android.graphics.drawable.PictureDrawable;
+import android.net.Uri;
 import android.support.v7.widget.RecyclerView;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -8,10 +10,20 @@ import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.bumptech.glide.GenericRequestBuilder;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.bumptech.glide.load.model.StreamEncoder;
+import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
+import com.caverock.androidsvg.SVG;
 import com.owncloud.android.R;
 import com.owncloud.android.lib.resources.activities.models.Activity;
 import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.SvgDecoder;
+import com.owncloud.android.utils.SvgDrawableTranscoder;
+import com.owncloud.android.utils.SvgSoftwareLayerSetter;
 
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -49,9 +61,34 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
         ((ActivityViewHolder)holder).message.setText(activity.getMessage());
 
         // Todo set proper action icon (to be clarified how to pick)
+
+        downloadIcon(activity.getIcon(),((ActivityViewHolder)holder).activityIcon);
         //((ActivityViewHolder)holder).activityIcon.setImageResource(R.drawable.ic_action_share);
     }
 
+    private void downloadIcon(String icon, ImageView itemViewType) {
+        GenericRequestBuilder<Uri, InputStream, SVG, PictureDrawable> requestBuilder = Glide.with(context)
+                .using(Glide.buildStreamModelLoader(Uri.class, context), InputStream.class)
+                .from(Uri.class)
+                .as(SVG.class)
+                .transcode(new SvgDrawableTranscoder(), PictureDrawable.class)
+                .sourceEncoder(new StreamEncoder())
+                .cacheDecoder(new FileToStreamDecoder<SVG>(new SvgDecoder()))
+                .decoder(new SvgDecoder())
+                .placeholder(R.drawable.ic_menu_archive)
+                .error(R.drawable.ic_web)
+                .animate(android.R.anim.fade_in)
+                .listener(new SvgSoftwareLayerSetter<Uri>());
+
+
+        Uri uri = Uri.parse(icon);
+        requestBuilder
+                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
+                // SVG cannot be serialized so it's not worth to cache it
+                .load(uri)
+                .into(itemViewType);
+    }
+
     @Override
     public int getItemCount() {
         return mValues.size();

+ 31 - 0
src/main/java/com/owncloud/android/utils/SvgDecoder.java

@@ -0,0 +1,31 @@
+package com.owncloud.android.utils;
+
+
+
+import com.bumptech.glide.load.ResourceDecoder;
+import com.bumptech.glide.load.engine.Resource;
+import com.bumptech.glide.load.resource.SimpleResource;
+import com.caverock.androidsvg.SVG;
+import com.caverock.androidsvg.SVGParseException;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Decodes an SVG internal representation from an {@link InputStream}.
+ */
+public class SvgDecoder implements ResourceDecoder<InputStream, SVG> {
+    public Resource<SVG> decode(InputStream source, int width, int height) throws IOException {
+        try {
+            SVG svg = SVG.getFromInputStream(source);
+            return new SimpleResource<SVG>(svg);
+        } catch (SVGParseException ex) {
+            throw new IOException("Cannot load SVG from stream", ex);
+        }
+    }
+
+    @Override
+    public String getId() {
+        return "SvgDecoder.com.owncloud.android";
+    }
+}

+ 31 - 0
src/main/java/com/owncloud/android/utils/SvgDrawableTranscoder.java

@@ -0,0 +1,31 @@
+package com.owncloud.android.utils;
+
+/**
+ * Created by alejandro on 29/03/17.
+ */
+
+import android.graphics.Picture;
+import android.graphics.drawable.PictureDrawable;
+
+import com.bumptech.glide.load.engine.Resource;
+import com.bumptech.glide.load.resource.SimpleResource;
+import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
+import com.caverock.androidsvg.SVG;
+
+/**
+ * Convert the {@link SVG}'s internal representation to an Android-compatible one ({@link Picture}).
+ */
+public class SvgDrawableTranscoder implements ResourceTranscoder<SVG, PictureDrawable> {
+    @Override
+    public Resource<PictureDrawable> transcode(Resource<SVG> toTranscode) {
+        SVG svg = toTranscode.get();
+        Picture picture = svg.renderToPicture();
+        PictureDrawable drawable = new PictureDrawable(picture);
+        return new SimpleResource<PictureDrawable>(drawable);
+    }
+
+    @Override
+    public String getId() {
+        return "";
+    }
+}

+ 40 - 0
src/main/java/com/owncloud/android/utils/SvgSoftwareLayerSetter.java

@@ -0,0 +1,40 @@
+package com.owncloud.android.utils;
+
+import android.annotation.TargetApi;
+import android.graphics.drawable.PictureDrawable;
+import android.os.Build;
+import android.widget.ImageView;
+
+import com.bumptech.glide.request.RequestListener;
+import com.bumptech.glide.request.target.ImageViewTarget;
+import com.bumptech.glide.request.target.Target;
+
+/**
+ * Listener which updates the {@link ImageView} to be software rendered,
+ * because {@link com.caverock.androidsvg.SVG SVG}/{@link android.graphics.Picture Picture}
+ * can't render on a hardware backed {@link android.graphics.Canvas Canvas}.
+ *
+ * @param <T> not used, here to prevent unchecked warnings at usage
+ */
+@TargetApi(Build.VERSION_CODES.HONEYCOMB)
+public class SvgSoftwareLayerSetter<T> implements RequestListener<T, PictureDrawable> {
+
+    @Override
+    public boolean onException(Exception e, T model, Target<PictureDrawable> target, boolean isFirstResource) {
+        ImageView view = ((ImageViewTarget<?>) target).getView();
+        if (Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT) {
+            view.setLayerType(ImageView.LAYER_TYPE_NONE, null);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onResourceReady(PictureDrawable resource, T model, Target<PictureDrawable> target,
+                                   boolean isFromMemoryCache, boolean isFirstResource) {
+        ImageView view = ((ImageViewTarget<?>) target).getView();
+        if (Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT) {
+            view.setLayerType(ImageView.LAYER_TYPE_SOFTWARE, null);
+        }
+        return false;
+    }
+}