Commit af6964e60d5f6f874247a7e8b6a26b738c30ec71

Authored by Edmur LOPES
0 parents

create new git

Showing 329 changed files with 6653 additions and 0 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 329 files are displayed.

.gitignore 0 → 100644
  1 +++ a/.gitignore
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +*.iml
  2 +.gradle
  3 +/local.properties
  4 +/.idea/workspace.xml
  5 +/.idea/libraries
  6 +.DS_Store
  7 +/build
  8 +/captures
  9 +.externalNativeBuild
.idea/compiler.xml 0 → 100644
  1 +++ a/.idea/compiler.xml
@@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="CompilerConfiguration">
  4 + <resourceExtensions />
  5 + <wildcardResourcePatterns>
  6 + <entry name="!?*.java" />
  7 + <entry name="!?*.form" />
  8 + <entry name="!?*.class" />
  9 + <entry name="!?*.groovy" />
  10 + <entry name="!?*.scala" />
  11 + <entry name="!?*.flex" />
  12 + <entry name="!?*.kt" />
  13 + <entry name="!?*.clj" />
  14 + <entry name="!?*.aj" />
  15 + </wildcardResourcePatterns>
  16 + <annotationProcessing>
  17 + <profile default="true" name="Default" enabled="false">
  18 + <processorPath useClasspath="true" />
  19 + </profile>
  20 + </annotationProcessing>
  21 + </component>
  22 +</project>
0 \ No newline at end of file 23 \ No newline at end of file
.idea/copyright/profiles_settings.xml 0 → 100644
  1 +++ a/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<component name="CopyrightManager">
  2 + <settings default="" />
  3 +</component>
0 \ No newline at end of file 4 \ No newline at end of file
.idea/gradle.xml 0 → 100644
  1 +++ a/.idea/gradle.xml
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="GradleSettings">
  4 + <option name="linkedExternalProjectsSettings">
  5 + <GradleProjectSettings>
  6 + <option name="distributionType" value="DEFAULT_WRAPPED" />
  7 + <option name="externalProjectPath" value="$PROJECT_DIR$" />
  8 + <option name="modules">
  9 + <set>
  10 + <option value="$PROJECT_DIR$" />
  11 + <option value="$PROJECT_DIR$/app" />
  12 + </set>
  13 + </option>
  14 + <option name="resolveModulePerSourceSet" value="false" />
  15 + </GradleProjectSettings>
  16 + </option>
  17 + </component>
  18 +</project>
0 \ No newline at end of file 19 \ No newline at end of file
.idea/markdown-navigator/profiles_settings.xml 0 → 100644
  1 +++ a/.idea/markdown-navigator/profiles_settings.xml
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<component name="MarkdownNavigator.ProfileManager">
  2 + <settings default="" pdf-export="" />
  3 +</component>
0 \ No newline at end of file 4 \ No newline at end of file
.idea/misc.xml 0 → 100644
  1 +++ a/.idea/misc.xml
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="EntryPointsManager">
  4 + <entry_points version="2.0" />
  5 + </component>
  6 + <component name="NullableNotNullManager">
  7 + <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
  8 + <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
  9 + <option name="myNullables">
  10 + <value>
  11 + <list size="4">
  12 + <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
  13 + <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
  14 + <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
  15 + <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
  16 + </list>
  17 + </value>
  18 + </option>
  19 + <option name="myNotNulls">
  20 + <value>
  21 + <list size="4">
  22 + <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
  23 + <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
  24 + <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
  25 + <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
  26 + </list>
  27 + </value>
  28 + </option>
  29 + </component>
  30 + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
  31 + <output url="file://$PROJECT_DIR$/build/classes" />
  32 + </component>
  33 + <component name="ProjectType">
  34 + <option name="id" value="Android" />
  35 + </component>
  36 +</project>
0 \ No newline at end of file 37 \ No newline at end of file
.idea/modules.xml 0 → 100644
  1 +++ a/.idea/modules.xml
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="ProjectModuleManager">
  4 + <modules>
  5 + <module fileurl="file://$PROJECT_DIR$/AUTRE.iml" filepath="$PROJECT_DIR$/AUTRE.iml" />
  6 + <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
  7 + </modules>
  8 + </component>
  9 +</project>
0 \ No newline at end of file 10 \ No newline at end of file
.idea/runConfigurations.xml 0 → 100644
  1 +++ a/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="RunConfigurationProducerService">
  4 + <option name="ignoredProducers">
  5 + <set>
  6 + <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
  7 + <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
  8 + <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
  9 + </set>
  10 + </option>
  11 + </component>
  12 +</project>
0 \ No newline at end of file 13 \ No newline at end of file
acrylic/.gitignore 0 → 100644
  1 +++ a/acrylic/.gitignore
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/build
acrylic/build.gradle 0 → 100644
  1 +++ a/acrylic/build.gradle
@@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
  1 +apply plugin: 'com.android.application'
  2 +
  3 +android {
  4 + compileSdkVersion 25
  5 + buildToolsVersion "25.0.2"
  6 +
  7 + defaultConfig {
  8 + applicationId "anupam.acrylic"
  9 + minSdkVersion 15
  10 + targetSdkVersion 25
  11 + versionCode 1
  12 + versionName "1.0"
  13 +
  14 + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  15 +
  16 + }
  17 + buildTypes {
  18 + release {
  19 + minifyEnabled false
  20 + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  21 + }
  22 + }
  23 +}
  24 +
  25 +dependencies {
  26 + compile fileTree(dir: 'libs', include: ['*.jar'])
  27 + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
  28 + exclude group: 'com.android.support', module: 'support-annotations'
  29 + })
  30 + compile 'com.android.support:appcompat-v7:25.1.1'
  31 + testCompile 'junit:junit:4.12'
  32 +}
acrylic/proguard-rules.pro 0 → 100644
  1 +++ a/acrylic/proguard-rules.pro
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +# Add project specific ProGuard rules here.
  2 +# By default, the flags in this file are appended to flags specified
  3 +# in C:\Users\Edmur\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
  4 +# You can edit the include path and order by changing the proguardFiles
  5 +# directive in build.gradle.
  6 +#
  7 +# For more details, see
  8 +# http://developer.android.com/guide/developing/tools/proguard.html
  9 +
  10 +# Add any project specific keep options here:
  11 +
  12 +# If your project uses WebView with JS, uncomment the following
  13 +# and specify the fully qualified class name to the JavaScript interface
  14 +# class:
  15 +#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
  16 +# public *;
  17 +#}
acrylic/src/androidTest/java/anupam/acrylic/ExampleInstrumentedTest.java 0 → 100644
  1 +++ a/acrylic/src/androidTest/java/anupam/acrylic/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +package anupam.acrylic;
  2 +
  3 +import android.content.Context;
  4 +import android.support.test.InstrumentationRegistry;
  5 +import android.support.test.runner.AndroidJUnit4;
  6 +
  7 +import org.junit.Test;
  8 +import org.junit.runner.RunWith;
  9 +
  10 +import static org.junit.Assert.*;
  11 +
  12 +/**
  13 + * Instrumentation test, which will execute on an Android device.
  14 + *
  15 + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
  16 + */
  17 +@RunWith(AndroidJUnit4.class)
  18 +public class ExampleInstrumentedTest {
  19 + @Test
  20 + public void useAppContext() throws Exception {
  21 + // Context of the app under test.
  22 + Context appContext = InstrumentationRegistry.getTargetContext();
  23 +
  24 + assertEquals("anupam.acrylic", appContext.getPackageName());
  25 + }
  26 +}
acrylic/src/main/AndroidManifest.xml 0 → 100644
  1 +++ a/acrylic/src/main/AndroidManifest.xml
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3 + package="anupam.acrylic"
  4 + android:versionCode="15"
  5 + android:versionName="2.2.0" >
  6 +
  7 + <supports-screens
  8 + android:anyDensity="true"
  9 + android:largeScreens="true"
  10 + android:normalScreens="true"
  11 + android:resizeable="true"
  12 + android:smallScreens="true" />
  13 +
  14 + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  15 +
  16 + <application
  17 + android:allowBackup="true"
  18 + android:icon="@drawable/ic_launcher"
  19 + android:label="@string/app_name"
  20 + android:theme="@style/Theme" >
  21 + <activity
  22 + android:name=".Splash"
  23 + android:configChanges="keyboard|keyboardHidden|orientation"
  24 + android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen" >
  25 + <intent-filter>
  26 + <action android:name="android.intent.action.MAIN" />
  27 + <category android:name="android.intent.category.LAUNCHER" />
  28 + </intent-filter>
  29 + </activity>
  30 + <activity
  31 + android:name=".EasyPaint"
  32 + android:launchMode="singleTop" >
  33 + <intent-filter>
  34 + <action android:name="android.intent.action.SEND" />
  35 + <category android:name="android.intent.category.DEFAULT" />
  36 + <data android:mimeType="image/*" />
  37 + </intent-filter>
  38 + </activity>
  39 + <activity
  40 + android:name=".AboutActivity"
  41 + android:label="@string/title_activity_about"
  42 + android:parentActivityName=".EasyPaint" >
  43 + <meta-data
  44 + android:name="android.support.PARENT_ACTIVITY"
  45 + android:value=".EasyPaint" />
  46 + </activity>
  47 + </application>
  48 +
  49 +</manifest>
