Android UnsupportedOperationException on Canvas.clipPath

I use the image cropping library here https://github.com/lvillani/android-cropimage in my project to crop the images stored on the device.

However, some users report crashes with the next stack trace.

java.lang.UnsupportedOperationException at android.view.GLES20Canvas.clipPath(GLES20Canvas.java:413) at com.android.camera.HighlightView.draw(HighlightView.java:101) at com.android.camera.CropImageView.onDraw(CropImage.java:783) at android.view.View.draw(View.java:11006) at android.view.View.getDisplayList(View.java:10445) at android.view.ViewGroup.drawChild(ViewGroup.java:2850) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489) at android.view.View.getDisplayList(View.java:10443) at android.view.ViewGroup.drawChild(ViewGroup.java:2850) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489) at android.view.View.getDisplayList(View.java:10443) at android.view.ViewGroup.drawChild(ViewGroup.java:2850) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489) at android.view.View.getDisplayList(View.java:10443) at android.view.ViewGroup.drawChild(ViewGroup.java:2850) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489) at android.view.View.getDisplayList(View.java:10443) at android.view.ViewGroup.drawChild(ViewGroup.java:2850) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489) at android.view.View.draw(View.java:11009) at android.widget.FrameLayout.draw(FrameLayout.java:450) at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2154) at android.view.View.getDisplayList(View.java:10445) at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:853) at android.view.ViewRootImpl.draw(ViewRootImpl.java:1961) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1679) at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2558) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4697) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:787) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:554) at dalvik.system.NativeStart.main(Native Method) 

From the search, I think that this is caused by hardware acceleration only on certain devices. I disabled hardware acceleration in my manifest, but the exception is still happening. I also found that "A workaround is to identify problematic operations in your code, then draw them into a bitmap, and then split the bitmap into your accelerated canvas."

Problem code according to stack trace

 protected void draw(Canvas canvas) { if (mHidden) { return; } canvas.save(); Path path = new Path(); if (!hasFocus()) { mOutlinePaint.setColor(0xFF000000); canvas.drawRect(mDrawRect, mOutlinePaint); } else { Rect viewDrawingRect = new Rect(); mContext.getDrawingRect(viewDrawingRect); if (mCircle) { float width = mDrawRect.width(); float height = mDrawRect.height(); path.addCircle(mDrawRect.left + (width / 2), mDrawRect.top + (height / 2), width / 2, Path.Direction.CW); mOutlinePaint.setColor(0xFFEF04D6); } else { path.addRect(new RectF(mDrawRect), Path.Direction.CW); mOutlinePaint.setColor(0xFFFF8A00); } canvas.clipPath(path, Region.Op.DIFFERENCE); canvas.drawRect(viewDrawingRect, hasFocus() ? mFocusPaint : mNoFocusPaint); canvas.restore(); canvas.drawPath(path, mOutlinePaint); if (mMode == ModifyMode.Grow) { if (mCircle) { int width = mResizeDrawableDiagonal.getIntrinsicWidth(); int height = mResizeDrawableDiagonal.getIntrinsicHeight(); int d = (int) Math.round(Math.cos(/*45deg*/Math.PI / 4D) * (mDrawRect.width() / 2D)); int x = mDrawRect.left + (mDrawRect.width() / 2) + d - width / 2; int y = mDrawRect.top + (mDrawRect.height() / 2) - d - height / 2; mResizeDrawableDiagonal.setBounds(x, y, x + mResizeDrawableDiagonal.getIntrinsicWidth(), y + mResizeDrawableDiagonal.getIntrinsicHeight()); mResizeDrawableDiagonal.draw(canvas); } else { int left = mDrawRect.left + 1; int right = mDrawRect.right + 1; int top = mDrawRect.top + 4; int bottom = mDrawRect.bottom + 3; int widthWidth = mResizeDrawableWidth.getIntrinsicWidth() / 2; int widthHeight = mResizeDrawableWidth.getIntrinsicHeight() / 2; int heightHeight = mResizeDrawableHeight.getIntrinsicHeight() / 2; int heightWidth = mResizeDrawableHeight.getIntrinsicWidth() / 2; int xMiddle = mDrawRect.left + ((mDrawRect.right - mDrawRect.left) / 2); int yMiddle = mDrawRect.top + ((mDrawRect.bottom - mDrawRect.top) / 2); mResizeDrawableWidth.setBounds(left - widthWidth, yMiddle - widthHeight, left + widthWidth, yMiddle + widthHeight); mResizeDrawableWidth.draw(canvas); mResizeDrawableWidth.setBounds(right - widthWidth, yMiddle - widthHeight, right + widthWidth, yMiddle + widthHeight); mResizeDrawableWidth.draw(canvas); mResizeDrawableHeight.setBounds(xMiddle - heightWidth, top - heightHeight, xMiddle + heightWidth, top + heightHeight); mResizeDrawableHeight.draw(canvas); mResizeDrawableHeight.setBounds(xMiddle - heightWidth, bottom - heightHeight, xMiddle + heightWidth, bottom + heightHeight); mResizeDrawableHeight.draw(canvas); } } } } 

How can I draw a bitmap and then blit to the canvas?

Any help would be greatly appreciated!

+11
source share
3 answers

On ICS devices, there is a developer option to force hardware acceleration, even if the application does not request it. This is what causes the accident. You should use something like this to make it use software rendering:

 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) { myCusomView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } 
+17
source

I think you can draw your presentation on the screen bitmap and copy the bitmap onto the screen canvas. For instance,

 protected void draw(Canvas canvas) { if (mHidden) { return; } Bitmap bitmap = createOffScreenBitmap(); canvas.drawa(bitmap,0f, 0f, null); } private Bitmap drawOffScreenBitmap(){ // Draw whatever you want to draw right here. } 

Alternatively, you can use PorterDuffxfermode , which supports hardware acceleration instead of clippath .

0
source

myCustomView = view class name or use this

 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) { this.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } 

I get the solution using that method.

0
source

Source: https://habr.com/ru/post/1444314/


All Articles