blob: ac47fbda09c61e97be44522d6f20a6e5f835b1f2 [file] [log] [blame]
Dan Sandler45f17c52018-05-02 20:01:38 -04001/*
2 * Copyright (C) 2018 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.egg.paint;
18
19import static android.view.MotionEvent.ACTION_CANCEL;
20import static android.view.MotionEvent.ACTION_DOWN;
21import static android.view.MotionEvent.ACTION_MOVE;
22import static android.view.MotionEvent.ACTION_UP;
23
24import android.app.Activity;
25import android.content.res.Configuration;
26import android.graphics.Bitmap;
27import android.graphics.Color;
28import android.os.Bundle;
29import android.view.MotionEvent;
30import android.view.View;
31import android.view.ViewGroup;
32import android.view.WindowManager;
33import android.view.animation.OvershootInterpolator;
34import android.widget.FrameLayout;
35import android.widget.ImageButton;
36import android.widget.LinearLayout;
37import android.widget.Magnifier;
38
39import com.android.egg.R;
40
41import java.util.ArrayList;
42import java.util.Arrays;
43import java.util.Collections;
44import java.util.stream.IntStream;
45
46public class PaintActivity extends Activity {
47 private static final float MAX_BRUSH_WIDTH_DP = 100f;
48 private static final float MIN_BRUSH_WIDTH_DP = 1f;
49
50 private static final int NUM_BRUSHES = 6;
51 private static final int NUM_COLORS = 6;
52
53 private Painting painting = null;
54 private CutoutAvoidingToolbar toolbar = null;
55 private LinearLayout brushes = null;
56 private LinearLayout colors = null;
57 private Magnifier magnifier = null;
58 private boolean sampling = false;
59
60 private View.OnClickListener buttonHandler = new View.OnClickListener() {
61 @Override
62 public void onClick(View view) {
63 switch (view.getId()) {
64 case R.id.btnBrush:
65 view.setSelected(true);
66 hideToolbar(colors);
67 toggleToolbar(brushes);
68 break;
69 case R.id.btnColor:
70 view.setSelected(true);
71 hideToolbar(brushes);
72 toggleToolbar(colors);
73 break;
74 case R.id.btnClear:
75 painting.clear();
76 break;
77 case R.id.btnSample:
78 sampling = true;
79 view.setSelected(true);
80 break;
81 case R.id.btnZen:
82 painting.setZenMode(!painting.getZenMode());
83 view.animate()
84 .setStartDelay(200)
85 .setInterpolator(new OvershootInterpolator())
86 .rotation(painting.getZenMode() ? 0f : 90f);
87 break;
88 }
89 }
90 };
91
92 private void showToolbar(View bar) {
93 if (bar.getVisibility() != View.GONE) return;
94 bar.setVisibility(View.VISIBLE);
95 bar.setTranslationY(toolbar.getHeight()/2);
96 bar.animate()
97 .translationY(toolbar.getHeight())
98 .alpha(1f)
99 .setDuration(220)
100 .start();
101 }
102
103 private void hideToolbar(View bar) {
104 if (bar.getVisibility() != View.VISIBLE) return;
105 bar.animate()
106 .translationY(toolbar.getHeight()/2)
107 .alpha(0f)
108 .setDuration(150)
109 .withEndAction(new Runnable() {
110 @Override
111 public void run() {
112 bar.setVisibility(View.GONE);
113 }
114 })
115 .start();
116 }
117
118 private void toggleToolbar(View bar) {
119 if (bar.getVisibility() == View.VISIBLE) {
120 hideToolbar(bar);
121 } else {
122 showToolbar(bar);
123 }
124 }
125
126 private BrushPropertyDrawable widthButtonDrawable;
127 private BrushPropertyDrawable colorButtonDrawable;
128 private float maxBrushWidth, minBrushWidth;
129 private int nightMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
130
131 static final float lerp(float f, float a, float b) {
132 return a + (b-a) * f;
133 }
134
135 void setupViews(Painting oldPainting) {
136 setContentView(R.layout.activity_paint);
137
138 painting = oldPainting != null ? oldPainting : new Painting(this);
139 ((FrameLayout) findViewById(R.id.contentView)).addView(painting,
140 new FrameLayout.LayoutParams(
141 ViewGroup.LayoutParams.MATCH_PARENT,
142 ViewGroup.LayoutParams.MATCH_PARENT));
143
144 painting.setPaperColor(getColor(R.color.paper_color));
145 painting.setPaintColor(getColor(R.color.paint_color));
146
147 toolbar = findViewById(R.id.toolbar);
148 brushes = findViewById(R.id.brushes);
149 colors = findViewById(R.id.colors);
150
151 magnifier = new Magnifier(painting);
152
153 painting.setOnTouchListener(
154 new View.OnTouchListener() {
155 @Override
156 public boolean onTouch(View view, MotionEvent event) {
157 switch (event.getActionMasked()) {
158 case ACTION_DOWN:
159 case ACTION_MOVE:
160 if (sampling) {
161 magnifier.show(event.getX(), event.getY());
162 colorButtonDrawable.setWellColor(
163 painting.sampleAt(event.getX(), event.getY()));
164 return true;
165 }
166 break;
167 case ACTION_CANCEL:
168 if (sampling) {
169 findViewById(R.id.btnSample).setSelected(false);
170 sampling = false;
171 magnifier.dismiss();
172 }
173 break;
174 case ACTION_UP:
175 if (sampling) {
176 findViewById(R.id.btnSample).setSelected(false);
177 sampling = false;
178 magnifier.dismiss();
179 painting.setPaintColor(
180 painting.sampleAt(event.getX(), event.getY()));
181 refreshBrushAndColor();
182 }
183 break;
184 }
185 return false; // allow view to continue handling
186 }
187 });
188
189 findViewById(R.id.btnBrush).setOnClickListener(buttonHandler);
190 findViewById(R.id.btnColor).setOnClickListener(buttonHandler);
191 findViewById(R.id.btnClear).setOnClickListener(buttonHandler);
192 findViewById(R.id.btnSample).setOnClickListener(buttonHandler);
193 findViewById(R.id.btnZen).setOnClickListener(buttonHandler);
194
195 findViewById(R.id.btnColor).setOnLongClickListener(new View.OnLongClickListener() {
196 @Override
197 public boolean onLongClick(View view) {
198 colors.removeAllViews();
199 showToolbar(colors);
200 refreshBrushAndColor();
201 return true;
202 }
203 });
204
205 findViewById(R.id.btnClear).setOnLongClickListener(new View.OnLongClickListener() {
206 @Override
207 public boolean onLongClick(View view) {
208 painting.invertContents();
209 return true;
210 }
211 });
212
213 widthButtonDrawable = new BrushPropertyDrawable(this);
214 widthButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color));
215 colorButtonDrawable = new BrushPropertyDrawable(this);
216 colorButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color));
217
218 ((ImageButton) findViewById(R.id.btnBrush)).setImageDrawable(widthButtonDrawable);
219 ((ImageButton) findViewById(R.id.btnColor)).setImageDrawable(colorButtonDrawable);
220
221 refreshBrushAndColor();
222 }
223
224 private void refreshBrushAndColor() {
225 final LinearLayout.LayoutParams button_lp = new LinearLayout.LayoutParams(
226 0, ViewGroup.LayoutParams.WRAP_CONTENT);
227 button_lp.weight = 1f;
228 if (brushes.getChildCount() == 0) {
229 for (int i = 0; i < NUM_BRUSHES; i++) {
230 final BrushPropertyDrawable icon = new BrushPropertyDrawable(this);
231 icon.setFrameColor(getColor(R.color.toolbar_icon_color));
232 // exponentially increasing brush size
233 final float width = lerp(
234 (float) Math.pow((float) i / NUM_BRUSHES, 2f), minBrushWidth,
235 maxBrushWidth);
236 icon.setWellScale(width / maxBrushWidth);
237 icon.setWellColor(getColor(R.color.toolbar_icon_color));
238 final ImageButton button = new ImageButton(this);
239 button.setImageDrawable(icon);
240 button.setBackground(getDrawable(R.drawable.toolbar_button_bg));
241 button.setOnClickListener(
242 new View.OnClickListener() {
243 @Override
244 public void onClick(View view) {
245 brushes.setSelected(false);
246 hideToolbar(brushes);
247 painting.setBrushWidth(width);
248 refreshBrushAndColor();
249 }
250 });
251 brushes.addView(button, button_lp);
252 }
253 }
254
255 if (colors.getChildCount() == 0) {
256 final Palette pal = new Palette(NUM_COLORS);
257 for (final int c : IntStream.concat(
258 IntStream.of(Color.BLACK, Color.WHITE),
259 Arrays.stream(pal.getColors())
260 ).toArray()) {
261 final BrushPropertyDrawable icon = new BrushPropertyDrawable(this);
262 icon.setFrameColor(getColor(R.color.toolbar_icon_color));
263 icon.setWellColor(c);
264 final ImageButton button = new ImageButton(this);
265 button.setImageDrawable(icon);
266 button.setBackground(getDrawable(R.drawable.toolbar_button_bg));
267 button.setOnClickListener(
268 new View.OnClickListener() {
269 @Override
270 public void onClick(View view) {
271 colors.setSelected(false);
272 hideToolbar(colors);
273 painting.setPaintColor(c);
274 refreshBrushAndColor();
275 }
276 });
277 colors.addView(button, button_lp);
278 }
279 }
280
281 widthButtonDrawable.setWellScale(painting.getBrushWidth() / maxBrushWidth);
282 widthButtonDrawable.setWellColor(painting.getPaintColor());
283 colorButtonDrawable.setWellColor(painting.getPaintColor());
284 }
285
286 private void refreshNightMode(Configuration config) {
287 int newNightMode =
288 (config.uiMode & Configuration.UI_MODE_NIGHT_MASK);
289 if (nightMode != newNightMode) {
290 if (nightMode != Configuration.UI_MODE_NIGHT_UNDEFINED) {
291 painting.invertContents();
292
293 ((ViewGroup) painting.getParent()).removeView(painting);
294 setupViews(painting);
295
296 final View decorView = getWindow().getDecorView();
297 int decorSUIV = decorView.getSystemUiVisibility();
298
299 if (newNightMode == Configuration.UI_MODE_NIGHT_YES) {
300 decorView.setSystemUiVisibility(
301 decorSUIV & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
302 } else {
303 decorView.setSystemUiVisibility(
304 decorSUIV | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
305 }
306 }
307 nightMode = newNightMode;
308 }
309 }
310
311 public PaintActivity() {
312
313 }
314
315 @Override
316 public void onTrimMemory(int level) {
317 super.onTrimMemory(level);
318
319 painting.onTrimMemory();
320 }
321
322 @Override
323 public void onConfigurationChanged(Configuration newConfig) {
324 super.onConfigurationChanged(newConfig);
325
326 refreshNightMode(newConfig);
327 }
328
329 @Override
330 public void onCreate(Bundle savedInstanceState) {
331 super.onCreate(savedInstanceState);
332
333 WindowManager.LayoutParams lp = getWindow().getAttributes();
334 lp.flags = lp.flags
335 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
336 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
337 getWindow().setAttributes(lp);
338
339 maxBrushWidth = MAX_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density;
340 minBrushWidth = MIN_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density;
341
342 setupViews(null);
343 refreshNightMode(getResources().getConfiguration());
344 }
345
346 @Override
347 public void onPostResume() {
348 super.onPostResume();
349 }
350
351}