1 /*
2  * Copyright (C) 2019 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 android.systemui.cts;
18 
19 import android.graphics.Canvas;
20 import android.graphics.Color;
21 import android.graphics.ColorFilter;
22 import android.graphics.CornerPathEffect;
23 import android.graphics.DashPathEffect;
24 import android.graphics.Insets;
25 import android.graphics.Paint;
26 import android.graphics.Path;
27 import android.graphics.Point;
28 import android.graphics.Rect;
29 import android.graphics.drawable.Drawable;
30 import android.view.MotionEvent;
31 import android.view.View;
32 import android.view.WindowInsets;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 
37 public class WindowInsetsPresenterDrawable extends Drawable implements View.OnTouchListener {
38     private static final int GAP = 15;
39     private final Path mPath;
40     private final Paint mMandatorySystemGesturePaint;
41     private final Paint mSystemGesturePaint;
42     private final Paint mSystemWindowPaint;
43     private final Paint mTappableElementPaint;
44     private final Paint mTouchPaint;
45     private final Paint mTouchTrackPaint;
46     private final List<Point> mAllActionPoints;
47     private final List<Point> mActionCancelPoints;
48     private final List<Point> mActionDownPoints;
49     private final List<Point> mActionUpPoints;
50     private WindowInsets mWindowInsets;
51     private float mLastX;
52     private float mLastY;
53 
54     /**
55      * Initial 4 paints and 1 path for drawing.
56      * initial mPointList for recording the touch points.
57      */
WindowInsetsPresenterDrawable()58     public WindowInsetsPresenterDrawable() {
59         mMandatorySystemGesturePaint = new Paint();
60         mMandatorySystemGesturePaint.setStrokeWidth(2);
61         mMandatorySystemGesturePaint.setStyle(Paint.Style.STROKE);
62         mMandatorySystemGesturePaint.setColor(Color.RED);
63         mMandatorySystemGesturePaint.setPathEffect(new DashPathEffect(new float[]{GAP, GAP * 3},
64                 0));
65 
66         mSystemGesturePaint = new Paint();
67         mSystemGesturePaint.setStrokeWidth(2);
68         mSystemGesturePaint.setStyle(Paint.Style.STROKE);
69         mSystemGesturePaint.setColor(Color.GREEN);
70         mSystemGesturePaint.setPathEffect(new DashPathEffect(new float[]{GAP, GAP, GAP * 2},
71                 0));
72 
73         mTappableElementPaint = new Paint();
74         mTappableElementPaint.setStrokeWidth(2);
75         mTappableElementPaint.setStyle(Paint.Style.STROKE);
76         mTappableElementPaint.setColor(Color.BLUE);
77         mTappableElementPaint.setPathEffect(new DashPathEffect(new float[]{GAP * 2, GAP, GAP}, 0));
78 
79         mSystemWindowPaint = new Paint();
80         mSystemWindowPaint.setStrokeWidth(2);
81         mSystemWindowPaint.setStyle(Paint.Style.STROKE);
82         mSystemWindowPaint.setColor(Color.YELLOW);
83         mSystemWindowPaint.setPathEffect(new DashPathEffect(new float[]{0, GAP * 3, GAP}, 0));
84 
85         mTouchPaint = new Paint();
86         mTouchPaint.setColor(0x4ffff070);
87         mTouchPaint.setStrokeWidth(10);
88         mTouchPaint.setStyle(Paint.Style.FILL_AND_STROKE);
89 
90         mPath = new Path();
91         mTouchTrackPaint = new Paint();
92         mTouchTrackPaint.setColor(Color.WHITE);
93         mTouchTrackPaint.setStrokeWidth(1);
94         mTouchTrackPaint.setStyle(Paint.Style.STROKE);
95         mTouchTrackPaint.setPathEffect(new CornerPathEffect(5));
96 
97         mAllActionPoints = new ArrayList<>();
98         mActionCancelPoints = new ArrayList<>();
99         mActionDownPoints = new ArrayList<>();
100         mActionUpPoints = new ArrayList<>();
101     }
102 
103 
WindowInsetsPresenterDrawable(WindowInsets windowInsets)104     public WindowInsetsPresenterDrawable(WindowInsets windowInsets) {
105         this();
106         mWindowInsets = windowInsets;
107     }
108 
109     @Override
setBounds(Rect bounds)110     public void setBounds(Rect bounds) {
111         super.setBounds(bounds);
112     }
113 
drawInset(Canvas canvas, Insets insets, Paint paint)114     private void drawInset(Canvas canvas, Insets insets, Paint paint) {
115         final Rect rect = getBounds();
116 
117         if (insets.left > 0) {
118             canvas.drawRect(0, 0, insets.left, rect.bottom, paint);
119         }
120         if (insets.top > 0) {
121             canvas.drawRect(0, 0, rect.width(), insets.top, paint);
122         }
123         if (insets.right > 0) {
124             canvas.drawRect(rect.width() - insets.right, 0, rect.width(), rect.bottom,
125                     paint);
126         }
127         if (insets.bottom > 0) {
128             canvas.drawRect(0, rect.height() - insets.bottom, rect.width(), rect.height(),
129                     paint);
130         }
131     }
132 
133     @Override
draw(Canvas canvas)134     public void draw(Canvas canvas) {
135         canvas.save();
136 
137         if (mWindowInsets != null) {
138             drawInset(canvas, mWindowInsets.getSystemGestureInsets(), mSystemGesturePaint);
139             drawInset(canvas, mWindowInsets.getMandatorySystemGestureInsets(),
140                     mMandatorySystemGesturePaint);
141             drawInset(canvas, mWindowInsets.getTappableElementInsets(), mTappableElementPaint);
142             drawInset(canvas, mWindowInsets.getSystemWindowInsets(), mSystemWindowPaint);
143         }
144 
145         if (mAllActionPoints.size() > 0) {
146             canvas.drawPath(mPath, mTouchTrackPaint);
147 
148             for (Point p : mAllActionPoints) {
149                 canvas.drawPoint(p.x, p.y, mTouchPaint);
150             }
151         }
152 
153         canvas.restore();
154     }
155 
156     @Override
setAlpha(int alpha)157     public void setAlpha(int alpha) {
158         /* do noting, only for implement abstract method */
159     }
160 
161     @Override
setColorFilter(ColorFilter colorFilter)162     public void setColorFilter(ColorFilter colorFilter) {
163         /* do noting, only for implement abstract method */
164     }
165 
166     @Override
getOpacity()167     public int getOpacity() {
168         return 255; /* not transparent */
169     }
170 
171     /**
172      * To set the IwndowInsets that is showed on this drawable.
173      * @param windowInsets the WindowInsets will show.
174      */
setWindowInsets(WindowInsets windowInsets)175     public void setWindowInsets(WindowInsets windowInsets) {
176         if (windowInsets != null) {
177             mWindowInsets = new WindowInsets.Builder(windowInsets).build();
178             invalidateSelf();
179         }
180     }
181 
182     @Override
onTouch(View v, MotionEvent event)183     public boolean onTouch(View v, MotionEvent event) {
184         Point p;
185         switch (event.getAction()) {
186             case MotionEvent.ACTION_DOWN:
187                 mPath.moveTo(event.getX(), event.getY());
188                 p = new Point((int) event.getX(), (int) event.getY());
189                 mAllActionPoints.add(p);
190                 mActionDownPoints.add(p);
191                 mLastX = event.getX();
192                 mLastY = event.getY();
193                 invalidateSelf();
194 
195                 break;
196             case MotionEvent.ACTION_UP:
197                 mPath.lineTo(event.getX(), event.getY());
198                 p = new Point((int) event.getX(), (int) event.getY());
199                 mAllActionPoints.add(p);
200                 mActionUpPoints.add(p);
201                 invalidateSelf();
202                 break;
203             case MotionEvent.ACTION_MOVE:
204                 mPath.quadTo(mLastX, mLastY, event.getX(), event.getY());
205                 p = new Point((int) event.getX(), (int) event.getY());
206                 mAllActionPoints.add(p);
207                 mLastX = event.getX();
208                 mLastY = event.getY();
209                 invalidateSelf();
210                 break;
211             case MotionEvent.ACTION_CANCEL:
212                 mPath.lineTo(event.getX(), event.getY());
213                 p = new Point((int) event.getX(), (int) event.getY());
214                 mAllActionPoints.add(p);
215                 mActionCancelPoints.add(p);
216                 break;
217             default:
218                 break;
219         }
220         return false;
221     }
222 
getActionCancelPoints()223     public List<Point> getActionCancelPoints() {
224         return mActionCancelPoints;
225     }
226 
getActionDownPoints()227     public List<Point> getActionDownPoints() {
228         return mActionDownPoints;
229     }
230 
getActionUpPoints()231     public List<Point> getActionUpPoints() {
232         return mActionUpPoints;
233     }
234 }
235