diff --git a/library/build.gradle b/library/build.gradle index d6a4eef5..27198e52 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -11,7 +11,7 @@ dependencies { } android { - compileSdkVersion 26 + compileSdkVersion 28 buildToolsVersion "26.0.1" lintOptions { abortOnError false diff --git a/library/src/main/java/com/sothree/slidinguppanel/SlidingUpPanelLayout.java b/library/src/main/java/com/sothree/slidinguppanel/SlidingUpPanelLayout.java index 424a008c..50b6d64a 100644 --- a/library/src/main/java/com/sothree/slidinguppanel/SlidingUpPanelLayout.java +++ b/library/src/main/java/com/sothree/slidinguppanel/SlidingUpPanelLayout.java @@ -22,6 +22,8 @@ import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; +import com.sothree.slidinguppanel.canvassaveproxy.CanvasSaveProxy; +import com.sothree.slidinguppanel.canvassaveproxy.CanvasSaveProxyFactory; import com.sothree.slidinguppanel.library.R; import java.util.List; @@ -218,6 +220,8 @@ public enum PanelState { private View.OnClickListener mFadeOnClickListener; private final ViewDragHelper mDragHelper; + private final CanvasSaveProxyFactory mCanvasSaveProxyFactory; + private CanvasSaveProxy mCanvasSaveProxy; /** * Stores whether or not the pane was expanded the last time it was slideable. @@ -273,6 +277,8 @@ public SlidingUpPanelLayout(Context context, AttributeSet attrs) { public SlidingUpPanelLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + mCanvasSaveProxyFactory = new CanvasSaveProxyFactory(); + if (isInEditMode()) { mShadowDrawable = null; mDragHelper = null; @@ -1186,7 +1192,12 @@ private void onPanelDragged(int newTop) { @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean result; - final int save = canvas.save(Canvas.CLIP_SAVE_FLAG); + + if (mCanvasSaveProxy == null || !mCanvasSaveProxy.isFor(canvas)) { + mCanvasSaveProxy = mCanvasSaveProxyFactory.create(canvas); + } + + final int save = mCanvasSaveProxy.save(); if (mSlideableView != null && mSlideableView != child) { // if main view // Clip against the slider; no sense drawing what will immediately be covered, diff --git a/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/AndroidPCanvasSaveProxy.java b/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/AndroidPCanvasSaveProxy.java new file mode 100644 index 00000000..70216d2e --- /dev/null +++ b/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/AndroidPCanvasSaveProxy.java @@ -0,0 +1,28 @@ +package com.sothree.slidinguppanel.canvassaveproxy; + +import android.graphics.Canvas; +import android.os.Build; +import android.support.annotation.RequiresApi; +import android.util.Log; + +@RequiresApi(api = Build.VERSION_CODES.P) +class AndroidPCanvasSaveProxy implements CanvasSaveProxy { + private static final String TAG = CanvasSaveProxy.class.getSimpleName(); + private final Canvas mCanvas; + + AndroidPCanvasSaveProxy(final Canvas canvas) { + Log.d(TAG, "New AndroidPCanvasSaveProxy"); + + mCanvas = canvas; + } + + @Override + public int save() { + return mCanvas.save(); + } + + @Override + public boolean isFor(final Canvas canvas) { + return canvas == mCanvas; + } +} diff --git a/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/CanvasSaveProxy.java b/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/CanvasSaveProxy.java new file mode 100644 index 00000000..102e23f9 --- /dev/null +++ b/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/CanvasSaveProxy.java @@ -0,0 +1,9 @@ +package com.sothree.slidinguppanel.canvassaveproxy; + +import android.graphics.Canvas; + +public interface CanvasSaveProxy { + int save(); + + boolean isFor(final Canvas canvas); +} diff --git a/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/CanvasSaveProxyFactory.java b/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/CanvasSaveProxyFactory.java new file mode 100644 index 00000000..4d3e1781 --- /dev/null +++ b/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/CanvasSaveProxyFactory.java @@ -0,0 +1,16 @@ +package com.sothree.slidinguppanel.canvassaveproxy; + +import android.graphics.Canvas; +import android.os.Build; + +public class CanvasSaveProxyFactory { + + public CanvasSaveProxy create(final Canvas canvas) { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + return new AndroidPCanvasSaveProxy(canvas); + } else { + return new LegacyCanvasSaveProxy(canvas); + } + } +} diff --git a/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/LegacyCanvasSaveProxy.java b/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/LegacyCanvasSaveProxy.java new file mode 100644 index 00000000..1b9262a1 --- /dev/null +++ b/library/src/main/java/com/sothree/slidinguppanel/canvassaveproxy/LegacyCanvasSaveProxy.java @@ -0,0 +1,67 @@ +package com.sothree.slidinguppanel.canvassaveproxy; + +import android.graphics.Canvas; +import android.util.Log; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +@Deprecated +class LegacyCanvasSaveProxy implements CanvasSaveProxy { + private static final String TAG = CanvasSaveProxy.class.getSimpleName(); + private static final String METHOD_NAME = "save"; + private static final String FIELD_NAME = "CLIP_SAVE_FLAG"; + + private final Canvas mCanvas; + private final Method mSaveMethod; + private final int mClipSaveFlag; + + LegacyCanvasSaveProxy(final Canvas canvas) { + Log.d(TAG, "New LegacyCanvasSaveProxy"); + + mCanvas = canvas; + mSaveMethod = findSaveMethod(); + mClipSaveFlag = getClipSaveFlagValue(); + } + + @Override + public int save() { + return invokeSave(); + } + + @Override + public boolean isFor(final Canvas canvas) { + return canvas == mCanvas; + } + + private int getClipSaveFlagValue() { + final Field constantField; + try { + constantField = Canvas.class.getDeclaredField(FIELD_NAME); + return (int) constantField.get(null); + } catch (NoSuchFieldException e) { + throw new IllegalStateException("Failed to get value of " + FIELD_NAME + " - NoSuchFieldException", e); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Failed to get value of " + FIELD_NAME + " - IllegalAccessException", e); + } + } + + private Method findSaveMethod() { + try { + return Canvas.class.getMethod(METHOD_NAME, int.class); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Canvas does not contain a method with signature save(int)"); + } + } + + private int invokeSave() { + try { + return (int) mSaveMethod.invoke(mCanvas, mClipSaveFlag); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Failed to execute save(int) - IllegalAccessException", e); + } catch (InvocationTargetException e) { + throw new IllegalStateException("Failed to execute save(int) - InvocationTargetException", e); + } + } +}