acrylic/src/main/java/anupam/acrylic/AboutActivity.java 0 → 100644
  1 +++ a/acrylic/src/main/java/anupam/acrylic/AboutActivity.java
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +package anupam.acrylic;
  2 +
  3 +import android.app.Activity;
  4 +import android.os.Bundle;
  5 +import android.text.Html;
  6 +import android.text.Spanned;
  7 +import android.text.method.LinkMovementMethod;
  8 +import android.widget.TextView;
  9 +
  10 +public class AboutActivity extends Activity {
  11 +
  12 + @Override
  13 + protected void onCreate(Bundle savedInstanceState) {
  14 + super.onCreate(savedInstanceState);
  15 + setContentView(R.layout.activity_about);
  16 + Spanned htmlText = Html.fromHtml(getResources().getString(R.string.about_description));
  17 + TextView aboutTextView = (TextView) findViewById(R.id.aboutTextView);
  18 + aboutTextView.setText(htmlText);
  19 + aboutTextView.setMovementMethod(LinkMovementMethod.getInstance());
  20 + }
  21 +}
acrylic/src/main/java/anupam/acrylic/ColorPickerDialog.java 0 → 100644
  1 +++ a/acrylic/src/main/java/anupam/acrylic/ColorPickerDialog.java
@@ -0,0 +1,242 @@ @@ -0,0 +1,242 @@
  1 +/*
  2 + * Copyright (C) 2014 Valerio Bozzolan
  3 + *
  4 + * This program is free software: you can redistribute it and/or modify
  5 + * it under the terms of the GNU General Public License as published by
  6 + * the Free Software Foundation, either version 3 of the License, or
  7 + * (at your option) any later version.
  8 + *
  9 + * This program is distributed in the hope that it will be useful,
  10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 + * GNU General Public License for more details.
  13 + *
  14 + * You should have received a copy of the GNU General Public License
  15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 +*/
  17 +
  18 +package anupam.acrylic;
  19 +
  20 +import android.annotation.SuppressLint;
  21 +import android.app.Dialog;
  22 +import android.content.Context;
  23 +import android.graphics.Canvas;
  24 +import android.graphics.Color;
  25 +import android.graphics.ColorMatrix;
  26 +import android.graphics.Paint;
  27 +import android.graphics.RectF;
  28 +import android.graphics.Shader;
  29 +import android.graphics.SweepGradient;
  30 +import android.os.Bundle;
  31 +import android.view.MotionEvent;
  32 +import android.view.View;
  33 +
  34 +@SuppressLint("ClickableViewAccessibility")
  35 +public class ColorPickerDialog extends Dialog {
  36 +
  37 + private OnColorChangedListener mListener;
  38 + private int mInitialColor;
  39 +
  40 + @Override
  41 + protected void onCreate(Bundle savedInstanceState) {
  42 + super.onCreate(savedInstanceState);
  43 + OnColorChangedListener l = new OnColorChangedListener() {
  44 + public void colorChanged(int color) {
  45 + mListener.colorChanged(color);
  46 + dismiss();
  47 + }
  48 + };
  49 +
  50 + setContentView(new ColorPickerView(getContext(), l, mInitialColor));
  51 + setTitle(R.string.pick_color);
  52 + }
  53 +
  54 + public interface OnColorChangedListener {
  55 + void colorChanged(int color);
  56 + }
  57 +
  58 + private static class ColorPickerView extends View {
  59 + private static final int CENTER_X = 230;
  60 + private static final int CENTER_Y = 230;
  61 + private static final int CENTER_RADIUS = 100;
  62 + private Paint mPaint;
  63 + private Paint mCenterPaint;
  64 + private final int[] mColors;
  65 + private OnColorChangedListener mListener;
  66 + private boolean mTrackingCenter;
  67 + private boolean mHighlightCenter;
  68 +
  69 + ColorPickerView(Context c, OnColorChangedListener l, int color) {
  70 + super(c);
  71 + mListener = l;
  72 + mColors = new int[] {
  73 + 0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
  74 + 0xFFFFFF00, 0xFFFF0000
  75 + };
  76 + Shader s = new SweepGradient(0, 0, mColors, null);
  77 +
  78 + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  79 + mPaint.setShader(s);
  80 + mPaint.setStyle(Paint.Style.STROKE);
  81 + mPaint.setStrokeWidth(32);
  82 +
  83 + mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  84 + mCenterPaint.setColor(color);
  85 + mCenterPaint.setStrokeWidth(EasyPaint.DEFAULT_BRUSH_SIZE);
  86 + }
  87 +
  88 + @Override
  89 + protected void onDraw(Canvas canvas) {
  90 +
  91 + float r = CENTER_X - mPaint.getStrokeWidth()*0.5f - 30;
  92 +
  93 + canvas.translate(CENTER_X, CENTER_X);
  94 +
  95 + canvas.drawOval(new RectF(-r, -r, r, r), mPaint);
  96 + canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint);
  97 +
  98 + if (mTrackingCenter) {
  99 + int c = mCenterPaint.getColor();
  100 + mCenterPaint.setStyle(Paint.Style.STROKE);
  101 +
  102 + if (mHighlightCenter) {
  103 + mCenterPaint.setAlpha(0xFF);
  104 + } else {
  105 + mCenterPaint.setAlpha(0x80);
  106 + }
  107 + canvas.drawCircle(0, 0,
  108 + CENTER_RADIUS + mCenterPaint.getStrokeWidth(),
  109 + mCenterPaint);
  110 +
  111 + mCenterPaint.setStyle(Paint.Style.FILL);
  112 + mCenterPaint.setColor(c);
  113 + }
  114 + }
  115 +
  116 + @Override
  117 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  118 + setMeasuredDimension(CENTER_X*2, CENTER_Y*2);
  119 + }
  120 +
  121 + private int floatToByte(float x) {
  122 + int n = java.lang.Math.round(x);
  123 + return n;
  124 + }
  125 + private int pinToByte(int n) {
  126 + if (n < 0) {
  127 + n = 0;
  128 + } else if (n > 255) {
  129 + n = 255;
  130 + }
  131 + return n;
  132 + }
  133 +
  134 + private int ave(int s, int d, float p) {
  135 + return s + java.lang.Math.round(p * (d - s));
  136 + }
  137 +
  138 + private int interpColor(int colors[], float unit) {
  139 + if (unit <= 0) {
  140 + return colors[0];
  141 + }
  142 + if (unit >= 1) {
  143 + return colors[colors.length - 1];
  144 + }
  145 +
  146 + float p = unit * (colors.length - 1);
  147 + int i = (int)p;
  148 + p -= i;
  149 +
  150 + // now p is just the fractional part [0...1) and i is the index
  151 + int c0 = colors[i];
  152 + int c1 = colors[i+1];
  153 + int a = ave(Color.alpha(c0), Color.alpha(c1), p);
  154 + int r = ave(Color.red(c0), Color.red(c1), p);
  155 + int g = ave(Color.green(c0), Color.green(c1), p);
  156 + int b = ave(Color.blue(c0), Color.blue(c1), p);
  157 +
  158 + return Color.argb(a, r, g, b);
  159 + }
  160 +
  161 + @SuppressWarnings("unused")
  162 + private int rotateColor(int color, float rad) {
  163 + float deg = rad * 180 / 3.1415927f;
  164 + int r = Color.red(color);
  165 + int g = Color.green(color);
  166 + int b = Color.blue(color);
  167 +
  168 + ColorMatrix cm = new ColorMatrix();
  169 + ColorMatrix tmp = new ColorMatrix();
  170 +
  171 + cm.setRGB2YUV();
  172 + tmp.setRotate(0, deg);
  173 + cm.postConcat(tmp);
  174 + tmp.setYUV2RGB();
  175 + cm.postConcat(tmp);
  176 +
  177 + final float[] a = cm.getArray();
  178 +
  179 + int ir = floatToByte(a[0] * r + a[1] * g + a[2] * b);
  180 + int ig = floatToByte(a[5] * r + a[6] * g + a[7] * b);
  181 + int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b);
  182 +
  183 + return Color.argb(Color.alpha(color), pinToByte(ir),
  184 + pinToByte(ig), pinToByte(ib));
  185 + }
  186 +
  187 + private static final float PI = 3.1415926f;
  188 +
  189 + @Override
  190 + public boolean onTouchEvent(MotionEvent event) {
  191 + float x = event.getX() - CENTER_X;
  192 + float y = event.getY() - CENTER_Y;
  193 + boolean inCenter = java.lang.Math.sqrt(x*x + y*y) <= CENTER_RADIUS;
  194 +
  195 + switch (event.getAction()) {
  196 + case MotionEvent.ACTION_DOWN:
  197 + mTrackingCenter = inCenter;
  198 + if (inCenter) {
  199 + mHighlightCenter = true;
  200 + invalidate();
  201 + break;
  202 + }
  203 + case MotionEvent.ACTION_MOVE:
  204 + if (mTrackingCenter) {
  205 + if (mHighlightCenter != inCenter) {
  206 + mHighlightCenter = inCenter;
  207 + invalidate();
  208 + }
  209 + } else {
  210 + float angle = (float)java.lang.Math.atan2(y, x);
  211 + // need to turn angle [-PI ... PI] into unit [0....1]
  212 + float unit = angle/(2*PI);
  213 + if (unit < 0) {
  214 + unit += 1;
  215 + }
  216 + mCenterPaint.setColor(interpColor(mColors, unit));
  217 + invalidate();
  218 + }
  219 + break;
  220 + case MotionEvent.ACTION_UP:
  221 + if (mTrackingCenter) {
  222 + if (inCenter) {
  223 + mListener.colorChanged(mCenterPaint.getColor());
  224 + }
  225 + mTrackingCenter = false; // so we draw w/o halo
  226 + invalidate();
  227 + }
  228 + break;
  229 + }
  230 + return true;
  231 + }
  232 + }
  233 +
  234 + public ColorPickerDialog(Context context,
  235 + OnColorChangedListener listener,
  236 + int initialColor) {
  237 + super(context);
  238 +
  239 + mListener = listener;
  240 + mInitialColor = initialColor;
  241 + }
  242 +}
