blob: ac47fbda09c61e97be44522d6f20a6e5f835b1f2 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.egg.paint;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.Magnifier;
import com.android.egg.R;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.IntStream;
public class PaintActivity extends Activity {
private static final float MAX_BRUSH_WIDTH_DP = 100f;
private static final float MIN_BRUSH_WIDTH_DP = 1f;
private static final int NUM_BRUSHES = 6;
private static final int NUM_COLORS = 6;
private Painting painting = null;
private CutoutAvoidingToolbar toolbar = null;
private LinearLayout brushes = null;
private LinearLayout colors = null;
private Magnifier magnifier = null;
private boolean sampling = false;
private View.OnClickListener buttonHandler = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnBrush:
view.setSelected(true);
hideToolbar(colors);
toggleToolbar(brushes);
break;
case R.id.btnColor:
view.setSelected(true);
hideToolbar(brushes);
toggleToolbar(colors);
break;
case R.id.btnClear:
painting.clear();
break;
case R.id.btnSample:
sampling = true;
view.setSelected(true);
break;
case R.id.btnZen:
painting.setZenMode(!painting.getZenMode());
view.animate()
.setStartDelay(200)
.setInterpolator(new OvershootInterpolator())
.rotation(painting.getZenMode() ? 0f : 90f);
break;
}
}
};
private void showToolbar(View bar) {
if (bar.getVisibility() != View.GONE) return;
bar.setVisibility(View.VISIBLE);
bar.setTranslationY(toolbar.getHeight()/2);
bar.animate()
.translationY(toolbar.getHeight())
.alpha(1f)
.setDuration(220)
.start();
}
private void hideToolbar(View bar) {
if (bar.getVisibility() != View.VISIBLE) return;
bar.animate()
.translationY(toolbar.getHeight()/2)
.alpha(0f)
.setDuration(150)
.withEndAction(new Runnable() {
@Override
public void run() {
bar.setVisibility(View.GONE);
}
})
.start();
}
private void toggleToolbar(View bar) {
if (bar.getVisibility() == View.VISIBLE) {
hideToolbar(bar);
} else {
showToolbar(bar);
}
}
private BrushPropertyDrawable widthButtonDrawable;
private BrushPropertyDrawable colorButtonDrawable;
private float maxBrushWidth, minBrushWidth;
private int nightMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
static final float lerp(float f, float a, float b) {
return a + (b-a) * f;
}
void setupViews(Painting oldPainting) {
setContentView(R.layout.activity_paint);
painting = oldPainting != null ? oldPainting : new Painting(this);
((FrameLayout) findViewById(R.id.contentView)).addView(painting,
new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
painting.setPaperColor(getColor(R.color.paper_color));
painting.setPaintColor(getColor(R.color.paint_color));
toolbar = findViewById(R.id.toolbar);
brushes = findViewById(R.id.brushes);
colors = findViewById(R.id.colors);
magnifier = new Magnifier(painting);
painting.setOnTouchListener(
new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getActionMasked()) {
case ACTION_DOWN:
case ACTION_MOVE:
if (sampling) {
magnifier.show(event.getX(), event.getY());
colorButtonDrawable.setWellColor(
painting.sampleAt(event.getX(), event.getY()));
return true;
}
break;
case ACTION_CANCEL:
if (sampling) {
findViewById(R.id.btnSample).setSelected(false);
sampling = false;
magnifier.dismiss();
}
break;
case ACTION_UP:
if (sampling) {
findViewById(R.id.btnSample).setSelected(false);
sampling = false;
magnifier.dismiss();
painting.setPaintColor(
painting.sampleAt(event.getX(), event.getY()));
refreshBrushAndColor();
}
break;
}
return false; // allow view to continue handling
}
});
findViewById(R.id.btnBrush).setOnClickListener(buttonHandler);
findViewById(R.id.btnColor).setOnClickListener(buttonHandler);
findViewById(R.id.btnClear).setOnClickListener(buttonHandler);
findViewById(R.id.btnSample).setOnClickListener(buttonHandler);
findViewById(R.id.btnZen).setOnClickListener(buttonHandler);
findViewById(R.id.btnColor).setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
colors.removeAllViews();
showToolbar(colors);
refreshBrushAndColor();
return true;
}
});
findViewById(R.id.btnClear).setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
painting.invertContents();
return true;
}
});
widthButtonDrawable = new BrushPropertyDrawable(this);
widthButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color));
colorButtonDrawable = new BrushPropertyDrawable(this);
colorButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color));
((ImageButton) findViewById(R.id.btnBrush)).setImageDrawable(widthButtonDrawable);
((ImageButton) findViewById(R.id.btnColor)).setImageDrawable(colorButtonDrawable);
refreshBrushAndColor();
}
private void refreshBrushAndColor() {
final LinearLayout.LayoutParams button_lp = new LinearLayout.LayoutParams(
0, ViewGroup.LayoutParams.WRAP_CONTENT);
button_lp.weight = 1f;
if (brushes.getChildCount() == 0) {
for (int i = 0; i < NUM_BRUSHES; i++) {
final BrushPropertyDrawable icon = new BrushPropertyDrawable(this);
icon.setFrameColor(getColor(R.color.toolbar_icon_color));
// exponentially increasing brush size
final float width = lerp(
(float) Math.pow((float) i / NUM_BRUSHES, 2f), minBrushWidth,
maxBrushWidth);
icon.setWellScale(width / maxBrushWidth);
icon.setWellColor(getColor(R.color.toolbar_icon_color));
final ImageButton button = new ImageButton(this);
button.setImageDrawable(icon);
button.setBackground(getDrawable(R.drawable.toolbar_button_bg));
button.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
brushes.setSelected(false);
hideToolbar(brushes);
painting.setBrushWidth(width);
refreshBrushAndColor();
}
});
brushes.addView(button, button_lp);
}
}
if (colors.getChildCount() == 0) {
final Palette pal = new Palette(NUM_COLORS);
for (final int c : IntStream.concat(
IntStream.of(Color.BLACK, Color.WHITE),
Arrays.stream(pal.getColors())
).toArray()) {
final BrushPropertyDrawable icon = new BrushPropertyDrawable(this);
icon.setFrameColor(getColor(R.color.toolbar_icon_color));
icon.setWellColor(c);
final ImageButton button = new ImageButton(this);
button.setImageDrawable(icon);
button.setBackground(getDrawable(R.drawable.toolbar_button_bg));
button.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
colors.setSelected(false);
hideToolbar(colors);
painting.setPaintColor(c);
refreshBrushAndColor();
}
});
colors.addView(button, button_lp);
}
}
widthButtonDrawable.setWellScale(painting.getBrushWidth() / maxBrushWidth);
widthButtonDrawable.setWellColor(painting.getPaintColor());
colorButtonDrawable.setWellColor(painting.getPaintColor());
}
private void refreshNightMode(Configuration config) {
int newNightMode =
(config.uiMode & Configuration.UI_MODE_NIGHT_MASK);
if (nightMode != newNightMode) {
if (nightMode != Configuration.UI_MODE_NIGHT_UNDEFINED) {
painting.invertContents();
((ViewGroup) painting.getParent()).removeView(painting);
setupViews(painting);
final View decorView = getWindow().getDecorView();
int decorSUIV = decorView.getSystemUiVisibility();
if (newNightMode == Configuration.UI_MODE_NIGHT_YES) {
decorView.setSystemUiVisibility(
decorSUIV & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
} else {
decorView.setSystemUiVisibility(
decorSUIV | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
}
}
nightMode = newNightMode;
}
}
public PaintActivity() {
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
painting.onTrimMemory();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
refreshNightMode(newConfig);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.flags = lp.flags
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
getWindow().setAttributes(lp);
maxBrushWidth = MAX_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density;
minBrushWidth = MIN_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density;
setupViews(null);
refreshNightMode(getResources().getConfiguration());
}
@Override
public void onPostResume() {
super.onPostResume();
}
}