1 /* 2 * Copyright (C) 2024 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.example.android.vdmdemo.demos; 18 19 import android.content.Context; 20 import android.graphics.Bitmap; 21 import android.graphics.Canvas; 22 import android.graphics.Color; 23 import android.graphics.Paint; 24 import android.graphics.Path; 25 import android.graphics.Rect; 26 import android.graphics.drawable.Drawable; 27 import android.util.AttributeSet; 28 import android.view.MotionEvent; 29 import android.view.View; 30 31 import androidx.annotation.Nullable; 32 33 /** A view for drawing on the screen with a stylus. */ 34 public class StylusDrawingView extends View { 35 36 private final Path mDrawPath = new Path(); 37 private final Paint mCanvasPaint = new Paint(Paint.DITHER_FLAG); 38 private final Paint mDrawPaint = new Paint(); 39 private Canvas mDrawCanvas; 40 private Bitmap mCanvasBitmap; 41 StylusDrawingView(Context context)42 public StylusDrawingView(Context context) { 43 super(context); 44 init(); 45 } 46 StylusDrawingView(Context context, @Nullable AttributeSet attrs)47 public StylusDrawingView(Context context, @Nullable AttributeSet attrs) { 48 super(context, attrs); 49 init(); 50 } 51 StylusDrawingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr)52 public StylusDrawingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 53 super(context, attrs, defStyleAttr); 54 init(); 55 } 56 StylusDrawingView( Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)57 public StylusDrawingView( 58 Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 59 super(context, attrs, defStyleAttr, defStyleRes); 60 init(); 61 } 62 init()63 private void init() { 64 mDrawPaint.setAntiAlias(true); 65 mDrawPaint.setStyle(Paint.Style.STROKE); 66 mDrawPaint.setStrokeJoin(Paint.Join.ROUND); 67 mDrawPaint.setStrokeCap(Paint.Cap.ROUND); 68 setBackgroundColor(Color.WHITE); 69 70 Drawable hoverPointer = getContext().getResources().getDrawable(R.drawable.circle, null); 71 setOnHoverListener((v, e) -> { 72 Rect rect = new Rect(); 73 StylusDrawingView.this.getGlobalVisibleRect(rect); 74 int x = (int) e.getX() + rect.left; 75 int y = (int) e.getY() + rect.top; 76 hoverPointer.setBounds(new Rect(x - 10, y - 10, x + 10, y + 10)); 77 switch (e.getAction()) { 78 case MotionEvent.ACTION_HOVER_ENTER: 79 getRootView().getOverlay().add(hoverPointer); 80 break; 81 case MotionEvent.ACTION_HOVER_EXIT: 82 getRootView().getOverlay().clear(); 83 break; 84 } 85 return true; 86 }); 87 } 88 89 @Override onSizeChanged(int w, int h, int oldw, int oldh)90 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 91 super.onSizeChanged(w, h, oldw, oldh); 92 mCanvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 93 mDrawCanvas = new Canvas(mCanvasBitmap); 94 } 95 96 @Override onDraw(Canvas canvas)97 protected void onDraw(Canvas canvas) { 98 canvas.drawBitmap(mCanvasBitmap, 0 , 0, mCanvasPaint); 99 canvas.drawPath(mDrawPath, mDrawPaint); 100 } 101 102 @Override onTouchEvent(MotionEvent event)103 public boolean onTouchEvent(MotionEvent event) { 104 // TODO: do something fun with tilt and orientation 105 106 if (event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) { 107 mDrawPaint.setStrokeWidth((int) Math.max(3, Math.pow(50, event.getPressure()))); 108 if (event.getButtonState() == MotionEvent.BUTTON_STYLUS_PRIMARY) { 109 mDrawPaint.setColor(Color.MAGENTA); 110 } else if (event.getButtonState() == MotionEvent.BUTTON_STYLUS_SECONDARY) { 111 mDrawPaint.setColor(Color.YELLOW); 112 } else { 113 mDrawPaint.setColor(Color.CYAN); 114 } 115 } else if (event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER) { 116 mDrawPaint.setStrokeWidth(100); 117 mDrawPaint.setColor(Color.WHITE); 118 mDrawPaint.setStrokeJoin(Paint.Join.ROUND); 119 mDrawPaint.setStrokeCap(Paint.Cap.ROUND); 120 } else { 121 return false; 122 } 123 124 float x = event.getX(); 125 float y = event.getY(); 126 127 switch (event.getAction()) { 128 case MotionEvent.ACTION_DOWN: 129 case MotionEvent.ACTION_UP: 130 mDrawPath.moveTo(x, y); 131 break; 132 case MotionEvent.ACTION_MOVE: 133 mDrawPath.lineTo(x, y); 134 mDrawCanvas.drawPath(mDrawPath, mDrawPaint); 135 mDrawPath.reset(); 136 mDrawPath.moveTo(x, y); 137 break; 138 default: 139 return false; 140 } 141 invalidate(); 142 return true; 143 } 144 } 145