acrylic/src/main/java/anupam/acrylic/EasyPaint.java 0 → 100644
  1 +++ a/acrylic/src/main/java/anupam/acrylic/EasyPaint.java
@@ -0,0 +1,593 @@ @@ -0,0 +1,593 @@
  1 +/*
  2 + * Copyright (C) 2014, 2016 Valerio Bozzolan & James Dearing (TheOpenSourceNinja)
  3 + *
  4 + * This program is free software: you can redistribute it and/or modify
  5 + * it under the terms of the GNU General Public License as published by
  6 + * the Free Software Foundation, either version 3 of the License, or
  7 + * (at your option) any later version.
  8 + *
  9 + * This program is distributed in the hope that it will be useful,
  10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 + * GNU General Public License for more details.
  13 + *
  14 + * You should have received a copy of the GNU General Public License
  15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 + */
  17 +
  18 +package anupam.acrylic;
  19 +
  20 +import java.io.File;
  21 +import java.io.FileNotFoundException;
  22 +import java.io.FileOutputStream;
  23 +import java.io.IOException;
  24 +import java.util.Calendar;
  25 +import android.annotation.SuppressLint;
  26 +import android.app.AlertDialog;
  27 +import android.content.Context;
  28 +import android.content.DialogInterface;
  29 +import android.content.Intent;
  30 +import android.content.SharedPreferences;
  31 +import android.content.pm.ActivityInfo;
  32 +import android.graphics.Bitmap;
  33 +import android.graphics.Bitmap.CompressFormat;
  34 +import android.graphics.BitmapShader;
  35 +import android.graphics.BlurMaskFilter;
  36 +import android.graphics.Canvas;
  37 +import android.graphics.Color;
  38 +import android.graphics.EmbossMaskFilter;
  39 +import android.graphics.MaskFilter;
  40 +import android.graphics.Paint;
  41 +import android.graphics.Path;
  42 +import android.graphics.Point;
  43 +import android.graphics.PorterDuff.Mode;
  44 +import android.graphics.PorterDuffXfermode;
  45 +import android.graphics.PorterDuffColorFilter;
  46 +import android.graphics.Shader;
  47 +import android.net.Uri;
  48 +import android.os.Build;
  49 +import android.os.Bundle;
  50 +import android.os.Handler;
  51 +import android.provider.MediaStore;
  52 +import android.renderscript.Allocation;
  53 +import android.renderscript.Element;
  54 +import android.renderscript.RenderScript;
  55 +import android.renderscript.ScriptIntrinsicBlur;
  56 +import android.util.Log;
  57 +import android.view.Display;
  58 +import android.view.LayoutInflater;
  59 +import android.view.Menu;
  60 +import android.view.MenuItem;
  61 +import android.view.MotionEvent;
  62 +import android.view.View;
  63 +import android.view.ViewGroup;
  64 +import android.widget.SeekBar;
  65 +import android.widget.TextView;
  66 +import android.widget.Toast;
  67 +
  68 +@SuppressLint("ClickableViewAccessibility")
  69 +public class EasyPaint extends GraphicsActivity implements
  70 + ColorPickerDialog.OnColorChangedListener {
  71 +
  72 + public static int DEFAULT_BRUSH_SIZE = 10;
  73 + private static int MAX_POINTERS = 10;
  74 + private static final float TOUCH_TOLERANCE = 4;
  75 +
  76 + private Paint mPaint;
  77 + private MaskFilter mEmboss;
  78 + private MaskFilter mBlur;
  79 + private static final int CHOOSE_IMAGE = 0;
  80 + private MyView contentView;
  81 +
  82 + private boolean waitingForBackgroundColor = false; //If true and colorChanged() is called, fill the background, else mPaint.setColor()
  83 + private boolean extractingColor = false; //If this is true, the next touch event should extract a color rather than drawing a line.
  84 +
  85 + @Override
  86 + protected void onCreate(Bundle savedInstanceState) {
  87 + super.onCreate(savedInstanceState);
  88 +
  89 + // it removes the title from the actionbar(more space for icons?)
  90 + this.getActionBar().setDisplayShowTitleEnabled(false);
  91 +
  92 + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  93 + contentView = new MyView( this );
  94 + setContentView( contentView );
  95 +
  96 + mPaint = new Paint();
  97 + mPaint.setAntiAlias(true);
  98 + mPaint.setDither(true);
  99 + mPaint.setColor(Color.GREEN);
  100 + mPaint.setStyle(Paint.Style.STROKE);
  101 + mPaint.setStrokeJoin(Paint.Join.ROUND);
  102 + mPaint.setStrokeCap(Paint.Cap.ROUND);
  103 + mPaint.setStrokeWidth(DEFAULT_BRUSH_SIZE);
  104 +
  105 + // Where did these magic numbers come from? What do they mean? Can I change them? ~TheOpenSourceNinja
  106 + // Absolutely random numbers in order to see the emboss. asd! ~Valerio
  107 + mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
  108 +
  109 + mBlur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);
  110 +
  111 + if (isFirstTime()) {
  112 + AlertDialog.Builder alert = new AlertDialog.Builder(this);
  113 +
  114 + alert.setTitle(R.string.app_name);
  115 + alert.setMessage(R.string.app_description);
  116 + alert.setNegativeButton(R.string.continue_fuck,
  117 + new DialogInterface.OnClickListener() {
  118 + public void onClick(DialogInterface dialog,
  119 + int whichButton) {
  120 + Toast.makeText(getApplicationContext(),
  121 + R.string.here_is_your_canvas,
  122 + Toast.LENGTH_SHORT).show();
  123 + }
  124 + });
  125 +
  126 + alert.show();
  127 + } else {
  128 + Toast.makeText(getApplicationContext(),
  129 + R.string.here_is_your_canvas, Toast.LENGTH_SHORT).show();
  130 + }
  131 +
  132 + loadFromIntents();
  133 + }
  134 +
  135 + @Override
  136 + public void onBackPressed() {
  137 +
  138 + super.onBackPressed();
  139 + return;
  140 + }
  141 + public void colorChanged(int color) {
  142 + if( waitingForBackgroundColor ) {
  143 + waitingForBackgroundColor = false;
  144 + contentView.mBitmapBackground.eraseColor( color );
  145 + //int[] colors = new int[ 1 ];
  146 + //colors[ 0 ] = color;
  147 + //contentView.mBitmapBackground = Bitmap.createBitmap( colors, contentView.mBitmapBackground.getWidth(), contentView.mBitmapBackground.getHeight(), contentView.mBitmapBackground.getConfig() );
  148 + } else {
  149 + mPaint.setColor( color );
  150 + }
  151 + }
  152 +
  153 + public class MyView extends View {
  154 +
  155 + public Bitmap mBitmap;
  156 + private Bitmap mBitmapBackground;
  157 + private Canvas mCanvas;
  158 + private Paint mBitmapPaint;
  159 + private MultiLinePathManager multiLinePathManager;
  160 +
  161 + private class LinePath extends Path {
  162 + private Integer idPointer;
  163 + private float lastX;
  164 + private float lastY;
  165 +
  166 + LinePath() {
  167 + this.idPointer = null;
  168 + }
  169 +
  170 + public float getLastX() {
  171 + return lastX;
  172 + }
  173 +
  174 + public float getLastY() {
  175 + return lastY;
  176 + }
  177 +
  178 + public void touchStart(float x, float y) {
  179 + this.reset();
  180 + this.moveTo(x, y);
  181 + this.lastX = x;
  182 + this.lastY = y;
  183 + }
  184 +
  185 + public void touchMove(float x, float y) {
  186 + float dx = Math.abs(x - lastX);
  187 + float dy = Math.abs(y - lastY);
  188 + if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
  189 + this.quadTo(lastX, lastY, (x + lastX) / 2, (y + lastY) / 2);
  190 + lastX = x;
  191 + lastY = y;
  192 + }
  193 + }
  194 +
  195 + public boolean isDisassociatedFromPointer() {
  196 + return idPointer == null;
  197 + }
  198 +
  199 + public boolean isAssociatedToPointer(int idPointer) {
  200 + return this.idPointer != null
  201 + && (int) this.idPointer == idPointer;
  202 + }
  203 +
  204 + public void disassociateFromPointer() {
  205 + idPointer = null;
  206 + }
  207 +
  208 + public void associateToPointer(int idPointer) {
  209 + this.idPointer = idPointer;
  210 + }
  211 + }
  212 +
  213 + private class MultiLinePathManager {
  214 + public LinePath[] superMultiPaths;
  215 +
  216 + MultiLinePathManager(int maxPointers) {
  217 + superMultiPaths = new LinePath[maxPointers];
  218 + for (int i = 0; i < maxPointers; i++) {
  219 + superMultiPaths[i] = new LinePath();
  220 + }
  221 + }
  222 +
  223 + public LinePath findLinePathFromPointer(int idPointer) {
  224 + for (LinePath superMultiPath : superMultiPaths) {
  225 + if (superMultiPath.isAssociatedToPointer(idPointer)) {
  226 + return superMultiPath;
  227 + }
  228 + }
  229 + return null;
  230 + }
  231 +
  232 + public LinePath addLinePathWithPointer(int idPointer) {
  233 + for (LinePath superMultiPath : superMultiPaths) {
  234 + if (superMultiPath.isDisassociatedFromPointer()) {
  235 + superMultiPath.associateToPointer(idPointer);
  236 + return superMultiPath;
  237 + }
  238 + }
  239 + return null;
  240 + }
  241 + }
  242 +
  243 + public MyView(Context c) {
  244 + super(c);
  245 +
  246 + setId(R.id.CanvasId);
  247 + Display display = getWindowManager().getDefaultDisplay();
  248 + Point size = new Point();
  249 + display.getSize(size);
  250 + mBitmapBackground = Bitmap.createBitmap(size.x, size.y, Bitmap.Config.ARGB_8888);
  251 + mBitmap = Bitmap.createBitmap(size.x, size.y,
  252 + Bitmap.Config.ARGB_8888);
  253 + mCanvas = new Canvas(mBitmap);
  254 + mBitmapPaint = new Paint(Paint.DITHER_FLAG);
  255 + multiLinePathManager = new MultiLinePathManager(MAX_POINTERS);
  256 + }
  257 +
  258 + @Override
  259 + protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  260 + super.onSizeChanged(w, h, oldw, oldh);
  261 + }
  262 +
  263 + @Override
  264 + protected void onDraw(Canvas canvas) {
  265 + canvas.drawColor(0xFFFFFFFF);
  266 + canvas.drawBitmap( mBitmapBackground, 0, 0, new Paint() );
  267 + canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint );
  268 + for (int i = 0; i < multiLinePathManager.superMultiPaths.length; i++) {
  269 + canvas.drawPath(multiLinePathManager.superMultiPaths[i], mPaint);
  270 + }
  271 + }
  272 +
  273 + @Override
  274 + public boolean onTouchEvent(MotionEvent event) {
  275 + LinePath linePath;
  276 + int index;
  277 + int id;
  278 + int eventMasked = event.getActionMasked();
  279 + switch (eventMasked) {
  280 + case MotionEvent.ACTION_DOWN:
  281 + case MotionEvent.ACTION_POINTER_DOWN: {
  282 + index = event.getActionIndex( );
  283 + id = event.getPointerId( index );
  284 +
  285 + if( extractingColor ) { //If the user chose the 'extract color' menu option, the touch event indicates where they want to extract the color from.
  286 + extractingColor = false;
  287 +
  288 + View v = findViewById(R.id.CanvasId);
  289 + v.setDrawingCacheEnabled(true);
  290 + Bitmap cachedBitmap = v.getDrawingCache();
  291 +
  292 + int newColor = cachedBitmap.getPixel( Math.round( event.getX( index ) ), Math.round( event.getY( index ) ) );
  293 +
  294 + v.destroyDrawingCache();
  295 + colorChanged( newColor );
  296 +
  297 + Toast.makeText(getApplicationContext(),
  298 + R.string.color_extracted,
  299 + Toast.LENGTH_SHORT).show();
  300 + } else {
  301 +
  302 + linePath = multiLinePathManager.addLinePathWithPointer( id );
  303 + if( linePath != null ) {
  304 + linePath.touchStart( event.getX( index ), event.getY( index ) );
  305 + } else {
  306 + Log.e( "anupam", "Too many fingers!" );
  307 + }
  308 + }
  309 +
  310 + break;
  311 + }
  312 + case MotionEvent.ACTION_MOVE:
  313 + for (int i = 0; i < event.getPointerCount(); i++) {
  314 + id = event.getPointerId(i);
  315 + index = event.findPointerIndex(id);
  316 + linePath = multiLinePathManager.findLinePathFromPointer(id);
  317 + if (linePath != null) {
  318 + linePath.touchMove(event.getX(index), event.getY(index));
  319 + }
  320 + }
  321 + break;
  322 + case MotionEvent.ACTION_UP:
  323 + case MotionEvent.ACTION_POINTER_UP:
  324 + case MotionEvent.ACTION_CANCEL:
  325 + index = event.getActionIndex();
  326 + id = event.getPointerId(index);
  327 + linePath = multiLinePathManager.findLinePathFromPointer(id);
  328 + if (linePath != null) {
  329 + linePath.lineTo(linePath.getLastX(), linePath.getLastY());
  330 +
  331 + // Commit the path to our offscreen
  332 + mCanvas.drawPath(linePath, mPaint);
  333 +
  334 + // Kill this so we don't double draw
  335 + linePath.reset();
  336 +
  337 + // Allow this LinePath to be associated to another idPointer
  338 + linePath.disassociateFromPointer();
  339 + }
  340 + break;
  341 + }
  342 + invalidate();
  343 + return true;
  344 + }
  345 + }
  346 +
  347 + @Override
  348 + public boolean onCreateOptionsMenu(Menu menu) {
  349 + // Inflate the menu; this adds items to the action bar if it is present.
  350 + getMenuInflater().inflate(R.menu.main, menu);
  351 + return true;
  352 + }
  353 +
  354 + @Override
  355 + public boolean onPrepareOptionsMenu(Menu menu) {
  356 + super.onPrepareOptionsMenu(menu);
  357 + return true;
  358 + }
  359 +
  360 + @Override
  361 + public boolean onOptionsItemSelected(MenuItem item) {
  362 + mPaint.setXfermode(null);
  363 + mPaint.setAlpha(0xFF);
  364 +
  365 + switch (item.getItemId()) {
  366 + case R.id.normal_brush_menu:
  367 + mPaint.setShader( null );
  368 + mPaint.setMaskFilter(null);
  369 + return true;
  370 + case R.id.color_menu:
  371 + new ColorPickerDialog(this, this, mPaint.getColor()).show();
  372 + return true;
  373 + case R.id.emboss_menu:
  374 + mPaint.setShader( null );
  375 + mPaint.setMaskFilter(mEmboss);
  376 + return true;
  377 +
  378 + case R.id.blur_menu:
  379 + mPaint.setShader( null );
  380 + mPaint.setMaskFilter(mBlur);
  381 + return true;
  382 + case R.id.size_menu: {
  383 + LayoutInflater inflater = ( LayoutInflater ) getSystemService( Context.LAYOUT_INFLATER_SERVICE );
  384 + View layout = inflater.inflate( R.layout.brush,
  385 + ( ViewGroup ) findViewById( R.id.root ) );
  386 + AlertDialog.Builder builder = new AlertDialog.Builder( this )
  387 + .setView( layout );
  388 + builder.setTitle( R.string.choose_width );
  389 + final AlertDialog alertDialog = builder.create( );
  390 + alertDialog.show( );
  391 + SeekBar sb = ( SeekBar ) layout.findViewById( R.id.brushSizeSeekBar );
  392 + sb.setProgress( getStrokeSize( ) );
  393 + final TextView txt = ( TextView ) layout
  394 + .findViewById( R.id.sizeValueTextView );
  395 + txt.setText( String.format(
  396 + getResources( ).getString( R.string.your_selected_size_is ),
  397 + getStrokeSize( ) + 1 ) );
  398 + sb.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener( ) {
  399 + public void onProgressChanged( SeekBar seekBar,
  400 + final int progress, boolean fromUser ) {
  401 + // Do something here with new value
  402 + mPaint.setStrokeWidth( progress );
  403 + txt.setText( String.format(
  404 + getResources( ).getString(
  405 + R.string.your_selected_size_is ), progress + 1 ) );
  406 + }
  407 +
  408 + @Override
  409 + public void onStartTrackingTouch( SeekBar seekBar ) {
  410 + // TODO Auto-generated method stub
  411 + }
  412 +
  413 + @Override
  414 + public void onStopTrackingTouch( SeekBar seekBar ) {
  415 + // TODO Auto-generated method stub
  416 + }
  417 + } );
  418 + return true;
  419 + }
  420 + case R.id.erase_menu: {
  421 + LayoutInflater inflater_e = ( LayoutInflater ) getSystemService( Context.LAYOUT_INFLATER_SERVICE );
  422 + View layout_e = inflater_e.inflate( R.layout.brush,
  423 + ( ViewGroup ) findViewById( R.id.root ) );
  424 + AlertDialog.Builder builder_e = new AlertDialog.Builder( this )
  425 + .setView( layout_e );
  426 + builder_e.setTitle( R.string.choose_width );
  427 + final AlertDialog alertDialog_e = builder_e.create( );
  428 + alertDialog_e.show( );
  429 + SeekBar sb_e = ( SeekBar ) layout_e.findViewById( R.id.brushSizeSeekBar );
  430 + sb_e.setProgress( getStrokeSize( ) );
  431 + final TextView txt_e = ( TextView ) layout_e
  432 + .findViewById( R.id.sizeValueTextView );
  433 + txt_e.setText( String.format(
  434 + getResources( ).getString( R.string.your_selected_size_is ),
  435 + getStrokeSize( ) + 1 ) );
  436 + sb_e.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener( ) {
  437 + public void onProgressChanged( SeekBar seekBar,
  438 + final int progress, boolean fromUser ) {
  439 + // Do something here with new value
  440 + mPaint.setStrokeWidth( progress );
  441 + txt_e.setText( String.format(
  442 + getResources( ).getString(
  443 + R.string.your_selected_size_is ), progress + 1 ) );
  444 + }
  445 +
  446 + public void onStartTrackingTouch( SeekBar seekBar ) {
  447 + // TODO Auto-generated method stub
  448 + }
  449 +
  450 + public void onStopTrackingTouch( SeekBar seekBar ) {
  451 + // TODO Auto-generated method stub
  452 + }
  453 + } );
  454 + mPaint.setShader( null );
  455 + mPaint.setXfermode( new PorterDuffXfermode( Mode.CLEAR ) );
  456 + return true;
  457 + }
  458 + case R.id.clear_all_menu: {
  459 + contentView.mBitmap.eraseColor( Color.TRANSPARENT );
  460 + return true;
  461 + }
  462 + case R.id.save_menu:
  463 + takeScreenshot(true);
  464 + break;
  465 + case R.id.fill_background_with_color: {
  466 + waitingForBackgroundColor = true;
  467 + new ColorPickerDialog( this, this, contentView.mBitmapBackground.getPixel( 0, 0 ) ).show();
  468 + return true;
  469 + }
  470 + case R.id.about_menu:
  471 + startActivity(new Intent(this, AboutActivity.class));
  472 + break;
  473 + }
  474 + return super.onOptionsItemSelected(item);
  475 + }
  476 +
  477 + /**
  478 + * This takes the screenshot of the whole screen. Is this a good thing?
  479 + */
  480 + private File takeScreenshot(boolean showToast) {
  481 + View v = findViewById(R.id.CanvasId);
  482 + v.setDrawingCacheEnabled(true);
  483 + Bitmap cachedBitmap = v.getDrawingCache();
  484 + Bitmap copyBitmap = cachedBitmap.copy(Bitmap.Config.RGB_565, true);
  485 + v.destroyDrawingCache();
  486 + FileOutputStream output = null;
  487 + File file = null;
  488 + try {
  489 + File path = Places.getScreenshotFolder();
  490 + Calendar cal = Calendar.getInstance();
  491 +
  492 + file = new File(path,
  493 +
  494 + cal.get(Calendar.YEAR) + "_" + (1 + cal.get(Calendar.MONTH)) + "_"
  495 + + cal.get(Calendar.DAY_OF_MONTH) + "_"
  496 + + cal.get(Calendar.HOUR_OF_DAY) + "_"
  497 + + cal.get(Calendar.MINUTE) + "_" + cal.get(Calendar.SECOND)
  498 + + ".png");
  499 + output = new FileOutputStream(file);
  500 + copyBitmap.compress(CompressFormat.PNG, 100, output);
  501 + } catch (FileNotFoundException e) {
  502 + file = null;
  503 + e.printStackTrace();
  504 + } finally {
  505 + if (output != null) {
  506 + try {
  507 + output.close();
  508 + } catch (IOException e) {
  509 + e.printStackTrace();
  510 + }
  511 + }
  512 +
  513 + }
  514 +
  515 + if (file != null) {
  516 + if (showToast)
  517 + Toast.makeText(
  518 + getApplicationContext(),
  519 + String.format(
  520 + getResources().getString(
  521 + R.string.saved_your_location_to),
  522 + file.getAbsolutePath()), Toast.LENGTH_LONG)
  523 + .show();
  524 + // sending a broadcast to the media scanner so it will scan the new
  525 + // screenshot.
  526 + Intent requestScan = new Intent(
  527 + Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
  528 + requestScan.setData(Uri.fromFile(file));
  529 + sendBroadcast(requestScan);
  530 +
  531 + return file;
  532 + } else {
  533 + return null;
  534 + }
  535 + }
  536 +
  537 + private boolean isFirstTime() {
  538 + SharedPreferences preferences = getPreferences(MODE_PRIVATE);
  539 + boolean ranBefore = preferences.getBoolean("RanBefore", false);
  540 + if (!ranBefore) {
  541 + // first time
  542 + SharedPreferences.Editor editor = preferences.edit();
  543 + editor.putBoolean("RanBefore", true);
  544 + editor.commit();
  545 + }
  546 + return !ranBefore;
  547 + }
  548 +
  549 + private int getStrokeSize() {
  550 + return (int) mPaint.getStrokeWidth();
  551 + }
  552 +
  553 + public void onActivityResult( int requestCode, int resultCode, Intent data ) {
  554 + super.onActivityResult( requestCode, resultCode, data );
  555 +
  556 + if( resultCode != RESULT_CANCELED ) { //"The resultCode will be RESULT_CANCELED if the activity explicitly returned that, didn't return any result, or crashed during its operation." (quote from https://developer.android.com/reference/android/app/Activity.html#onActivityResult(int,%20int,%20android.content.Intent) )
  557 + switch( requestCode ) {
  558 + case CHOOSE_IMAGE: {
  559 + setBackgroundUri( data.getData() );
  560 + }
  561 + }
  562 + }
  563 + }
  564 +
  565 + public void setBackgroundUri(Uri uri) {
  566 + if (uri == null) {
  567 + return;
  568 + }
  569 +
  570 + try {
  571 + //I don't like loading both full-sized and reduced-size copies of the image (the larger copy can use a lot of memory), but I couldn't find any other way to do this.
  572 + Bitmap fullsize = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
  573 + Bitmap resized = Bitmap.createScaledBitmap(fullsize, contentView.mBitmap.getWidth(), contentView.mBitmap.getHeight(), true);
  574 + contentView.mBitmapBackground = resized;
  575 + //contentView.mCanvas = new Canvas( contentView.mBitmapBackground );
  576 + } catch (IOException exception) {
  577 + //TODO: How should we handle this exception?
  578 + }
  579 + }
  580 +
  581 + public void loadFromIntents() {
  582 + Intent intent = getIntent();
  583 + String action = intent.getAction();
  584 + String type = intent.getType();
  585 + System.out.println("Intentoso " + action + " type " + type);
  586 + if(Intent.ACTION_SEND.equals(action) && type != null) {
  587 + if( type.startsWith("image/") ) {
  588 + setBackgroundUri( (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM) );
  589 + }
  590 +
  591 + }
  592 + }
  593 +}
