1 /*
2  * Copyright (C) 2016 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.systemui.screenshot;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.graphics.Canvas;
22 import android.graphics.Color;
23 import android.graphics.Paint;
24 import android.graphics.Point;
25 import android.graphics.PorterDuff;
26 import android.graphics.PorterDuffXfermode;
27 import android.graphics.Rect;
28 import android.util.AttributeSet;
29 import android.view.MotionEvent;
30 import android.view.View;
31 
32 import java.util.function.Consumer;
33 
34 /**
35  * Draws a selection rectangle while taking screenshot
36  */
37 public class ScreenshotSelectorView extends View {
38     private Point mStartPoint;
39     private Rect mSelectionRect;
40     private final Paint mPaintSelection, mPaintBackground;
41 
42     private Consumer<Rect> mOnScreenshotSelected;
43 
ScreenshotSelectorView(Context context)44     public ScreenshotSelectorView(Context context) {
45         this(context, null);
46     }
47 
ScreenshotSelectorView(Context context, @Nullable AttributeSet attrs)48     public ScreenshotSelectorView(Context context, @Nullable AttributeSet attrs) {
49         super(context, attrs);
50         mPaintBackground = new Paint(Color.BLACK);
51         mPaintBackground.setAlpha(160);
52         mPaintSelection = new Paint(Color.TRANSPARENT);
53         mPaintSelection.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
54 
55         setOnTouchListener((v, event) -> {
56             switch (event.getAction()) {
57                 case MotionEvent.ACTION_DOWN:
58                     startSelection((int) event.getX(), (int) event.getY());
59                     return true;
60                 case MotionEvent.ACTION_MOVE:
61                     updateSelection((int) event.getX(), (int) event.getY());
62                     return true;
63                 case MotionEvent.ACTION_UP:
64                     setVisibility(View.GONE);
65                     final Rect rect = getSelectionRect();
66                     if (mOnScreenshotSelected != null
67                             && rect != null
68                             && rect.width() != 0 && rect.height() != 0) {
69                         mOnScreenshotSelected.accept(rect);
70                     }
71                     stopSelection();
72                     return true;
73             }
74             return false;
75         });
76     }
77 
78     @Override
draw(Canvas canvas)79     public void draw(Canvas canvas) {
80         canvas.drawRect(mLeft, mTop, mRight, mBottom, mPaintBackground);
81         if (mSelectionRect != null) {
82             canvas.drawRect(mSelectionRect, mPaintSelection);
83         }
84     }
85 
setOnScreenshotSelected(Consumer<Rect> onScreenshotSelected)86     void setOnScreenshotSelected(Consumer<Rect> onScreenshotSelected) {
87         mOnScreenshotSelected = onScreenshotSelected;
88     }
89 
stop()90     void stop() {
91         if (getSelectionRect() != null) {
92             stopSelection();
93         }
94     }
95 
startSelection(int x, int y)96     private void startSelection(int x, int y) {
97         mStartPoint = new Point(x, y);
98         mSelectionRect = new Rect(x, y, x, y);
99     }
100 
updateSelection(int x, int y)101     private void updateSelection(int x, int y) {
102         if (mSelectionRect != null) {
103             mSelectionRect.left = Math.min(mStartPoint.x, x);
104             mSelectionRect.right = Math.max(mStartPoint.x, x);
105             mSelectionRect.top = Math.min(mStartPoint.y, y);
106             mSelectionRect.bottom = Math.max(mStartPoint.y, y);
107             invalidate();
108         }
109     }
110 
getSelectionRect()111     private Rect getSelectionRect() {
112         return mSelectionRect;
113     }
114 
stopSelection()115     private void stopSelection() {
116         mStartPoint = null;
117         mSelectionRect = null;
118     }
119 }
120