1 /* 2 * Copyright 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.compose.ui.graphics 18 19 import android.annotation.SuppressLint 20 import android.graphics.Canvas 21 import android.os.Build 22 import androidx.annotation.RequiresApi 23 import java.lang.reflect.InvocationTargetException 24 import java.lang.reflect.Method 25 26 internal object CanvasUtils { 27 private var reorderBarrierMethod: Method? = null 28 private var inorderBarrierMethod: Method? = null 29 private var orderMethodsFetched = false 30 31 /** 32 * Enables Z support for the Canvas. 33 * 34 * This is only supported on Lollipop and later. 35 */ 36 @SuppressLint("SoonBlockedPrivateApi") enableZnull37 fun enableZ(canvas: Canvas, enable: Boolean) { 38 if (Build.VERSION.SDK_INT >= 29) { 39 CanvasZHelper.enableZ(canvas, enable) 40 } else { 41 if (!orderMethodsFetched) { 42 try { 43 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) { 44 // use double reflection to avoid grey list on P 45 val getDeclaredMethod = 46 Class::class 47 .java 48 .getDeclaredMethod( 49 "getDeclaredMethod", 50 String::class.java, 51 arrayOf<Class<*>>()::class.java 52 ) 53 reorderBarrierMethod = 54 getDeclaredMethod.invoke( 55 Canvas::class.java, 56 "insertReorderBarrier", 57 emptyArray<Class<*>>() 58 ) as Method? 59 inorderBarrierMethod = 60 getDeclaredMethod.invoke( 61 Canvas::class.java, 62 "insertInorderBarrier", 63 emptyArray<Class<*>>() 64 ) as Method? 65 } else { 66 reorderBarrierMethod = 67 Canvas::class.java.getDeclaredMethod("insertReorderBarrier") 68 inorderBarrierMethod = 69 Canvas::class.java.getDeclaredMethod("insertInorderBarrier") 70 } 71 reorderBarrierMethod?.isAccessible = true 72 inorderBarrierMethod?.isAccessible = true 73 } catch (ignore: IllegalAccessException) { // Do nothing 74 } catch (ignore: InvocationTargetException) { // Do nothing 75 } catch (ignore: NoSuchMethodException) { // Do nothing 76 } 77 orderMethodsFetched = true 78 } 79 try { 80 if (enable && reorderBarrierMethod != null) { 81 reorderBarrierMethod!!.invoke(canvas) 82 } 83 if (!enable && inorderBarrierMethod != null) { 84 inorderBarrierMethod!!.invoke(canvas) 85 } 86 } catch (ignore: IllegalAccessException) { // Do nothing 87 } catch (ignore: InvocationTargetException) { // Do nothing 88 } 89 } 90 } 91 } 92 93 @RequiresApi(29) 94 private object CanvasZHelper { enableZnull95 fun enableZ(canvas: Canvas, enable: Boolean) { 96 if (enable) { 97 canvas.enableZ() 98 } else { 99 canvas.disableZ() 100 } 101 } 102 } 103