acrylic/src/main/java/anupam/acrylic/GraphicsActivity.java 0 → 100644
  1 +++ a/acrylic/src/main/java/anupam/acrylic/GraphicsActivity.java
@@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
  1 +/*
  2 + * Copyright (C) 2014 Valerio Bozzolan
  3 + *
  4 + * This program is free software: you can redistribute it and/or modify
  5 + * it under the terms of the GNU General Public License as published by
  6 + * the Free Software Foundation, either version 3 of the License, or
  7 + * (at your option) any later version.
  8 + *
  9 + * This program is distributed in the hope that it will be useful,
  10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 + * GNU General Public License for more details.
  13 + *
  14 + * You should have received a copy of the GNU General Public License
  15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 +*/
  17 +
  18 +package anupam.acrylic;
  19 +
  20 +import android.app.Activity;
  21 +import android.content.pm.ActivityInfo;
  22 +import android.os.Bundle;
  23 +import android.view.View;
  24 +import android.view.ViewGroup;
  25 +
  26 +class GraphicsActivity extends Activity {
  27 + @Override
  28 + protected void onCreate(Bundle savedInstanceState) {
  29 + super.onCreate(savedInstanceState);
  30 + this.setRequestedOrientation(
  31 + ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  32 + }
  33 +
  34 + @SuppressWarnings("unused")
  35 + @Override
  36 + public void setContentView(View view) {
  37 + if (false) { // set to true to test Picture
  38 + ViewGroup vg = new PictureLayout(this);
  39 + vg.addView(view);
  40 + view = vg;
  41 + }
  42 + super.setContentView(view);
  43 + }
  44 +}
  45 +
acrylic/src/main/java/anupam/acrylic/MainActivity.java 0 → 100644
  1 +++ a/acrylic/src/main/java/anupam/acrylic/MainActivity.java
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +package anupam.acrylic;
  2 +
  3 +import android.support.v7.app.AppCompatActivity;
  4 +import android.os.Bundle;
  5 +
  6 +public class MainActivity extends AppCompatActivity {
  7 +
  8 + @Override
  9 + protected void onCreate(Bundle savedInstanceState) {
  10 + super.onCreate(savedInstanceState);
  11 + setContentView(R.layout.activity_main);
  12 + }
  13 +}
acrylic/src/main/java/anupam/acrylic/PictureLayout.java 0 → 100644
  1 +++ a/acrylic/src/main/java/anupam/acrylic/PictureLayout.java
@@ -0,0 +1,165 @@ @@ -0,0 +1,165 @@
  1 +/*
  2 + * Copyright (C) 2014 Valerio Bozzolan
  3 + *
  4 + * This program is free software: you can redistribute it and/or modify
  5 + * it under the terms of the GNU General Public License as published by
  6 + * the Free Software Foundation, either version 3 of the License, or
  7 + * (at your option) any later version.
  8 + *
  9 + * This program is distributed in the hope that it will be useful,
  10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 + * GNU General Public License for more details.
  13 + *
  14 + * You should have received a copy of the GNU General Public License
  15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 +*/
  17 +
  18 +package anupam.acrylic;
  19 +
  20 +import android.content.Context;
  21 +import android.graphics.Canvas;
  22 +import android.graphics.Picture;
  23 +import android.graphics.Rect;
  24 +import android.graphics.drawable.Drawable;
  25 +import android.util.AttributeSet;
  26 +import android.view.View;
  27 +import android.view.ViewGroup;
  28 +import android.view.ViewParent;
  29 +
  30 +
  31 +public class PictureLayout extends ViewGroup {
  32 + private static String error = "PictureLayout can host only one direct child";
  33 + private final Picture mPicture = new Picture();
  34 +
  35 + public PictureLayout(Context context) {
  36 + super(context);
  37 + }
  38 +
  39 + public PictureLayout(Context context, AttributeSet attrs) {
  40 + super(context, attrs);
  41 + }
  42 +
  43 + @Override
  44 + public void addView(View child) {
  45 + if (getChildCount() > 1) {
  46 + throw new IllegalStateException(error);
  47 + }
  48 +
  49 + super.addView(child);
  50 + }
  51 +
  52 + @Override
  53 + public void addView(View child, int index) {
  54 + if (getChildCount() > 1) {
  55 + throw new IllegalStateException(error);
  56 + }
  57 +
  58 + super.addView(child, index);
  59 + }
  60 +
  61 + @Override
  62 + public void addView(View child, LayoutParams params) {
  63 + if (getChildCount() > 1) {
  64 + throw new IllegalStateException(error);
  65 + }
  66 +
  67 + super.addView(child, params);
  68 + }
  69 +
  70 + @Override
  71 + public void addView(View child, int index, LayoutParams params) {
  72 + if (getChildCount() > 1) {
  73 + throw new IllegalStateException(error);
  74 + }
  75 +
  76 + super.addView(child, index, params);
  77 + }
  78 +
  79 + @Override
  80 + protected LayoutParams generateDefaultLayoutParams() {
  81 + return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
  82 + }
  83 +
  84 + @Override
  85 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  86 + final int count = getChildCount();
  87 +
  88 + int maxHeight = 0;
  89 + int maxWidth = 0;
  90 +
  91 + for (int i = 0; i < count; i++) {
  92 + final View child = getChildAt(i);
  93 + if (child.getVisibility() != GONE) {
  94 + measureChild(child, widthMeasureSpec, heightMeasureSpec);
  95 + }
  96 + }
  97 +
  98 + maxWidth += getPaddingLeft() + getPaddingRight();
  99 + maxHeight += getPaddingTop() + getPaddingBottom();
  100 +
  101 + Drawable drawable = getBackground();
  102 + if (drawable != null) {
  103 + maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
  104 + maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
  105 + }
  106 +
  107 + setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
  108 + resolveSize(maxHeight, heightMeasureSpec));
  109 + }
  110 +
  111 + private void drawPict(Canvas canvas, int x, int y, int w, int h,
  112 + float sx, float sy) {
  113 + canvas.save();
  114 + canvas.translate(x, y);
  115 + canvas.clipRect(0, 0, w, h);
  116 + canvas.scale(0.5f, 0.5f);
  117 + canvas.scale(sx, sy, w, h);
  118 + canvas.drawPicture(mPicture);
  119 + canvas.restore();
  120 + }
  121 +
  122 + @SuppressWarnings("unused")
  123 + @Override
  124 + protected void dispatchDraw(Canvas canvas) {
  125 + super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight()));
  126 + mPicture.endRecording();
  127 +
  128 + int x = getWidth()/2;
  129 + int y = getHeight()/2;
  130 +
  131 + if (false) {
  132 + canvas.drawPicture(mPicture);
  133 + } else {
  134 + drawPict(canvas, 0, 0, x, y, 1, 1);
  135 + drawPict(canvas, x, 0, x, y, -1, 1);
  136 + drawPict(canvas, 0, y, x, y, 1, -1);
  137 + drawPict(canvas, x, y, x, y, -1, -1);
  138 + }
  139 + }
  140 +
  141 + @Override
  142 + public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
  143 + location[0] = getLeft();
  144 + location[1] = getTop();
  145 + dirty.set(0, 0, getWidth(), getHeight());
  146 + return getParent();
  147 + }
  148 +
  149 + @Override
  150 + protected void onLayout(boolean changed, int l, int t, int r, int b) {
  151 + final int count = super.getChildCount();
  152 +
  153 + for (int i = 0; i < count; i++) {
  154 + final View child = getChildAt(i);
  155 + if (child.getVisibility() != GONE) {
  156 + final int childLeft = getPaddingLeft();
  157 + final int childTop = getPaddingTop();
  158 + child.layout(childLeft, childTop,
  159 + childLeft + child.getMeasuredWidth(),
  160 + childTop + child.getMeasuredHeight());
  161 +
  162 + }
  163 + }
  164 + }
  165 +}
