/* * 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(); } }