1 /* 2 * Copyright (C) 2021 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 com.android.test.hwui 18 19 import android.content.Context 20 import android.graphics.BlendMode 21 import android.graphics.Color 22 import android.graphics.Paint 23 import android.graphics.Rect 24 import android.hardware.HardwareBuffer 25 import android.util.AttributeSet 26 import android.view.InputDevice 27 import android.view.MotionEvent 28 import android.view.Surface 29 import android.view.SurfaceHolder 30 import android.view.SurfaceView 31 import android.view.WindowInsets 32 import android.view.WindowInsetsController 33 34 class FrontBufferedLayer : SurfaceView, SurfaceHolder.Callback { 35 var mRenderer: PenStylusActivity.SingleBufferedCanvas? = null 36 37 constructor(context: Context) : super(context) 38 constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) 39 40 init { 41 holder.addCallback(this) 42 setZOrderOnTop(true) 43 } 44 45 override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { 46 nDestroy(mNativePtr) 47 mNativePtr = nCreate(holder.surface) 48 mRenderer = PenStylusActivity.SingleBufferedCanvas(width, height) 49 clearOverlay() 50 51 if ((false)) { 52 val canvas = holder.lockCanvas() 53 canvas.drawColor(Color.LTGRAY) 54 holder.unlockCanvasAndPost(canvas) 55 } 56 } 57 58 override fun surfaceDestroyed(holder: SurfaceHolder) { 59 mRenderer = null 60 nDestroy(mNativePtr) 61 mNativePtr = 0 62 } 63 64 override fun surfaceCreated(holder: SurfaceHolder) { 65 } 66 67 override fun onAttachedToWindow() { 68 super.onAttachedToWindow() 69 requestUnbufferedDispatch(InputDevice.SOURCE_CLASS_POINTER) 70 this.windowInsetsController?.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT) 71 this.windowInsetsController?.hide(WindowInsets.Type.navigationBars()) 72 this.windowInsetsController?.hide(WindowInsets.Type.statusBars()) 73 } 74 75 private fun clearOverlay() { 76 mRenderer?.let { 77 it.update(null) { 78 drawColor(Color.WHITE, BlendMode.SRC) 79 } 80 nUpdateBuffer(mNativePtr, it.mHardwareBuffer) 81 } 82 } 83 84 private var prevX: Float = 0f 85 private var prevY: Float = 0f 86 private val paint = Paint().also { 87 it.color = Color.BLACK 88 it.strokeWidth = 10f 89 it.isAntiAlias = true 90 } 91 92 override fun onTouchEvent(event: MotionEvent): Boolean { 93 if (!event.isFromSource(InputDevice.SOURCE_STYLUS)) { 94 if (event.action == MotionEvent.ACTION_DOWN) { 95 clearOverlay() 96 } 97 return true 98 } 99 val action = event.actionMasked 100 if (action == MotionEvent.ACTION_DOWN || 101 action == MotionEvent.ACTION_MOVE) { 102 mRenderer?.let { 103 val left = minOf(prevX, event.x).toInt() - 10 104 val top = minOf(prevY, event.y).toInt() - 10 105 val right = maxOf(prevX, event.x).toInt() + 10 106 val bottom = maxOf(prevY, event.y).toInt() + 10 107 it.update(Rect(left, top, right, bottom)) { 108 if (action == MotionEvent.ACTION_MOVE) { 109 drawLine(prevX, prevY, event.x, event.y, paint) 110 } 111 drawCircle(event.x, event.y, 5f, paint) 112 } 113 nUpdateBuffer(mNativePtr, it.mHardwareBuffer) 114 } 115 prevX = event.x 116 prevY = event.y 117 } 118 return true 119 } 120 121 private var mNativePtr: Long = 0 122 123 private external fun nCreate(surface: Surface): Long 124 private external fun nDestroy(ptr: Long) 125 private external fun nUpdateBuffer(ptr: Long, buffer: HardwareBuffer) 126 127 companion object { 128 init { 129 System.loadLibrary("hwaccelerationtest_jni") 130 } 131 } 132 }