acrylic/src/main/java/anupam/acrylic/Places.java 0 → 100644
  1 +++ a/acrylic/src/main/java/anupam/acrylic/Places.java
@@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
  1 +/*
  2 + * Copyright (C) 2014 Valerio Bozzolan
  3 + *
  4 + * This program is free software: you can redistribute it and/or modify
  5 + * it under the terms of the GNU General Public License as published by
  6 + * the Free Software Foundation, either version 3 of the License, or
  7 + * (at your option) any later version.
  8 + *
  9 + * This program is distributed in the hope that it will be useful,
  10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 + * GNU General Public License for more details.
  13 + *
  14 + * You should have received a copy of the GNU General Public License
  15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 +*/
  17 +
  18 +package anupam.acrylic;
  19 +
  20 +import java.io.File;
  21 +import java.io.IOException;
  22 +
  23 +import android.os.Environment;
  24 +
  25 +public class Places {
  26 + public static File getScreenshotFolder() {
  27 + File path = new File(Environment.getExternalStorageDirectory(),
  28 + "/Acrylic Paint/");
  29 + path.mkdirs();
  30 +
  31 + return path;
  32 + }
  33 +
  34 + public static File getCameraTempFolder() {
  35 + File path = new File(Environment.getExternalStorageDirectory(),
  36 + "/Acrylic Paint/Temp/");
  37 + path.mkdirs();
  38 + // this folder should not be scanned
  39 + File noScanning = new File(path, ".nomedia");
  40 + if (!noScanning.exists())
  41 + try {
  42 + noScanning.createNewFile();
  43 + } catch (IOException e) {
  44 + // TODO Auto-generated catch block
  45 + e.printStackTrace();
  46 + }
  47 + return path;
  48 + }
  49 +
  50 + public static File getCameraTempFile() {
  51 + return new File(getCameraTempFolder(), "temp.jpg");
  52 + }
  53 +}
