• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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