skydoves / ColorPickerPreference

🎨 A library that lets you implement ColorPicker, ColorPickerDialog, ColorPickerPreference.
Apache License 2.0
480 stars 51 forks source link

API 28 Issue #8

Closed LossyDragon closed 6 years ago

LossyDragon commented 6 years ago

Hello,

I recently bumped my application to API 28, when launching the application, the following below crashes within the ColorPickerView.

Using these dependencies crash the app implementation 'com.android.support:design:28.0.0-rc01' implementation 'com.android.support:appcompat-v7:28.0.0-rc01'

Going down to API 27 works fine, not sure if the new dependencies once they get out of RC will still cause issues.

08-09 20:23:22.157 8630-8630/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.lossydragon.arduinorgb, PID: 8630
    java.lang.IllegalArgumentException: x must be < bitmap.width()
        at android.graphics.Bitmap.checkPixelAccess(Bitmap.java:1780)
        at android.graphics.Bitmap.getPixel(Bitmap.java:1728)
        at com.skydoves.colorpickerpreference.ColorPickerView.getColorFromBitmap(ColorPickerView.java:215)
        at com.skydoves.colorpickerpreference.ColorPickerView.setSelectorPoint(ColorPickerView.java:313)
        at com.skydoves.colorpickerpreference.ColorPickerView.onFirstLayout(ColorPickerView.java:111)
        at com.skydoves.colorpickerpreference.ColorPickerView.access$000(ColorPickerView.java:40)
        at com.skydoves.colorpickerpreference.ColorPickerView$1.onGlobalLayout(ColorPickerView.java:102)
        at android.view.ViewTreeObserver.dispatchOnGlobalLayout(ViewTreeObserver.java:945)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2358)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1460)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7184)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:949)
        at android.view.Choreographer.doCallbacks(Choreographer.java:761)
        at android.view.Choreographer.doFrame(Choreographer.java:696)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Thanks,

boardy commented 6 years ago

I'm getting the exact same issue when using the builder for the ColorPicerDialog. If it helps at all, below is code snippet on how it is being launched.

ColorPickerDialog.Builder builder = new ColorPickerDialog.Builder(QueryValueMetricConfiguration.this,
                    AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);
            builder.setTitle("Set Background Colour");
            builder.setPreferenceName("Background Colour");
            builder.setPositiveButton("Confirm", new ColorListener() {
                @Override
                public void onColorSelected(ColorEnvelope colorEnvelope) {

                    view.setBackgroundColor(colorEnvelope.getColor());
                    view.setTag(colorEnvelope);
                    processRules();
                }
            });
            builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    dialogInterface.dismiss();
                }
            });
            builder.show();
effleurager commented 6 years ago

@skydoves I found the issue:

private int getColorFromBitmap(float x, float y) {
        if (paletteDrawable == null) return 0;

        Matrix invertMatrix = new Matrix();
        palette.getImageMatrix().invert(invertMatrix);

        float[] mappedPoints = new float[]{x, y};
        invertMatrix.mapPoints(mappedPoints);

        if (palette.getDrawable() != null && palette.getDrawable() instanceof BitmapDrawable &&
                mappedPoints[0] > 0 && mappedPoints[1] > 0 &&
                mappedPoints[0] < palette.getDrawable().getIntrinsicWidth() && mappedPoints[1] < palette.getDrawable().getIntrinsicHeight()) {

            invalidate();
            return ((BitmapDrawable) palette.getDrawable()).getBitmap().getPixel((int) mappedPoints[0], (int) mappedPoints[1]);
        }
        return 0;
    }

In the non-zero return statement, palette.getDrawable() will return a drawable with the dimensions relative to whatever the display size is. In Android P, the call to .getBitmap() will return the size of the original bitmap, which is 730×730.

You'll have to interpolate the mapped points, or multiply the points with a scaling factor in the .getPixel() call.

acorbin3 commented 6 years ago

I have a fix I will trying to create a branch later today

skydoves commented 6 years ago

It's fixed at version 1.0.5. @acorbin3 Thank you for your contribution!

Anjuka commented 4 years ago

t's fixed at version 1.0.5. Need to update the version of lbr