acrylic/src/main/java/anupam/acrylic/Splash.java 0 → 100644
  1 +++ a/acrylic/src/main/java/anupam/acrylic/Splash.java
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
  1 +/*
  2 + * Copyright (C) 2014 Valerio Bozzolan
  3 + *
  4 + * This program is free software: you can redistribute it and/or modify
  5 + * it under the terms of the GNU General Public License as published by
  6 + * the Free Software Foundation, either version 3 of the License, or
  7 + * (at your option) any later version.
  8 + *
  9 + * This program is distributed in the hope that it will be useful,
  10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 + * GNU General Public License for more details.
  13 + *
  14 + * You should have received a copy of the GNU General Public License
  15 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 + */
  17 +
  18 +package anupam.acrylic;
  19 +
  20 +import android.app.Activity;
  21 +import android.content.Intent;
  22 +import android.content.pm.ActivityInfo;
  23 +import android.os.Bundle;
  24 +import anupam.acrylic.R;
  25 +
  26 +public class Splash extends Activity {
  27 +
  28 + @Override
  29 + protected void onCreate(Bundle savedInstanceState) {
  30 + // TODO Auto-generated method stub
  31 + super.onCreate(savedInstanceState);
  32 + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  33 + setContentView(R.layout.main);
  34 +
  35 + Thread t = new Thread() {
  36 +
  37 + public void run() {
  38 + try {
  39 + Thread.sleep(1000);
  40 +
  41 + startActivity(new Intent().setClassName("anupam.acrylic",
  42 + "anupam.acrylic.EasyPaint"));
  43 + finish();
  44 + } catch (Exception e) {
  45 + e.printStackTrace();
  46 + }
  47 + }
  48 + };
  49 + t.start();
  50 + }
  51 +}
