1

I have a problem with change background color at image in widget. Right now i'm using like this:

try {
        Class c = Class.forName("android.widget.RemoteViews");
        Method m = c.getMethod("setDrawableParameters", int.class, boolean.class, int.class, int.class, PorterDuff.Mode.class, int.class);
        m.invoke(remoteViews, R.id.myImage, true, -1, Color.HSVToColor(color), PorterDuff.Mode.SRC_OVER, -1);
    } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
        e.printStackTrace();
    }

Everything works perfect, until i tested on android 9, here i receive an error:

java.lang.NoSuchMethodException: setDrawableParameters [int, boolean, int, int, class android.graphics.PorterDuff$Mode, int]

Do you have any idea how can i make it work on android 9 also? Thanks.

Android
  • 1,420
  • 4
  • 13
  • 23
Bogdan
  • 43
  • 5

2 Answers2

3

Another solution that worked for me is to have the image source in the xml layout android:src="@mipmap/myImage" and in code remoteViews.setInt(R.id.myImageView,"setColorFilter", myColor);

denis_lor
  • 6,212
  • 4
  • 31
  • 55
Bogdan
  • 43
  • 5
  • I like it! @Bogdan thank you for your contribution! I added your answer with a link to it and mentioning you in my accepted answer so everyone can see how they can fix an issue that you had in your original question (method not found) and can also go deeper and create a solution for a specific case that is set background color of a image in remoteView. – denis_lor Mar 12 '19 at 14:01
  • It worked for me, thank you. Also I had to additionally set alpha to my imageview like that: `if (Build.VERSION.SDK_INT >= JELLY_BEAN) { views.setInt(R.id.widget_background, "setImageAlpha", Color.alpha(yourColor)) } else { views.setInt(R.id.widget_background, "setAlpha", Color.alpha(yourColor)) }` – akhris Nov 26 '19 at 04:37
1

setDrawableParameters(..) is called setDrawableTint(..) in Android 9.0.

Here is the source code of the new method setDrawableTint(..) available in Android 9.0, I guess it does the same job as setDrawableParameters(..) in previous version of Android but you have to try it out in your project.

/** 
 * Equivalent to calling 
 * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}, 
 * on the {@link Drawable} of a given view. 
 * <p> 
 * The operation will be performed on the {@link Drawable} returned by the 
 * target {@link View#getBackground()} by default.  If targetBackground is false, 
 * we assume the target is an {@link ImageView} and try applying the operations 
 * to {@link ImageView#getDrawable()}. 
 * <p> 
 */ 
private class SetDrawableTint extends Action { 
    SetDrawableTint(int id, boolean targetBackground, 
            int colorFilter, @NonNull PorterDuff.Mode mode) { 
        this.viewId = id; 
        this.targetBackground = targetBackground; 
        this.colorFilter = colorFilter; 
        this.filterMode = mode; 
    } 

    SetDrawableTint(Parcel parcel) { 
        viewId = parcel.readInt(); 
        targetBackground = parcel.readInt() != 0; 
        colorFilter = parcel.readInt(); 
        filterMode = PorterDuff.intToMode(parcel.readInt()); 
    } 

    public void writeToParcel(Parcel dest, int flags) { 
        dest.writeInt(viewId); 
        dest.writeInt(targetBackground ? 1 : 0); 
        dest.writeInt(colorFilter); 
        dest.writeInt(PorterDuff.modeToInt(filterMode)); 
    } 

    @Override 
    public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { 
        final View target = root.findViewById(viewId); 
        if (target == null) return; 

        // Pick the correct drawable to modify for this view 
        Drawable targetDrawable = null; 
        if (targetBackground) { 
            targetDrawable = target.getBackground(); 
        } else if (target instanceof ImageView) { 
            ImageView imageView = (ImageView) target; 
            targetDrawable = imageView.getDrawable(); 
        } 

        if (targetDrawable != null) { 
            targetDrawable.mutate().setColorFilter(colorFilter, filterMode); 
        } 
    } 

    @Override 
    public int getActionTag() { 
        return SET_DRAWABLE_TINT_TAG; 
    } 

    boolean targetBackground; 
    int colorFilter; 
    PorterDuff.Mode filterMode; 
} 

You could check how the new method works and what parameters needs and then have in your project something like:

if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.P){
    // Your actual implementation with "setDrawableParameters"
    changeImageBackgroundColorBeforeAndroidPIE()
} else{
    // Your new implementation with "setDrawableTint"
    changeImageBackgroundColorAndroidPIEAndLater()
}

Another solution could be:

As I see the method setDrawableParameters(..) is hidden, so it is not meant to be used in this way, I guess it won't be the optimal solution to solve your problem. It looks like a hacky solution, but it can actually get worst once they change it or once it won't be supported in the way you thought it works.

Let's start from the beginning, you want to change the background color of an image in a widget, in a RemoteView more precisely, probably you could convert the drawable into a bitmap and then call RemoteViews.setImageBitmap()

Here is how to Convert a drawable into a bitmap

UPDATE: Another solution that the author just found was

Another solution that worked for me is to have the image source in the xml layout android:src="@mipmap/myImage" and in code remoteViews.setInt(R.id.myImageView,"setColorFilter", myColor);

Here the author answer: https://stackoverflow.com/a/55123126/3564632

denis_lor
  • 6,212
  • 4
  • 31
  • 55
  • I've already tried solution 1: `Drawable drawable = ContextCompat.getDrawable(context, R.mipmap.image); drawable.setColorFilter(Color.HSVToColor(mycolor),PorterDuff.Mode.SRC_ATOP; Bitmap bitmap = drawableToBitmap(drawable); remoteViews.setImageViewBitmap(R.id.myimageview, bitmap);` , but doesn't working. Solution 2 it is working, thank you very much. – Bogdan Mar 11 '19 at 11:07
  • Try the new method available in Android 9. I updated my answer to better match the context and scope of your question – denis_lor Mar 11 '19 at 11:10
  • The first solution works...but i received an pop up on screen with the message: `Detected problems with API compatibility` to resolve this I have to modify my targetSdkVersion to 28, but after that the background doesn't change and I received the error: `java.lang.NoSuchMethodException: setDrawableTint [int, boolean, int, class android.graphics.PorterDuff$Mode]` – Bogdan Mar 12 '19 at 12:45
  • The popup happens because you are trying to access a method in the dark grey list API methods https://developer.android.com/about/versions/pie/restrictions-non-sdk-interfaces – denis_lor Mar 12 '19 at 13:00
  • yes, you are right....looks like there is no solution to change the background image color at widget... – Bogdan Mar 12 '19 at 13:10
  • Post is as another answer so everyone can benefit from it! – denis_lor Mar 12 '19 at 13:22