blob: 8daf819a50df0afc7ec3a070bc2286842686081e [file] [log] [blame]
Michael Kolb8872c232013-01-29 10:33:22 -08001/*
2 * Copyright (C) 2012 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
17package com.android.camera.ui;
18
19import android.content.Context;
20import android.graphics.Canvas;
21import android.util.AttributeSet;
22import android.view.MotionEvent;
23import android.view.View;
24import android.widget.FrameLayout;
25
Doris Liu6432cd62013-06-13 17:20:31 -070026import com.android.camera.PreviewGestures;
Angus Kong2bca2102014-03-11 16:27:30 -070027import com.android.camera.debug.Log;
Doris Liufb57df12013-05-14 14:37:46 -070028
Michael Kolb8872c232013-01-29 10:33:22 -080029import java.util.ArrayList;
30import java.util.List;
31
32public class RenderOverlay extends FrameLayout {
33
Angus Kong2bca2102014-03-11 16:27:30 -070034 private static final Log.Tag TAG = new Log.Tag("RenderOverlay");
Marco Nelissen0744e4a2013-11-22 01:47:37 +000035 private PreviewGestures.SingleTapListener mTapListener;
Michael Kolb8872c232013-01-29 10:33:22 -080036
37 interface Renderer {
38
39 public boolean handlesTouch();
40 public boolean onTouchEvent(MotionEvent evt);
41 public void setOverlay(RenderOverlay overlay);
42 public void layout(int left, int top, int right, int bottom);
43 public void draw(Canvas canvas);
44
45 }
46
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080047 private final RenderView mRenderView;
48 private final List<Renderer> mClients;
Doris Liu6432cd62013-06-13 17:20:31 -070049 private PreviewGestures mGestures;
Michael Kolb8872c232013-01-29 10:33:22 -080050 // reverse list of touch clients
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080051 private final List<Renderer> mTouchClients;
52 private final int[] mPosition = new int[2];
Michael Kolb8872c232013-01-29 10:33:22 -080053
54 public RenderOverlay(Context context, AttributeSet attrs) {
55 super(context, attrs);
56 mRenderView = new RenderView(context);
57 addView(mRenderView, new LayoutParams(LayoutParams.MATCH_PARENT,
58 LayoutParams.MATCH_PARENT));
59 mClients = new ArrayList<Renderer>(10);
60 mTouchClients = new ArrayList<Renderer>(10);
61 setWillNotDraw(false);
62 }
63
Doris Liu6432cd62013-06-13 17:20:31 -070064 public void setGestures(PreviewGestures gestures) {
Doris Liufb57df12013-05-14 14:37:46 -070065 mGestures = gestures;
66 }
67
Michael Kolb8872c232013-01-29 10:33:22 -080068 public void addRenderer(Renderer renderer) {
69 mClients.add(renderer);
70 renderer.setOverlay(this);
71 if (renderer.handlesTouch()) {
72 mTouchClients.add(0, renderer);
73 }
74 renderer.layout(getLeft(), getTop(), getRight(), getBottom());
75 }
76
77 public void addRenderer(int pos, Renderer renderer) {
78 mClients.add(pos, renderer);
79 renderer.setOverlay(this);
80 renderer.layout(getLeft(), getTop(), getRight(), getBottom());
81 }
82
83 public void remove(Renderer renderer) {
84 mClients.remove(renderer);
85 renderer.setOverlay(null);
86 }
87
88 public int getClientSize() {
89 return mClients.size();
90 }
91
Doris Liuf55f3c42013-11-20 00:24:46 -080092 // TODO: Remove this when refactor is done. This is only here temporarily
93 // to keep pie working before it's replaced with bottom bar.
94 public void directTouchEventsToPie(MotionEvent ev) {
95 PieRenderer pie = null;
96 for (int i = 0; i < mClients.size(); i++) {
97 if (mClients.get(i) instanceof PieRenderer) {
98 pie = (PieRenderer) mClients.get(i);
99 break;
100 }
101 }
Marco Nelissen0744e4a2013-11-22 01:47:37 +0000102 if (pie!= null && pie.isOpen()) {
Doris Liuf55f3c42013-11-20 00:24:46 -0800103 pie.onTouchEvent(ev);
Marco Nelissen0744e4a2013-11-22 01:47:37 +0000104 } else {
105 if (mTapListener != null && ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
106 mTapListener.onSingleTapUp(null, ((int) ev.getX()), ((int) ev.getY()));
107 }
Doris Liuf55f3c42013-11-20 00:24:46 -0800108 }
109 }
110
111 // TODO: Remove this when refactor is done. This is only here temporarily
112 // to keep pie working before it's replaced with bottom bar.
113 public void clear() {
114 mGestures = null;
115 while (mClients.size() > 0) {
116 remove(mClients.get(0));
117 }
118 mTouchClients.clear();
Marco Nelissen0744e4a2013-11-22 01:47:37 +0000119 mTapListener = null;
120 }
121
122 // TODO: Design a touch flow for each module to handle the leftover touch
123 // events from the app
124 public void setTapListener(PreviewGestures.SingleTapListener listener) {
125 mTapListener = listener;
Doris Liuf55f3c42013-11-20 00:24:46 -0800126 }
127
Erin Dahlgrenc5f08b02013-12-09 16:29:38 -0800128
129 // Only Gcam is using this right now, which is only using the pie
130 // menu for the capture progress.
131 // TODO: migrate all modes to PreviewOverlay.
Michael Kolb8872c232013-01-29 10:33:22 -0800132 @Override
Erin Dahlgrenc5f08b02013-12-09 16:29:38 -0800133 public boolean onTouchEvent(MotionEvent ev) {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800134 if (mTapListener != null && ev.getActionMasked() == MotionEvent.ACTION_UP) {
Erin Dahlgrenc5f08b02013-12-09 16:29:38 -0800135 mTapListener.onSingleTapUp(null, ((int) ev.getX()), ((int) ev.getY()));
Doris Liua52f04c2013-06-06 11:39:58 -0700136 }
Doris Liufb57df12013-05-14 14:37:46 -0700137 return true;
Michael Kolb8872c232013-01-29 10:33:22 -0800138 }
139
140 public boolean directDispatchTouch(MotionEvent m, Renderer target) {
141 mRenderView.setTouchTarget(target);
Doris Liufb57df12013-05-14 14:37:46 -0700142 boolean res = mRenderView.dispatchTouchEvent(m);
Michael Kolb8872c232013-01-29 10:33:22 -0800143 mRenderView.setTouchTarget(null);
144 return res;
145 }
146
147 private void adjustPosition() {
148 getLocationInWindow(mPosition);
149 }
150
151 public int getWindowPositionX() {
152 return mPosition[0];
153 }
154
155 public int getWindowPositionY() {
156 return mPosition[1];
157 }
158
159 public void update() {
160 mRenderView.invalidate();
161 }
162
163 private class RenderView extends View {
164
165 private Renderer mTouchTarget;
166
167 public RenderView(Context context) {
168 super(context);
169 setWillNotDraw(false);
170 }
171
172 public void setTouchTarget(Renderer target) {
173 mTouchTarget = target;
174 }
175
176 @Override
Doris Liufb57df12013-05-14 14:37:46 -0700177 public boolean dispatchTouchEvent(MotionEvent evt) {
Doris Liuf55f3c42013-11-20 00:24:46 -0800178 if (mGestures == null) {
179 return false;
180 }
Doris Liufb57df12013-05-14 14:37:46 -0700181
Michael Kolb8872c232013-01-29 10:33:22 -0800182 if (mTouchTarget != null) {
183 return mTouchTarget.onTouchEvent(evt);
184 }
185 if (mTouchClients != null) {
186 boolean res = false;
187 for (Renderer client : mTouchClients) {
188 res |= client.onTouchEvent(evt);
189 }
190 return res;
191 }
192 return false;
193 }
194
195 @Override
196 public void onLayout(boolean changed, int left, int top, int right, int bottom) {
197 adjustPosition();
198 super.onLayout(changed, left, top, right, bottom);
199 if (mClients == null) return;
200 for (Renderer renderer : mClients) {
201 renderer.layout(left, top, right, bottom);
202 }
203 }
204
205 @Override
206 public void draw(Canvas canvas) {
207 super.draw(canvas);
208 if (mClients == null) return;
209 boolean redraw = false;
210 for (Renderer renderer : mClients) {
211 renderer.draw(canvas);
212 redraw = redraw || ((OverlayRenderer) renderer).isVisible();
213 }
214 if (redraw) {
215 invalidate();
216 }
217 }
218 }
219
220}