acrylic/src/main/res/drawable-hdpi/about.png 0 → 100644

1.71 KB

acrylic/src/main/res/drawable-hdpi/blur.png 0 → 100644

1022 Bytes

acrylic/src/main/res/drawable-hdpi/clear_all.png 0 → 100644

1.43 KB

acrylic/src/main/res/drawable-hdpi/color.png 0 → 100644

1.26 KB

acrylic/src/main/res/drawable-hdpi/emboss.png 0 → 100644

856 Bytes

acrylic/src/main/res/drawable-hdpi/erase.png 0 → 100644

406 Bytes

acrylic/src/main/res/drawable-hdpi/extract_color.png 0 → 100644

418 Bytes

acrylic/src/main/res/drawable-hdpi/fill_background_with_color.png 0 → 100644

689 Bytes

acrylic/src/main/res/drawable-hdpi/ic_launcher.png 0 → 100644

8.88 KB

acrylic/src/main/res/drawable-hdpi/import_image.png 0 → 100644

448 Bytes

acrylic/src/main/res/drawable-hdpi/save.png 0 → 100644

819 Bytes

acrylic/src/main/res/drawable-hdpi/share.png 0 → 100644

1.21 KB

acrylic/src/main/res/drawable-hdpi/size.png 0 → 100644

851 Bytes

acrylic/src/main/res/drawable-hdpi/smudge.png 0 → 100644

874 Bytes

acrylic/src/main/res/drawable-hdpi/splash.png 0 → 100644

31.9 KB

acrylic/src/main/res/drawable-mdpi/about.png 0 → 100644

1.11 KB

acrylic/src/main/res/drawable-mdpi/blur.png 0 → 100644

769 Bytes

acrylic/src/main/res/drawable-mdpi/clear_all.png 0 → 100644

937 Bytes

acrylic/src/main/res/drawable-mdpi/color.png 0 → 100644

801 Bytes

acrylic/src/main/res/drawable-mdpi/emboss.png 0 → 100644

619 Bytes

acrylic/src/main/res/drawable-mdpi/erase.png 0 → 100644

305 Bytes

acrylic/src/main/res/drawable-mdpi/extract_color.png 0 → 100644

276 Bytes

acrylic/src/main/res/drawable-mdpi/fill_background_with_color.png 0 → 100644

474 Bytes

acrylic/src/main/res/drawable-mdpi/ic_launcher.png 0 → 100644

6.09 KB

acrylic/src/main/res/drawable-mdpi/import_image.png 0 → 100644

325 Bytes

acrylic/src/main/res/drawable-mdpi/save.png 0 → 100644

563 Bytes

acrylic/src/main/res/drawable-mdpi/share.png 0 → 100644

827 Bytes

acrylic/src/main/res/drawable-mdpi/size.png 0 → 100644

596 Bytes

acrylic/src/main/res/drawable-mdpi/smudge.png 0 → 100644

535 Bytes

acrylic/src/main/res/drawable-mdpi/splash.png 0 → 100644

19.4 KB

acrylic/src/main/res/drawable-xhdpi/about.png 0 → 100644

2.1 KB

acrylic/src/main/res/drawable-xhdpi/blur.png 0 → 100644

1.11 KB

acrylic/src/main/res/drawable-xhdpi/clear_all.png 0 → 100644

1.69 KB

acrylic/src/main/res/drawable-xhdpi/color.png 0 → 100644

1.53 KB

acrylic/src/main/res/drawable-xhdpi/emboss.png 0 → 100644

1.05 KB

acrylic/src/main/res/drawable-xhdpi/erase.png 0 → 100644

554 Bytes

acrylic/src/main/res/drawable-xhdpi/extract_color.png 0 → 100644

421 Bytes

acrylic/src/main/res/drawable-xhdpi/fill_background_with_color.png 0 → 100644

921 Bytes

acrylic/src/main/res/drawable-xhdpi/ic_launcher.png 0 → 100644

14.1 KB

acrylic/src/main/res/drawable-xhdpi/import_image.png 0 → 100644

540 Bytes

acrylic/src/main/res/drawable-xhdpi/save.png 0 → 100644

977 Bytes

acrylic/src/main/res/drawable-xhdpi/share.png 0 → 100644

1.63 KB

acrylic/src/main/res/drawable-xhdpi/size.png 0 → 100644

997 Bytes

acrylic/src/main/res/drawable-xhdpi/smudge.png 0 → 100644

1.11 KB

acrylic/src/main/res/drawable-xhdpi/splash.png 0 → 100644

50.8 KB

acrylic/src/main/res/drawable-xxhdpi/about.png 0 → 100644

3.77 KB

acrylic/src/main/res/drawable-xxhdpi/blur.png 0 → 100644

1.48 KB

acrylic/src/main/res/drawable-xxhdpi/clear_all.png 0 → 100644

2.71 KB

acrylic/src/main/res/drawable-xxhdpi/color.png 0 → 100644

2.5 KB

acrylic/src/main/res/drawable-xxhdpi/emboss.png 0 → 100644

1.58 KB

acrylic/src/main/res/drawable-xxhdpi/erase.png 0 → 100644

882 Bytes

acrylic/src/main/res/drawable-xxhdpi/extract_color.png 0 → 100644

766 Bytes

acrylic/src/main/res/drawable-xxhdpi/fill_background_with_color.png 0 → 100644

1.45 KB

acrylic/src/main/res/drawable-xxhdpi/ic_launcher.png 0 → 100644

22.9 KB

acrylic/src/main/res/drawable-xxhdpi/import_image.png 0 → 100644

895 Bytes

acrylic/src/main/res/drawable-xxhdpi/save.png 0 → 100644

1.32 KB

acrylic/src/main/res/drawable-xxhdpi/share.png 0 → 100644

2.76 KB

acrylic/src/main/res/drawable-xxhdpi/size.png 0 → 100644

1.49 KB

acrylic/src/main/res/drawable-xxhdpi/smudge.png 0 → 100644

1.81 KB

acrylic/src/main/res/drawable-xxhdpi/splash.png 0 → 100644

79.1 KB

acrylic/src/main/res/drawable-xxxhdpi/about.png 0 → 100644

4.25 KB

acrylic/src/main/res/drawable-xxxhdpi/actionbar_background.png 0 → 100644

5.05 KB

acrylic/src/main/res/drawable-xxxhdpi/blur.png 0 → 100644

1.3 KB

acrylic/src/main/res/drawable-xxxhdpi/clear_all.png 0 → 100644

2.94 KB

acrylic/src/main/res/drawable-xxxhdpi/color.png 0 → 100644

2.88 KB

acrylic/src/main/res/drawable-xxxhdpi/emboss.png 0 → 100644

1.71 KB

acrylic/src/main/res/drawable-xxxhdpi/erase.png 0 → 100644

1006 Bytes

acrylic/src/main/res/drawable-xxxhdpi/ic_launcher.png 0 → 100644

34.8 KB

acrylic/src/main/res/drawable-xxxhdpi/save.png 0 → 100644

1.24 KB

acrylic/src/main/res/drawable-xxxhdpi/share.png 0 → 100644

3.05 KB

acrylic/src/main/res/drawable-xxxhdpi/size.png 0 → 100644

1.38 KB

acrylic/src/main/res/drawable-xxxhdpi/splash.png 0 → 100644

79.1 KB

acrylic/src/main/res/layout/activity_about.xml 0 → 100644
  1 +++ a/acrylic/src/main/res/layout/activity_about.xml
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2 + xmlns:tools="http://schemas.android.com/tools"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:paddingBottom="@dimen/activity_vertical_margin"
  6 + android:paddingLeft="@dimen/activity_horizontal_margin"
  7 + android:paddingRight="@dimen/activity_horizontal_margin"
  8 + android:paddingTop="@dimen/activity_vertical_margin"
  9 + tools:context="anupam.acrylic.AboutActivity" >
  10 +
  11 + <TextView
  12 + android:id="@+id/aboutTextView"
  13 + android:layout_width="wrap_content"
  14 + android:layout_height="wrap_content"
  15 + android:layout_alignParentBottom="true"
  16 + android:layout_alignParentLeft="true"
  17 + android:layout_alignParentRight="true"
  18 + android:layout_alignParentTop="true" />
  19 +
  20 +</RelativeLayout>
0 \ No newline at end of file 21 \ No newline at end of file
acrylic/src/main/res/layout/activity_main.xml 0 → 100644
  1 +++ a/acrylic/src/main/res/layout/activity_main.xml
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
  4 + android:layout_width="match_parent" android:layout_height="match_parent"
  5 + android:paddingBottom="@dimen/activity_vertical_margin"
  6 + android:paddingLeft="@dimen/activity_horizontal_margin"
  7 + android:paddingRight="@dimen/activity_horizontal_margin"
  8 + android:paddingTop="@dimen/activity_vertical_margin"
  9 + tools:context="anupam.acrylic.MainActivity">
  10 +
  11 + <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
  12 + android:text="Hello World!" />
  13 +</RelativeLayout>
acrylic/src/main/res/layout/brush.xml 0 → 100644
  1 +++ a/acrylic/src/main/res/layout/brush.xml
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:id="@+id/root"
  4 + android:layout_width="fill_parent"
  5 + android:layout_height="fill_parent"
  6 + android:orientation="vertical" >
  7 +
  8 + <SeekBar
  9 + android:id="@+id/brushSizeSeekBar"
  10 + android:layout_width="fill_parent"
  11 + android:layout_height="wrap_content"
  12 + android:layout_alignParentLeft="true"
  13 + android:layout_alignParentTop="true"
  14 + android:layout_marginTop="20dp"
  15 + android:max="99"
  16 + android:paddingLeft="30dp"
  17 + android:paddingRight="30dp" >
  18 + </SeekBar>
  19 +
  20 + <TextView
  21 + android:id="@+id/sizeValueTextView"
  22 + android:layout_width="wrap_content"
  23 + android:layout_height="wrap_content"
  24 + android:layout_alignParentLeft="true"
  25 + android:layout_alignParentRight="true"
  26 + android:layout_below="@+id/brushSizeSeekBar"
  27 + android:layout_marginTop="5dp"
  28 + android:layout_marginBottom="10dp"
  29 + android:gravity="center_horizontal" />
  30 +
  31 +</RelativeLayout>
0 \ No newline at end of file 32 \ No newline at end of file
acrylic/src/main/res/layout/main.xml 0 → 100644
  1 +++ a/acrylic/src/main/res/layout/main.xml
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="fill_parent"
  4 + android:layout_height="fill_parent"
  5 + android:background="@drawable/splash"
  6 + android:orientation="vertical" >
  7 +
  8 +</LinearLayout>
0 \ No newline at end of file 9 \ No newline at end of file
acrylic/src/main/res/menu/main.xml 0 → 100644
  1 +++ a/acrylic/src/main/res/menu/main.xml
@@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<menu xmlns:android="http://schemas.android.com/apk/res/android" >
  3 +
  4 + <item
  5 + android:id="@+id/color_menu"
  6 + android:icon="@drawable/color"
  7 + android:showAsAction="ifRoom"
  8 + android:title="@string/color"/>
  9 + <item
  10 + android:id="@+id/size_menu"
  11 + android:icon="@drawable/size"
  12 + android:showAsAction="ifRoom"
  13 + android:title="@string/brush_size">
  14 + </item>
  15 + <item
  16 + android:id="@+id/erase_menu"
  17 + android:icon="@drawable/erase"
  18 + android:showAsAction="ifRoom"
  19 + android:title="@string/erase">
  20 + </item>
  21 + <item
  22 + android:id="@+id/clear_all_menu"
  23 + android:icon="@drawable/clear_all"
  24 + android:showAsAction="ifRoom"
  25 + android:title="@string/clear_all">
  26 + </item>
  27 + <item
  28 + android:id="@+id/normal_brush_menu"
  29 + android:icon="@drawable/size"
  30 + android:showAsAction="ifRoom"
  31 + android:title="@string/normal">
  32 + </item>
  33 + <item
  34 + android:id="@+id/emboss_menu"
  35 + android:icon="@drawable/emboss"
  36 + android:showAsAction="ifRoom"
  37 + android:title="@string/emboss">
  38 + </item>
  39 + <item
  40 + android:id="@+id/blur_menu"
  41 + android:icon="@drawable/blur"
  42 + android:showAsAction="ifRoom"
  43 + android:title="@string/blur">
  44 + </item>
  45 + <item
  46 + android:id="@+id/save_menu"
  47 + android:icon="@drawable/save"
  48 + android:showAsAction="ifRoom"
  49 + android:title="@string/save">
  50 + </item>
  51 + <item
  52 + android:id="@+id/fill_background_with_color"
  53 + android:icon="@drawable/fill_background_with_color"
  54 + android:showAsAction="ifRoom"
  55 + android:title="@string/fill_background_with_color">
  56 + </item>
  57 + <item
  58 + android:id="@+id/about_menu"
  59 + android:icon="@drawable/about"
  60 + android:showAsAction="ifRoom"
  61 + android:title="@string/about">
  62 + </item>
  63 +
  64 +</menu>
acrylic/src/main/res/mipmap-hdpi/ic_launcher.png 0 → 100644

3.34 KB

acrylic/src/main/res/mipmap-mdpi/ic_launcher.png 0 → 100644

2.15 KB