├── .gitignore
├── .idea
├── caches
│ └── build_file_checksums.ser
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── codingwithmitch
│ │ └── com
│ │ └── tabiancustomcamera
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── codingwithmitch
│ │ │ └── com
│ │ │ └── tabiancustomcamera
│ │ │ ├── Camera2Fragment.java
│ │ │ ├── DrawableImageView.java
│ │ │ ├── ICallback.java
│ │ │ ├── IMainActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── ScalingTextureView.java
│ │ │ ├── StickerAdapter.java
│ │ │ ├── Utility.java
│ │ │ ├── VerticalSlideColorPicker.java
│ │ │ ├── ViewStickersFragment.java
│ │ │ └── gestures
│ │ │ ├── BaseGestureDetector.java
│ │ │ └── MoveGestureDetector.java
│ └── res
│ │ ├── anim
│ │ ├── slide_in_down.xml
│ │ ├── slide_in_up.xml
│ │ ├── slide_out_down.xml
│ │ └── slide_out_up.xml
│ │ ├── drawable-hdpi
│ │ ├── ic_flash_auto.png
│ │ ├── ic_flash_off.png
│ │ ├── ic_flash_on.png
│ │ ├── ic_pen_small.png
│ │ ├── ic_save_small.png
│ │ ├── ic_sticker_small.png
│ │ ├── ic_switch_camera_orient.png
│ │ └── ic_undo_small.png
│ │ ├── drawable-mdpi
│ │ ├── ic_flash_auto.png
│ │ ├── ic_flash_off.png
│ │ ├── ic_flash_on.png
│ │ ├── ic_pen_small.png
│ │ ├── ic_save_small.png
│ │ ├── ic_sticker_small.png
│ │ ├── ic_switch_camera_orient.png
│ │ └── ic_undo_small.png
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xhdpi
│ │ ├── ic_flash_auto.png
│ │ ├── ic_flash_off.png
│ │ ├── ic_flash_on.png
│ │ ├── ic_pen_small.png
│ │ ├── ic_save_small.png
│ │ ├── ic_sticker_small.png
│ │ ├── ic_switch_camera_orient.png
│ │ └── ic_undo_small.png
│ │ ├── drawable-xxhdpi
│ │ ├── ic_flash_auto.png
│ │ ├── ic_flash_off.png
│ │ ├── ic_flash_on.png
│ │ ├── ic_pen_small.png
│ │ ├── ic_save_small.png
│ │ ├── ic_sticker_small.png
│ │ ├── ic_switch_camera_orient.png
│ │ └── ic_undo_small.png
│ │ ├── drawable
│ │ ├── astonished_face_emoji.png
│ │ ├── cam_action_capture.xml
│ │ ├── cam_action_stillshot.xml
│ │ ├── cam_circle_selector.xml
│ │ ├── cam_grey_circle_selector.xml
│ │ ├── circle_opaque.xml
│ │ ├── circle_white.xml
│ │ ├── cry_emoji.png
│ │ ├── evil_monkey_emoji.png
│ │ ├── ic_delete_black_24dp.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── nerd_emoji.png
│ │ ├── penguin_emoji.png
│ │ ├── sad_emoji.png
│ │ ├── slightly_smiling_face_emoji.png
│ │ ├── smiley_face_emoji.png
│ │ ├── smiley_face_tightly_closed_eyes_emoji.png
│ │ ├── smiley_smiling_eyes_emoji.png
│ │ ├── smiley_with_sweat_emoji.png
│ │ ├── smirking_emoji.png
│ │ ├── sunglasses_emoji.png
│ │ ├── tears_of_joy_emoji.png
│ │ ├── unamused_emoji.png
│ │ ├── upside_down_face_emoji.png
│ │ └── x_white_border.png
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── fragment_camera2.xml
│ │ ├── fragment_view_stickers.xml
│ │ └── layout_sticker_list_item.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── array.xml
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── default_colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── codingwithmitch
│ └── com
│ └── tabiancustomcamera
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # This code is deprecated. See [CameraX](https://developer.android.com/training/camerax)
2 |
3 |
4 |
5 |
6 | Get the course here.
7 |
8 |
9 | What you'll learn:
10 |
11 | - Android's camera2 API
12 | - Making full-screen camera previews
13 | - Accommodating different screen sizes
14 | - Capturing photos
15 | - Drawing on photos
16 | - Adding stickers
17 | - Saving photos to internal storage
18 |
19 |
20 | Submitting an Issue
21 | Watch this video to learn about how to properly submit an issue.
22 |
23 | Here is an example issue I made so you can get a good idea of what it should look like: Example
24 |
25 | Link to the Phone Test: Phone Test
26 |
27 | Phones with Known Issues
28 |
29 | -
30 |
Redmi 4X (santoni)
31 | See here for a workaround
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "codingwithmitch.com.tabiancustomcamera"
7 | minSdkVersion 21
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | implementation 'com.android.support:appcompat-v7:28.0.0'
24 | implementation 'com.android.support.constraint:constraint-layout:1.1.0'
25 | testImplementation 'junit:junit:4.12'
26 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
28 |
29 | //Support Design Library
30 | implementation 'com.android.support:design:28.0.0'
31 |
32 | //glide
33 | implementation 'com.github.bumptech.glide:glide:4.7.1'
34 | annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
35 | }
36 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/codingwithmitch/com/tabiancustomcamera/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
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 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
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("codingwithmitch.com.tabiancustomcamera", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
17 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/DrawableImageView.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.Paint;
8 | import android.graphics.Path;
9 | import android.graphics.Rect;
10 | import android.graphics.drawable.BitmapDrawable;
11 | import android.graphics.drawable.Drawable;
12 | import android.util.AttributeSet;
13 | import android.util.DisplayMetrics;
14 | import android.util.Log;
15 | import android.view.MotionEvent;
16 | import android.view.ScaleGestureDetector;
17 | import android.view.View;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | /**
23 | * Created by User on 5/23/2018.
24 | */
25 |
26 | public class DrawableImageView extends android.support.v7.widget.AppCompatImageView
27 | {
28 |
29 | private static final String TAG = "DrawableImageView";
30 |
31 | private static final int SIZE_CHANGE_SPEED = 2;
32 | private static final int STICKER_STARTING_WIDTH = 300;
33 | private static final int STICKER_STARTING_HEIGHT = 300;
34 | private static final int MIN_STICKER_WIDTH = 50;
35 | private static final int MIN_STICKER_HEIGHT = 50;
36 | private static final int TRASH_ICON_ENLARGED_SIZE = 55;
37 | private static final int TRASH_ICON_NORMAL_SIZE = 44;
38 |
39 | //vars
40 | private int color;
41 | private float width = 8f;
42 | private List mPenList = new ArrayList();
43 | private Activity mHostActivity;
44 | private boolean mIsDrawingEnabled = false;
45 |
46 |
47 | // Scales
48 | float mMinWidth = 8f;
49 | float mMaxWidth = 500f;
50 | private ScaleGestureDetector mScaleGestureDetector;
51 | private boolean mIsSizeChanging = false;
52 | private Circle mCircle;
53 | private int mScreenWidth;
54 |
55 |
56 | // Stickers
57 | private ArrayList mStickers = new ArrayList<>();
58 | int mPrevStickerX, mPrevStickerY;
59 | int mSelectedStickerIndex = -1;
60 | private boolean mIsStickerResizing = false;
61 |
62 | // Trash can location
63 | Rect trashRect;
64 |
65 | private class Sticker{
66 |
67 | Paint paint;
68 | Bitmap bitmap;
69 | Drawable drawable;
70 | int x, y;
71 | Rect rect;
72 |
73 |
74 | Sticker(Bitmap bitmap, Drawable drawable, int x, int y){
75 | paint = new Paint();
76 | this.x = x;
77 | this.y = y;
78 | this.bitmap = bitmap;
79 | this.drawable = drawable;
80 | rect = new Rect(x, y, x + STICKER_STARTING_WIDTH, y + STICKER_STARTING_HEIGHT);
81 | }
82 |
83 | public void adjustRect(){
84 | rect.left = x;
85 | rect.top = y;
86 | rect.right = x + bitmap.getWidth();
87 | rect.bottom = y + bitmap.getHeight();
88 | }
89 | }
90 |
91 |
92 | private class Circle {
93 |
94 | float x, y;
95 | Paint paint;
96 |
97 | Circle(int color, float x, float y) {
98 | this.x = x;
99 | this.y = y;
100 | paint = new Paint();
101 | paint.setAntiAlias(true);
102 | paint.setStrokeWidth(width);
103 | paint.setColor(color);
104 | paint.setStyle(Paint.Style.STROKE);
105 | paint.setStrokeJoin(Paint.Join.ROUND);
106 | paint.setStrokeCap(Paint.Cap.ROUND);
107 | }
108 | }
109 |
110 | private class Pen {
111 | Path path;
112 | Paint paint;
113 |
114 | Pen(int color, float width ) {
115 | path = new Path();
116 | paint = new Paint();
117 | paint.setAntiAlias(true);
118 | paint.setStrokeWidth(width);
119 | paint.setColor(color);
120 | paint.setStyle(Paint.Style.STROKE);
121 | paint.setStrokeJoin(Paint.Join.ROUND);
122 | paint.setStrokeCap(Paint.Cap.ROUND);
123 | }
124 | }
125 |
126 |
127 |
128 | public DrawableImageView(Context context) {
129 | super(context);
130 | init(context);
131 | }
132 |
133 | public DrawableImageView(Context context, AttributeSet attrs) {
134 | super(context, attrs);
135 |
136 | init(context);
137 | }
138 |
139 | public DrawableImageView(Context context, AttributeSet attrs, int defStyle) {
140 | super(context, attrs, defStyle);
141 |
142 | init(context);
143 | }
144 |
145 | private void init(Context context) {
146 | mPenList.add(new Pen(color, width));
147 | setDrawingCacheEnabled(true);
148 | if(context instanceof Activity) {
149 | mHostActivity = (Activity) context;
150 |
151 | mScaleGestureDetector = new ScaleGestureDetector(mHostActivity, new ScaleListener());
152 |
153 | DisplayMetrics displayMetrics = new DisplayMetrics();
154 | mHostActivity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
155 | mScreenWidth = displayMetrics.widthPixels;
156 |
157 | int screenHeight = displayMetrics.heightPixels;
158 |
159 | float density = displayMetrics.density;
160 | int bottomMargin = (int)mHostActivity.getResources().getDimension(R.dimen.cam_widget_margin_bottom);
161 |
162 | int left = (mScreenWidth / 2) - (int) ( (TRASH_ICON_NORMAL_SIZE ) * density + 0.5f);
163 | int top = screenHeight - (int) ( (bottomMargin + TRASH_ICON_NORMAL_SIZE ) * density + 0.5f);;
164 | int right = (mScreenWidth / 2) + (int) ( (TRASH_ICON_NORMAL_SIZE ) * density + 0.5f);
165 | int bottom = screenHeight;
166 |
167 | trashRect = new Rect(left, top, right, bottom);
168 | }
169 | }
170 |
171 |
172 | @Override
173 | protected void onDraw(Canvas canvas) {
174 | super.onDraw(canvas);
175 |
176 | if(mStickers.size() > 0){
177 | for(Sticker sticker: mStickers){
178 | canvas.drawBitmap(sticker.bitmap, sticker.x, sticker.y, sticker.paint);
179 | }
180 | }
181 |
182 | for (Pen pen : mPenList) {
183 | canvas.drawPath(pen.path, pen.paint);
184 | }
185 |
186 | if(mCircle != null){
187 | float radius = width / (float)mScreenWidth;
188 | canvas.drawCircle(mCircle.x, mCircle.y, radius, mCircle.paint);
189 | }
190 | }
191 |
192 |
193 | public boolean touchEvent(MotionEvent event){
194 |
195 | hideStatusBar();
196 |
197 | switch (event.getAction()) {
198 | case MotionEvent.ACTION_UP:{
199 | removeCircle();
200 | mIsSizeChanging = false;
201 | break;
202 | }
203 | }
204 |
205 | if(mIsDrawingEnabled) {
206 | if (event.getPointerCount() > 1) {
207 |
208 | if (!mIsSizeChanging) {
209 | mIsSizeChanging = true;
210 | }
211 |
212 | try {
213 | mScaleGestureDetector.onTouchEvent(event);
214 |
215 | float[] xPositions = new float[2];
216 | float[] yPositions = new float[2];
217 | float minX = 0;
218 | float minY = 0;
219 |
220 | for (int i = 0; i < event.getPointerCount(); i++) {
221 | int pointerId = event.getPointerId(i);
222 | if (pointerId == MotionEvent.INVALID_POINTER_ID) {
223 | continue;
224 | }
225 |
226 | if (minX == 0 && minY == 0) {
227 | minX = event.getX(i);
228 | minY = event.getY(i);
229 | } else {
230 | float tempMinX = event.getX(i);
231 | float tempMinY = event.getY(i);
232 | if (tempMinX < minX) {
233 | minX = tempMinX;
234 | }
235 | if (tempMinY < minY) {
236 | minY = tempMinY;
237 | }
238 | }
239 |
240 | xPositions[i] = event.getX(i);
241 | yPositions[i] = event.getY(i);
242 | }
243 |
244 | float circleX = (Math.abs(xPositions[1] - xPositions[0]) / 2) + minX;
245 | float circleY = (Math.abs(yPositions[1] - yPositions[0]) / 2) + minY;
246 |
247 |
248 | mCircle = new Circle(color, circleX, circleY);
249 |
250 | } catch (IndexOutOfBoundsException e) {
251 | Log.e(TAG, "touchEvent: IndexOutOfBoundsException: " + e.getMessage());
252 | }
253 | } else {
254 |
255 | if (!mIsSizeChanging) {
256 |
257 | float eventX = event.getX();
258 | float eventY = event.getY();
259 |
260 | switch (event.getAction()) {
261 | case MotionEvent.ACTION_DOWN:
262 | mPenList.add(new Pen(color, width));
263 | mPenList.get(mPenList.size() - 1).path.moveTo(eventX, eventY);
264 | return true;
265 | case MotionEvent.ACTION_MOVE:
266 | drawingStarted();
267 | mPenList.get(mPenList.size() - 1).path.lineTo(eventX, eventY);
268 | break;
269 | case MotionEvent.ACTION_UP:
270 | drawingStopped();
271 | break;
272 | default:
273 | return false;
274 | }
275 | }
276 | }
277 | }
278 |
279 | if(mStickers.size() > 0){
280 |
281 | int newPositionX = (int)event.getX();
282 | int newPositionY = (int)event.getY();
283 |
284 | switch(event.getAction()){
285 |
286 | case MotionEvent.ACTION_UP:{
287 | Log.d(TAG, "touchEvent: reset sticker index.");
288 |
289 | resetSticker(newPositionX, newPositionY);
290 |
291 | break;
292 | }
293 |
294 | case MotionEvent.ACTION_POINTER_UP:{
295 | Log.d(TAG, "touchEvent: reset sticker index.");
296 |
297 | resetSticker(newPositionX, newPositionY);
298 |
299 | break;
300 | }
301 |
302 | case MotionEvent.ACTION_MOVE:{
303 |
304 | if(mSelectedStickerIndex != -1){
305 |
306 | if(event.getPointerCount() > 1){
307 | mIsStickerResizing = true;
308 | }
309 | else{
310 | mIsStickerResizing = false;
311 |
312 | moveSticker(newPositionX, newPositionY);
313 |
314 | if(trashRect.contains(newPositionX, newPositionY)){
315 | enlargeTrashIcon();
316 | }
317 | else{
318 | shrinkTrashIcon();
319 | }
320 | }
321 | }
322 |
323 | if(mIsStickerResizing){
324 |
325 | moveSticker(newPositionX, newPositionY);
326 |
327 | mScaleGestureDetector.onTouchEvent(event);
328 | }
329 |
330 | break;
331 | }
332 |
333 | case MotionEvent.ACTION_DOWN:{
334 | for(int i = 0; i < mStickers.size(); i++){
335 | if(mStickers.get(i).rect.contains(newPositionX, newPositionY)){
336 | Log.d(TAG, "touchEvent: touched a STICKER.");
337 | mSelectedStickerIndex = i;
338 | mPrevStickerX = newPositionX;
339 | mPrevStickerY = newPositionY;
340 |
341 | dragStickerStarted();
342 |
343 | break; // break the loop
344 | }
345 | }
346 | break;
347 | }
348 |
349 | }
350 |
351 | }
352 |
353 | invalidate();
354 | return true;
355 | }
356 |
357 | private void dragStickerStarted(){
358 | if(mHostActivity != null){
359 | if(mHostActivity instanceof MainActivity){
360 | ((MainActivity)mHostActivity).dragStickerStarted();
361 | }
362 | }
363 | }
364 |
365 | private void dragStickerStopped(){
366 | if(mHostActivity != null){
367 | if(mHostActivity instanceof MainActivity){
368 | ((MainActivity)mHostActivity).dragStickerStopped();
369 | }
370 | }
371 | removeCircle();
372 | }
373 |
374 | public void removeSticker(){
375 | if(mSelectedStickerIndex != -1){
376 | mStickers.remove(mSelectedStickerIndex);
377 | invalidate();
378 | }
379 | }
380 |
381 | public void enlargeTrashIcon(){
382 | if(mHostActivity instanceof MainActivity){
383 | ((MainActivity)mHostActivity).setTrashIconSize(TRASH_ICON_ENLARGED_SIZE, TRASH_ICON_ENLARGED_SIZE);
384 | }
385 | }
386 |
387 | public void shrinkTrashIcon(){
388 | if(mHostActivity instanceof MainActivity){
389 | ((MainActivity)mHostActivity).setTrashIconSize(TRASH_ICON_NORMAL_SIZE, TRASH_ICON_NORMAL_SIZE);
390 | }
391 | }
392 |
393 | private void resetSticker(int newPositionX, int newPositionY){
394 | if(trashRect.contains(newPositionX, newPositionY)){
395 | removeSticker();
396 | }
397 |
398 | mSelectedStickerIndex = -1; // reset the sticker index
399 | mIsStickerResizing = false;
400 |
401 | dragStickerStopped();
402 | shrinkTrashIcon();
403 |
404 | }
405 |
406 | private void moveSticker(int newPositionX, int newPositionY){
407 | int dx = newPositionX - mPrevStickerX;
408 | int dy = newPositionY - mPrevStickerY;
409 |
410 | mPrevStickerX = newPositionX;
411 | mPrevStickerY = newPositionY;
412 |
413 | mStickers.get(mSelectedStickerIndex).x
414 | = mStickers.get(mSelectedStickerIndex).x + dx;
415 |
416 | mStickers.get(mSelectedStickerIndex).y
417 | = mStickers.get(mSelectedStickerIndex).y + dy;
418 |
419 | mStickers.get(mSelectedStickerIndex).adjustRect();
420 | }
421 |
422 |
423 | public void addNewSticker(Drawable drawable){
424 | if(mHostActivity != null){
425 | if(mHostActivity instanceof MainActivity){
426 | Log.d(TAG, "addNewSticker: adding new sticker to canvas.");
427 | Bitmap newStickerBitmap = drawableToBitmap(drawable);
428 |
429 | Sticker sticker = new Sticker(newStickerBitmap, drawable,0, 200);
430 | mStickers.add(sticker);
431 | invalidate();
432 | }
433 | }
434 | }
435 |
436 | private void drawingStarted(){
437 | if(mHostActivity != null){
438 | if(mHostActivity instanceof MainActivity){
439 | ((MainActivity)mHostActivity).hideStillshotWidgets();
440 | }
441 | }
442 | }
443 |
444 | private void drawingStopped(){
445 | if(mHostActivity != null){
446 | if(mHostActivity instanceof MainActivity){
447 | ((MainActivity)mHostActivity).showStillshotWidgets();
448 | }
449 | }
450 | removeCircle();
451 | }
452 |
453 | private void removeCircle(){
454 | mCircle = null;
455 | }
456 |
457 | public void removeLastPath(){
458 | if(mPenList.size() > 0){
459 | mPenList.remove(mPenList.size() - 1);
460 | invalidate();
461 | }
462 | }
463 |
464 |
465 | public void reset() {
466 | for (Pen pen : mPenList) {
467 | pen.path.reset();
468 | }
469 | width = mMinWidth;
470 | mStickers.clear();
471 | invalidate();
472 | }
473 |
474 | public void setBrushColor(int color) {
475 | this.color = color;
476 | }
477 |
478 | public int getBrushColor(){
479 | return color;
480 | }
481 |
482 | public void setWidth(float width) {
483 | this.width = width;
484 | }
485 |
486 |
487 | private void hideStatusBar() {
488 |
489 | if(mHostActivity != null){
490 | View decorView = mHostActivity.getWindow().getDecorView();
491 | // Hide the status bar.
492 | int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
493 | decorView.setSystemUiVisibility(uiOptions);
494 | }
495 |
496 | }
497 |
498 |
499 | public void setDrawingIsEnabled(boolean bool){
500 | mIsDrawingEnabled = bool;
501 | }
502 |
503 | private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
504 |
505 | @Override
506 | public boolean onScaleBegin(ScaleGestureDetector detector) {
507 | return true;
508 | }
509 |
510 | @Override
511 | public boolean onScale(ScaleGestureDetector detector) {
512 | float scaleFactor = detector.getScaleFactor();
513 |
514 | if(scaleFactor > 1.011 || scaleFactor < 0.99) {
515 |
516 | if(mSelectedStickerIndex != -1){
517 | mStickers.get(mSelectedStickerIndex).bitmap
518 | = resizeBitmap(
519 | mStickers.get(mSelectedStickerIndex).drawable,
520 | mStickers.get(mSelectedStickerIndex).bitmap,
521 | scaleFactor
522 | );
523 |
524 | mIsStickerResizing = true;
525 |
526 | }
527 | else{
528 | float prevWidth = width;
529 | if(scaleFactor > 1){
530 | width += ( (SIZE_CHANGE_SPEED + (width * 0.05)) * scaleFactor );
531 | }
532 | else{
533 | width -= ( (SIZE_CHANGE_SPEED + (width * 0.05)) * scaleFactor );
534 | }
535 | if ( width > mMaxWidth) {
536 | width = prevWidth;
537 | }
538 | else if (width < mMinWidth) {
539 | width = prevWidth;
540 | }
541 | }
542 |
543 | }
544 |
545 |
546 | return true;
547 | }
548 | }
549 |
550 | public static Bitmap resizeBitmap(Drawable drawable, Bitmap currentBitmap, float scale){
551 | Bitmap bitmap = null;
552 |
553 | int newWidth = 0;
554 | int newHeight = 0;
555 | if(scale > 1){
556 | newWidth = currentBitmap.getWidth() + (int)((currentBitmap.getWidth() * 0.04) * scale);
557 | newHeight = currentBitmap.getHeight() + (int)((currentBitmap.getHeight() * 0.04) * scale);
558 | }
559 | else{
560 | newWidth = currentBitmap.getWidth() - (int)((currentBitmap.getHeight() * 0.04) * scale);
561 | newHeight = currentBitmap.getHeight() - (int)((currentBitmap.getHeight() * 0.04) * scale);
562 | }
563 |
564 | if(newWidth < MIN_STICKER_WIDTH){
565 | newWidth = currentBitmap.getWidth();
566 | }
567 | if(newHeight < MIN_STICKER_HEIGHT){
568 | newHeight = currentBitmap.getHeight();
569 | }
570 |
571 | if (drawable instanceof BitmapDrawable) {
572 | BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
573 | if(bitmapDrawable.getBitmap() != null) {
574 | return Bitmap.createScaledBitmap(
575 | bitmapDrawable.getBitmap(),
576 | newWidth,
577 | newHeight,
578 | false);
579 | }
580 | }
581 |
582 | if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
583 | bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
584 | }
585 | else {
586 | bitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
587 | }
588 |
589 | Canvas canvas = new Canvas(bitmap);
590 | drawable.setBounds(0, 0, newWidth, newHeight);
591 | drawable.draw(canvas);
592 | return bitmap;
593 | }
594 |
595 | public static Bitmap drawableToBitmap (Drawable drawable) {
596 | Bitmap bitmap = null;
597 |
598 | if (drawable instanceof BitmapDrawable) {
599 | BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
600 | if(bitmapDrawable.getBitmap() != null) {
601 | return Bitmap.createScaledBitmap(bitmapDrawable.getBitmap(), STICKER_STARTING_WIDTH, STICKER_STARTING_HEIGHT, false);
602 | }
603 | }
604 |
605 | if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
606 | bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
607 | }
608 | else {
609 | bitmap = Bitmap.createBitmap(STICKER_STARTING_WIDTH, STICKER_STARTING_WIDTH, Bitmap.Config.ARGB_8888);
610 | }
611 |
612 | Canvas canvas = new Canvas(bitmap);
613 | drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
614 | drawable.draw(canvas);
615 | return bitmap;
616 | }
617 | }
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/ICallback.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
2 |
3 | /**
4 | * Created by User on 6/4/2018.
5 | */
6 |
7 | public interface ICallback {
8 |
9 | void done(Exception e);
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/IMainActivity.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
2 |
3 | import android.graphics.drawable.Drawable;
4 |
5 | /**
6 | * Created by User on 6/5/2018.
7 | */
8 |
9 | public interface IMainActivity {
10 |
11 | void setCameraFrontFacing();
12 |
13 | void setCameraBackFacing();
14 |
15 | boolean isCameraFrontFacing();
16 |
17 | boolean isCameraBackFacing();
18 |
19 | void setFrontCameraId(String cameraId);
20 |
21 | void setBackCameraId(String cameraId);
22 |
23 | String getFrontCameraId();
24 |
25 | String getBackCameraId();
26 |
27 | void hideStatusBar();
28 |
29 | void showStatusBar();
30 |
31 | void hideStillshotWidgets();
32 |
33 | void showStillshotWidgets();
34 |
35 | void toggleViewStickersFragment();
36 |
37 | void addSticker(Drawable sticker);
38 |
39 | void setTrashIconSize(int width, int height);
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/MainActivity.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.pm.PackageManager;
7 | import android.graphics.drawable.Drawable;
8 | import android.os.Bundle;
9 | import android.support.annotation.NonNull;
10 | import android.support.design.widget.Snackbar;
11 | import android.support.v4.app.ActivityCompat;
12 | import android.support.v4.app.FragmentTransaction;
13 | import android.support.v4.content.ContextCompat;
14 | import android.support.v7.app.AppCompatActivity;
15 | import android.util.DisplayMetrics;
16 | import android.util.Log;
17 | import android.view.View;
18 | import android.widget.Toast;
19 |
20 | public class MainActivity extends AppCompatActivity implements IMainActivity{
21 |
22 | private static final String TAG = "MainActivity";
23 | private static final int REQUEST_CODE = 1234;
24 | public static String CAMERA_POSITION_FRONT;
25 | public static String CAMERA_POSITION_BACK;
26 | public static String MAX_ASPECT_RATIO;
27 |
28 | //widgets
29 |
30 | //vars
31 | private boolean mPermissions;
32 | public String mCameraOrientation = "none"; // Front-facing or back-facing
33 |
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setContentView(R.layout.activity_main);
39 |
40 | init();
41 | }
42 |
43 | private void startCamera2(){
44 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
45 | transaction.replace(R.id.camera_container, Camera2Fragment.newInstance(), getString(R.string.fragment_camera2));
46 | transaction.commit();
47 | }
48 |
49 | private void init(){
50 | if(mPermissions){
51 | if(checkCameraHardware(this)){
52 |
53 | // Open the Camera
54 | startCamera2();
55 | }
56 | else{
57 | showSnackBar("You need a camera to use this application", Snackbar.LENGTH_INDEFINITE);
58 | }
59 | }
60 | else{
61 | verifyPermissions();
62 | }
63 | }
64 |
65 | /** Check if this device has a camera */
66 | private boolean checkCameraHardware(Context context) {
67 | if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
68 | // this device has a camera
69 | return true;
70 | } else {
71 | // no camera on this device
72 | return false;
73 | }
74 | }
75 |
76 | public void verifyPermissions(){
77 | Log.d(TAG, "verifyPermissions: asking user for permissions.");
78 | String[] permissions = {
79 | android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
80 | Manifest.permission.CAMERA};
81 | if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
82 | permissions[0] ) == PackageManager.PERMISSION_GRANTED
83 | && ContextCompat.checkSelfPermission(this.getApplicationContext(),
84 | permissions[1] ) == PackageManager.PERMISSION_GRANTED) {
85 | mPermissions = true;
86 | init();
87 | } else {
88 | ActivityCompat.requestPermissions(
89 | MainActivity.this,
90 | permissions,
91 | REQUEST_CODE
92 | );
93 | }
94 | }
95 |
96 | @Override
97 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
98 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
99 |
100 | if(requestCode == REQUEST_CODE){
101 | if(mPermissions){
102 | init();
103 | }
104 | else{
105 | verifyPermissions();
106 | }
107 | }
108 | }
109 |
110 |
111 | private void showSnackBar(final String text, final int length) {
112 | View view = this.findViewById(android.R.id.content).getRootView();
113 | Snackbar.make(view, text, length).show();
114 | }
115 |
116 | @Override
117 | public void setCameraFrontFacing() {
118 | Log.d(TAG, "setCameraFrontFacing: setting camera to front facing.");
119 | mCameraOrientation = CAMERA_POSITION_FRONT;
120 | }
121 |
122 | @Override
123 | public void setCameraBackFacing() {
124 | Log.d(TAG, "setCameraBackFacing: setting camera to back facing.");
125 | mCameraOrientation = CAMERA_POSITION_BACK;
126 | }
127 |
128 | @Override
129 | public void setFrontCameraId(String cameraId){
130 | CAMERA_POSITION_FRONT = cameraId;
131 | }
132 |
133 |
134 | @Override
135 | public void setBackCameraId(String cameraId){
136 | CAMERA_POSITION_BACK = cameraId;
137 | }
138 |
139 | @Override
140 | public boolean isCameraFrontFacing() {
141 | if(mCameraOrientation.equals(CAMERA_POSITION_FRONT)){
142 | return true;
143 | }
144 | return false;
145 | }
146 |
147 | @Override
148 | public boolean isCameraBackFacing() {
149 | if(mCameraOrientation.equals(CAMERA_POSITION_BACK)){
150 | return true;
151 | }
152 | return false;
153 | }
154 |
155 | @Override
156 | public String getBackCameraId(){
157 | return CAMERA_POSITION_BACK;
158 | }
159 |
160 | @Override
161 | public String getFrontCameraId(){
162 | return CAMERA_POSITION_FRONT;
163 | }
164 |
165 | @Override
166 | public void hideStatusBar() {
167 |
168 | View decorView = getWindow().getDecorView();
169 | // Hide the status bar.
170 | int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
171 | decorView.setSystemUiVisibility(uiOptions);
172 | }
173 |
174 | @Override
175 | public void showStatusBar() {
176 |
177 | View decorView = getWindow().getDecorView();
178 | // Hide the status bar.
179 | int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
180 | decorView.setSystemUiVisibility(uiOptions);
181 | }
182 |
183 | @Override
184 | public void hideStillshotWidgets() {
185 | Camera2Fragment camera2Fragment = (Camera2Fragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.fragment_camera2));
186 | if (camera2Fragment != null) {
187 | if(camera2Fragment.isVisible()){
188 | camera2Fragment.drawingStarted();
189 | }
190 | }
191 | }
192 |
193 | @Override
194 | public void showStillshotWidgets() {
195 | Camera2Fragment camera2Fragment = (Camera2Fragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.fragment_camera2));
196 | if (camera2Fragment != null) {
197 | if(camera2Fragment.isVisible()){
198 | camera2Fragment.drawingStopped();
199 | }
200 | }
201 | }
202 |
203 | @Override
204 | public void toggleViewStickersFragment(){
205 |
206 | ViewStickersFragment viewStickersFragment
207 | = (ViewStickersFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.fragment_view_stickers));
208 | if (viewStickersFragment != null) {
209 | if(viewStickersFragment.isVisible()){
210 | hideViewStickersFragment(viewStickersFragment);
211 | }
212 | else{
213 | showViewStickersFragment(viewStickersFragment);
214 | }
215 | }
216 | else{
217 | inflateViewStickersFragment();
218 | }
219 | }
220 |
221 | private void hideViewStickersFragment(ViewStickersFragment fragment){
222 |
223 | showStillshotWidgets();
224 |
225 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
226 | transaction.setCustomAnimations(R.anim.slide_in_up, R.anim.slide_in_down, R.anim.slide_out_down, R.anim.slide_out_up);
227 | transaction.hide(fragment);
228 | transaction.commit();
229 | }
230 |
231 | private void showViewStickersFragment(ViewStickersFragment fragment){
232 |
233 | hideStillshotWidgets();
234 |
235 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
236 | transaction.setCustomAnimations(R.anim.slide_in_up, R.anim.slide_in_down, R.anim.slide_out_down, R.anim.slide_out_up);
237 | transaction.show(fragment);
238 | transaction.commit();
239 | }
240 |
241 | private void inflateViewStickersFragment(){
242 |
243 | hideStillshotWidgets();
244 |
245 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
246 | transaction.setCustomAnimations(R.anim.slide_in_up, R.anim.slide_in_down, R.anim.slide_out_down, R.anim.slide_out_up);
247 | transaction.add(R.id.camera_container, ViewStickersFragment.newInstance(), getString(R.string.fragment_view_stickers));
248 | transaction.commit();
249 | }
250 |
251 | @Override
252 | public void addSticker(Drawable sticker){
253 | Camera2Fragment camera2Fragment = (Camera2Fragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.fragment_camera2));
254 | if (camera2Fragment != null) {
255 | if(camera2Fragment.isVisible()){
256 | camera2Fragment.addSticker(sticker);
257 | }
258 | }
259 | }
260 |
261 | @Override
262 | public void setTrashIconSize(int width, int height){
263 | Camera2Fragment camera2Fragment = (Camera2Fragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.fragment_camera2));
264 | if (camera2Fragment != null) {
265 | if(camera2Fragment.isVisible()){
266 | camera2Fragment.setTrashIconSize(width, height);
267 | }
268 | }
269 | }
270 |
271 | public void dragStickerStarted(){
272 | Camera2Fragment camera2Fragment = (Camera2Fragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.fragment_camera2));
273 | if (camera2Fragment != null) {
274 | if(camera2Fragment.isVisible()){
275 | camera2Fragment.dragStickerStarted();
276 | }
277 | }
278 | }
279 |
280 | public void dragStickerStopped(){
281 | Camera2Fragment camera2Fragment = (Camera2Fragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.fragment_camera2));
282 | if (camera2Fragment != null) {
283 | if(camera2Fragment.isVisible()){
284 | camera2Fragment.dragStickerStopped();
285 | }
286 | }
287 | }
288 | }
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/ScalingTextureView.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
2 |
3 | /**
4 | * Created by User on 5/21/2018.
5 | */
6 |
7 | import android.annotation.TargetApi;
8 | import android.content.Context;
9 | import android.graphics.Matrix;
10 | import android.graphics.PointF;
11 | import android.os.Build;
12 | import android.util.AttributeSet;
13 | import android.util.Log;
14 | import android.view.MotionEvent;
15 | import android.view.ScaleGestureDetector;
16 | import android.view.TextureView;
17 | import android.view.View;
18 |
19 | import codingwithmitch.com.tabiancustomcamera.gestures.MoveGestureDetector;
20 |
21 | /**
22 | * A {@link TextureView} that can be adjusted to a specified aspect ratio.
23 | */
24 | public class ScalingTextureView extends TextureView {
25 |
26 | private static final String TAG = "ScalingTextureView";
27 |
28 | public int mRatioWidth = 0;
29 | public int mRatioHeight = 0;
30 | private int mScreenWidth = 0;
31 | private int mScreenHeight = 0;
32 | private String mRoundedScreenAspectRatio = "";
33 | private String mRoundedPreviewAspectRatio = "";
34 |
35 | private Matrix mMatrix;
36 |
37 | private ScaleGestureDetector mScaleDetector;
38 |
39 | private MoveGestureDetector mMoveDetector;
40 |
41 | // scaling
42 | public float mScaleFactor = 1.f;
43 | public float mScaleFactorX = 1.f;
44 | public float mScaleFactorY = 1.f;
45 | public float mWidthCorrection = 0f;
46 | float mScreenAspectRatio = 1f;
47 | float mPreviewAspectRatio = 1f;
48 |
49 | public float mImageCenterX = 0.f;
50 |
51 | public float mImageCenterY = 0.f;
52 |
53 | public float mFocusX = 0.f;
54 |
55 | public float mFocusY = 0.f;
56 |
57 |
58 | public ScalingTextureView(Context context) {
59 | this(context, null);
60 | init(context);
61 | }
62 |
63 | public ScalingTextureView(Context context, AttributeSet attrs) {
64 | this(context, attrs,0);
65 | init(context);
66 | }
67 |
68 | public ScalingTextureView(Context context, AttributeSet attrs, int defStyle) {
69 | super(context, attrs, defStyle);
70 | init(context);
71 | }
72 |
73 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
74 | public ScalingTextureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
75 | super(context, attrs, defStyleAttr, defStyleRes);
76 | init(context);
77 | }
78 |
79 | /**
80 | * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
81 | * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
82 | * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
83 | *
84 | * @param width Relative horizontal size
85 | * @param height Relative vertical size
86 | */
87 | public void setAspectRatio(int width, int height, int screenWidth, int screenHeight) {
88 | if (width < 0 || height < 0) {
89 | throw new IllegalArgumentException("Size cannot be negative.");
90 | }
91 | mRatioWidth = width;
92 | mRatioHeight = height;
93 | requestLayout();
94 | mScreenWidth = screenWidth;
95 | mScreenHeight = screenHeight;
96 |
97 | mScreenAspectRatio = (float)mScreenHeight / (float)mScreenWidth;
98 | mPreviewAspectRatio = (float)mRatioHeight / (float)mRatioWidth;
99 | mRoundedScreenAspectRatio = String.format("%.2f", mScreenAspectRatio);
100 | mRoundedPreviewAspectRatio = String.format("%.2f", mPreviewAspectRatio);
101 | getWidthCorrection();
102 | }
103 |
104 | @Override
105 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
106 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
107 | int width = MeasureSpec.getSize(widthMeasureSpec);
108 | int height = MeasureSpec.getSize(heightMeasureSpec);
109 | if (0 == mRatioWidth || 0 == mRatioHeight) {
110 | setMeasuredDimension(width, height);
111 | }
112 | setMeasuredDimension(mScreenWidth, mScreenHeight);
113 |
114 | }
115 |
116 |
117 | private void init(Context context) {
118 |
119 | mMatrix = new Matrix();
120 |
121 | // Setup Gesture Detectors
122 | mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
123 |
124 | mMoveDetector = new MoveGestureDetector(context, new MoveListener());
125 | }
126 |
127 | private void getWidthCorrection(){
128 | String roundedScreenAspectRatio = String.format("%.2f", mScreenAspectRatio);
129 | String roundedPreviewAspectRatio = String.format("%.2f", mPreviewAspectRatio);
130 | if(!roundedPreviewAspectRatio.equals(roundedScreenAspectRatio) ){
131 |
132 | float scaleFactor = (mScreenAspectRatio / mPreviewAspectRatio);
133 | Log.d(TAG, "configureTransform: scale factor: " + scaleFactor);
134 |
135 | mWidthCorrection = (((float)mScreenWidth * scaleFactor) - mScreenWidth) / 2;
136 | Log.d(TAG, "getWidthCorrection: width correction: " + mWidthCorrection);
137 | }
138 | }
139 |
140 |
141 | public boolean onTouch(MotionEvent motionEvent) {
142 |
143 | mScaleDetector.onTouchEvent(motionEvent);
144 |
145 | mMoveDetector.onTouchEvent(motionEvent);
146 |
147 | if(mScaleFactor > 1.011111 || mScaleFactor < 0.99999) {
148 |
149 | mMatrix.reset();
150 |
151 | Log.d(TAG, "onTouch: scale factor: " + mScaleFactor);
152 |
153 | mScaleFactorY = mScaleFactor;
154 | mScaleFactorX = mScaleFactor;
155 |
156 |
157 | if(!mRoundedPreviewAspectRatio.equals(mRoundedScreenAspectRatio) ){
158 |
159 | mScaleFactorX *= (mScreenAspectRatio / mPreviewAspectRatio);
160 | Log.d(TAG, "configureTransform: scale factor: " + mScaleFactorX);
161 | }
162 |
163 | float scaledImageCenterX = (getWidth() * mScaleFactorX) / 2;
164 |
165 | float scaledImageCenterY = (getHeight() * mScaleFactorY) / 2;
166 |
167 |
168 | mMatrix.postScale(mScaleFactorX, mScaleFactorY);
169 |
170 | float dx = mImageCenterX - scaledImageCenterX;
171 |
172 | float dy = mImageCenterY - scaledImageCenterY;
173 |
174 | Log.d(TAG, "onTouch: dx: " + dx + ", dy: " + dy);
175 |
176 |
177 | // BOUNDARY 1: Right
178 | if (dx < (getWidth() - (((float)mScreenWidth - mWidthCorrection) * mScaleFactorX))) {
179 |
180 | dx = (getWidth() - (((float)mScreenWidth - mWidthCorrection) * mScaleFactorX));
181 |
182 | mImageCenterX = dx + scaledImageCenterX; // reverse the changes
183 |
184 | }
185 |
186 | //BOUNDARY 2: Bottom
187 | if (dy < (getHeight() - ((float)mScreenHeight * mScaleFactorY))) {
188 |
189 | dy = (getHeight() - ((float)mScreenHeight * mScaleFactorY));
190 |
191 | mImageCenterY = dy + scaledImageCenterY;
192 |
193 | }
194 |
195 |
196 | // BOUNDARY 3: Left
197 | if (dx > -mWidthCorrection) {
198 |
199 | dx = -mWidthCorrection;
200 |
201 | mImageCenterX = dx + scaledImageCenterX;
202 | }
203 |
204 |
205 | // BOUNDARY 4: Top
206 | if (dy > 0) {
207 |
208 | dy = 0;
209 |
210 | mImageCenterY = dy + scaledImageCenterY;
211 | }
212 |
213 | mMatrix.postTranslate(dx, dy);
214 |
215 | setTransform(mMatrix);
216 |
217 | setAlpha(1);
218 |
219 | mFocusX = -1 * (dx / mScaleFactorX);
220 | mFocusY = -1 * (dy / mScaleFactorY);
221 | }
222 | return true; // indicate event was handled
223 |
224 | }
225 |
226 |
227 | private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
228 | @Override
229 | public boolean onScale(ScaleGestureDetector detector) {
230 |
231 | mScaleFactor *= detector.getScaleFactor(); // scale change since previous event
232 |
233 | // Don't let the object get too small or too large.
234 | mScaleFactor = Math.max(1.f, Math.min(mScaleFactor, 4.0f));
235 |
236 | return true;
237 | }
238 | }
239 |
240 | private class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener {
241 | @Override
242 | public boolean onMove(MoveGestureDetector detector) {
243 |
244 | PointF d = detector.getFocusDelta();
245 |
246 | mImageCenterX += d.x;
247 |
248 | mImageCenterY += d.y;
249 |
250 | Log.d(TAG, "onMove: image center x: " + mImageCenterX);
251 | Log.d(TAG, "onMove: image canter y: " + mImageCenterY);
252 |
253 | return true;
254 | }
255 | }
256 |
257 | public void resetScale(){
258 | mScaleFactor = 1.0f;
259 | mScaleFactorX = 1f;
260 | mScaleFactorY = 1f;
261 | mImageCenterX = mRatioWidth / 2;
262 | mImageCenterX = mRatioHeight / 2;
263 | mFocusX = 0f;
264 | mFocusY = 0f;
265 | }
266 |
267 | }
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/StickerAdapter.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.support.annotation.NonNull;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.util.Log;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.ImageView;
12 |
13 | import com.bumptech.glide.Glide;
14 |
15 | import java.util.ArrayList;
16 |
17 | /**
18 | * Created by User on 5/24/2018.
19 | */
20 |
21 | public class StickerAdapter extends RecyclerView.Adapter {
22 |
23 | private static final String TAG = "StickerAdapter";
24 |
25 | private ArrayList mStickers = new ArrayList<>();
26 | private RecyclerViewClickListener mClickListener;
27 | private Context mContext;
28 |
29 |
30 | public StickerAdapter(Context context, ArrayList stickers, RecyclerViewClickListener clickListener) {
31 | mStickers = stickers;
32 | mClickListener = clickListener;
33 | mContext = context;
34 | }
35 |
36 |
37 | @NonNull
38 | @Override
39 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
40 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_sticker_list_item, parent, false);
41 | final ViewHolder holder = new ViewHolder(view, mClickListener);
42 | return holder;
43 | }
44 |
45 | @Override
46 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
47 |
48 | Glide.with(mContext)
49 | .load(mStickers.get(position))
50 | .into(((ViewHolder)holder).image);
51 | }
52 |
53 | @Override
54 | public int getItemCount() {
55 | return mStickers.size();
56 | }
57 |
58 |
59 | public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
60 |
61 | ImageView image;
62 | RecyclerViewClickListener clickListener;
63 |
64 | public ViewHolder(View itemView, RecyclerViewClickListener clickListener) {
65 | super(itemView);
66 | image = itemView.findViewById(R.id.sticker_image);
67 | this.clickListener = clickListener;
68 |
69 | itemView.setOnClickListener(this);
70 | }
71 |
72 | @Override
73 | public void onClick(View view) {
74 | if(clickListener != null){
75 | Log.d(TAG, "onClick: clicked.");
76 | clickListener.onStickerClicked(getAdapterPosition());
77 | }
78 | }
79 | }
80 |
81 | public interface RecyclerViewClickListener{
82 | void onStickerClicked(int position);
83 | }
84 | }
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/Utility.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
2 |
3 | import android.util.Log;
4 | import android.util.Size;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Collections;
8 | import java.util.Comparator;
9 | import java.util.List;
10 |
11 | /**
12 | * Created by User on 5/29/2018.
13 | */
14 |
15 | public class Utility {
16 |
17 | /**
18 | * Compares two {@code Size}s based on their areas.
19 | */
20 | static class CompareSizesByArea implements Comparator {
21 |
22 | public static CompareSizesByArea newInstance(){
23 | return new CompareSizesByArea();
24 | }
25 | @Override
26 | public int compare(Size lhs, Size rhs) {
27 | // We cast here to ensure the multiplications won't overflow
28 | return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
29 | (long) rhs.getWidth() * rhs.getHeight());
30 | }
31 |
32 | }
33 |
34 | /**
35 | * Given {@code choices} of {@code Size}s supported by a camera, choose the smallest one that
36 | * is at least as large as the respective texture view size, and that is at most as large as the
37 | * respective max size, and whose aspect ratio matches with the specified value. If such size
38 | * doesn't exist, choose the largest one that is at most as large as the respective max size,
39 | * and whose aspect ratio matches with the specified value.
40 | *
41 | * @param choices The list of sizes that the camera supports for the intended output
42 | * class
43 | * @param textureViewWidth The width of the texture view relative to sensor coordinate
44 | * @param textureViewHeight The height of the texture view relative to sensor coordinate
45 | * @param maxWidth The maximum width that can be chosen
46 | * @param maxHeight The maximum height that can be chosen
47 | * @param aspectRatio The aspect ratio
48 | * @return The optimal {@code Size}, or an arbitrary one if none were big enough
49 | */
50 | static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
51 | int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
52 |
53 | // Collect the supported resolutions that are at least as big as the preview Surface
54 | List bigEnough = new ArrayList<>();
55 | // Collect the supported resolutions that are smaller than the preview Surface
56 | List notBigEnough = new ArrayList<>();
57 | int w = aspectRatio.getWidth();
58 | int h = aspectRatio.getHeight();
59 | for (Size option : choices) {
60 | // Log.d(TAG, "chooseOptimalSize: w: " + option.getWidth() + ", h: " + option.getHeight());
61 |
62 | if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
63 | option.getHeight() == option.getWidth() * h / w) {
64 | if (option.getWidth() >= textureViewWidth &&
65 | option.getHeight() >= textureViewHeight) {
66 | bigEnough.add(option);
67 | } else {
68 | notBigEnough.add(option);
69 | }
70 | }
71 | }
72 |
73 | // Pick the smallest of those big enough. If there is no one big enough, pick the
74 | // largest of those not big enough.
75 | if (bigEnough.size() > 0) {
76 | return Collections.min(bigEnough, new CompareSizesByArea());
77 | } else if (notBigEnough.size() > 0) {
78 | return Collections.max(notBigEnough, new CompareSizesByArea());
79 | } else {
80 | return choices[0];
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/VerticalSlideColorPicker.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.LinearGradient;
9 | import android.graphics.Paint;
10 | import android.graphics.Path;
11 | import android.graphics.RectF;
12 | import android.graphics.Shader;
13 | import android.util.AttributeSet;
14 | import android.view.MotionEvent;
15 | import android.view.View;
16 |
17 |
18 | public class VerticalSlideColorPicker extends View {
19 |
20 | private Paint paint;
21 | private Paint strokePaint;
22 | private Path path;
23 | private Bitmap bitmap;
24 | private int viewWidth;
25 | private int viewHeight;
26 | private int centerX;
27 | private float colorPickerRadius;
28 | private OnColorChangeListener onColorChangeListener;
29 | private RectF colorPickerBody;
30 | private float selectorYPos;
31 | private int borderColor;
32 | private float borderWidth;
33 | private int[] colors;
34 | private boolean cacheBitmap = true;
35 |
36 | public VerticalSlideColorPicker(Context context) {
37 | super(context);
38 | init();
39 | }
40 |
41 | public VerticalSlideColorPicker(Context context, AttributeSet attrs) {
42 | super(context, attrs);
43 | TypedArray a = context.getTheme().obtainStyledAttributes(
44 | attrs,
45 | R.styleable.VerticalSlideColorPicker,
46 | 0, 0);
47 |
48 | try {
49 | borderColor = a.getColor(R.styleable.VerticalSlideColorPicker_borderColor, Color.WHITE);
50 | borderWidth = a.getDimension(R.styleable.VerticalSlideColorPicker_borderWidth, 10f);
51 | int colorsResourceId = a.getResourceId(R.styleable.VerticalSlideColorPicker_colors, R.array.default_colors);
52 | colors = a.getResources().getIntArray(colorsResourceId);
53 | } finally {
54 | a.recycle();
55 | }
56 | init();
57 | }
58 |
59 | public VerticalSlideColorPicker(Context context, AttributeSet attrs, int defStyleAttr) {
60 | super(context, attrs, defStyleAttr);
61 | init();
62 | }
63 |
64 | public VerticalSlideColorPicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
65 | super(context, attrs, defStyleAttr, defStyleRes);
66 | init();
67 | }
68 |
69 | private void init() {
70 | setWillNotDraw(false);
71 | paint = new Paint();
72 | paint.setStyle(Paint.Style.FILL);
73 | paint.setAntiAlias(true);
74 |
75 | path = new Path();
76 |
77 | strokePaint = new Paint();
78 | strokePaint.setStyle(Paint.Style.STROKE);
79 | strokePaint.setColor(borderColor);
80 | strokePaint.setAntiAlias(true);
81 | strokePaint.setStrokeWidth(borderWidth);
82 |
83 | setDrawingCacheEnabled(true);
84 |
85 | }
86 |
87 | @Override
88 | protected void onDraw(Canvas canvas) {
89 | super.onDraw(canvas);
90 |
91 | path.addCircle(centerX, borderWidth + colorPickerRadius, colorPickerRadius, Path.Direction.CW);
92 | path.addRect(colorPickerBody, Path.Direction.CW);
93 | path.addCircle(centerX, viewHeight - (borderWidth + colorPickerRadius), colorPickerRadius, Path.Direction.CW);
94 |
95 | canvas.drawPath(path, strokePaint);
96 | canvas.drawPath(path, paint);
97 |
98 | if (cacheBitmap) {
99 | bitmap = getDrawingCache();
100 | cacheBitmap = false;
101 | invalidate();
102 | } else {
103 | canvas.drawLine(colorPickerBody.left, selectorYPos, colorPickerBody.right, selectorYPos, strokePaint);
104 | }
105 | }
106 |
107 | @Override
108 | public boolean onTouchEvent(MotionEvent event) {
109 |
110 | float yPos = Math.min(event.getY(), colorPickerBody.bottom);
111 | yPos = Math.max(colorPickerBody.top, yPos);
112 |
113 | selectorYPos = yPos;
114 | int selectedColor = bitmap.getPixel(viewWidth/2, (int) selectorYPos);
115 |
116 | if (onColorChangeListener != null) {
117 | onColorChangeListener.onColorChange(selectedColor);
118 | }
119 |
120 | invalidate();
121 |
122 | return true;
123 | }
124 |
125 | @Override
126 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
127 | super.onSizeChanged(w, h, oldw, oldh);
128 |
129 | viewWidth = w;
130 | viewHeight = h;
131 |
132 | centerX = viewWidth/2;
133 | colorPickerRadius = (viewWidth/2) - borderWidth;
134 |
135 | colorPickerBody = new RectF(centerX - colorPickerRadius, borderWidth + colorPickerRadius, centerX + colorPickerRadius, viewHeight - (borderWidth + colorPickerRadius));
136 |
137 | LinearGradient gradient = new LinearGradient(0, colorPickerBody.top, 0, colorPickerBody.bottom, colors, null, Shader.TileMode.CLAMP);
138 | paint.setShader(gradient);
139 |
140 | resetToDefault();
141 | }
142 |
143 | public void setBorderColor(int borderColor) {
144 | this.borderColor = borderColor;
145 | invalidate();
146 | }
147 |
148 | public void setBorderWidth(float borderWidth) {
149 | this.borderWidth = borderWidth;
150 | invalidate();
151 | }
152 |
153 | public void setColors(int[] colors) {
154 | this.colors = colors;
155 | cacheBitmap = true;
156 | invalidate();
157 | }
158 |
159 | public void resetToDefault() {
160 | selectorYPos = borderWidth + colorPickerRadius;
161 |
162 | if (onColorChangeListener != null) {
163 | onColorChangeListener.onColorChange(Color.TRANSPARENT);
164 | }
165 |
166 | invalidate();
167 | }
168 |
169 | public void setOnColorChangeListener(OnColorChangeListener onColorChangeListener) {
170 | this.onColorChangeListener = onColorChangeListener;
171 | }
172 |
173 | public interface OnColorChangeListener {
174 |
175 | void onColorChange(int selectedColor);
176 | }
177 | }
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/ViewStickersFragment.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.os.Bundle;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.app.Fragment;
9 | import android.support.v7.widget.GridLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.util.Log;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 |
16 | import java.util.ArrayList;
17 |
18 | /**
19 | * Created by User on 5/24/2018.
20 | */
21 |
22 | public class ViewStickersFragment extends Fragment implements
23 | StickerAdapter.RecyclerViewClickListener,
24 | View.OnClickListener
25 | {
26 |
27 | private static final String TAG = "ViewStickersFragment";
28 | private static final int NUM_COLUMNS = 3;
29 |
30 | //widgets
31 | private RecyclerView mRecyclerView;
32 |
33 | //vars
34 | private ArrayList mStickers = new ArrayList<>();
35 | private IMainActivity mIMainActivity;
36 | private StickerAdapter mStickerAdapter;
37 |
38 | public static ViewStickersFragment newInstance() {
39 | return new ViewStickersFragment();
40 | }
41 |
42 | @Nullable
43 | @Override
44 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
45 | View view = inflater.inflate(R.layout.fragment_view_stickers, container, false);
46 | view.findViewById(R.id.init_sticker_icon).setOnClickListener(this);
47 | mRecyclerView = view.findViewById(R.id.recycler_view);
48 |
49 | getStickers();
50 | initRecyclerView();
51 |
52 | return view;
53 | }
54 |
55 | private void initRecyclerView(){
56 | if(mStickerAdapter == null){
57 | mStickerAdapter = new StickerAdapter(getActivity(), mStickers , this);
58 | }
59 | mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), NUM_COLUMNS));
60 | mRecyclerView.setAdapter(mStickerAdapter);
61 | }
62 |
63 | private void getStickers(){
64 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.astonished_face_emoji));
65 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.cry_emoji));
66 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.nerd_emoji));
67 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.sad_emoji));
68 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.slightly_smiling_face_emoji));
69 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.smiley_face_emoji));
70 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.smiley_face_tightly_closed_eyes_emoji));
71 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.smiley_smiling_eyes_emoji));
72 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.smiley_with_sweat_emoji));
73 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.smirking_emoji));
74 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.sunglasses_emoji));
75 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.tears_of_joy_emoji));
76 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.unamused_emoji));
77 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.upside_down_face_emoji));
78 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.ic_undo_small));
79 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.evil_monkey_emoji));
80 | mStickers.add(getActivity().getResources().getDrawable(R.drawable.penguin_emoji));
81 | }
82 |
83 | @Override
84 | public void onStickerClicked(int position) {
85 | mIMainActivity.addSticker(mStickers.get(position));
86 |
87 | mIMainActivity.toggleViewStickersFragment();
88 | }
89 |
90 | @Override
91 | public void onClick(View view) {
92 |
93 | switch (view.getId()){
94 |
95 | case R.id.init_sticker_icon:{
96 | mIMainActivity.toggleViewStickersFragment();
97 | break;
98 | }
99 | }
100 | }
101 |
102 | @Override
103 | public void onAttach(Context context) {
104 | super.onAttach(context);
105 | try{
106 | mIMainActivity = (IMainActivity) getActivity();
107 | }catch (ClassCastException e){
108 | Log.e(TAG, "onAttach: ClassCastException: " + e.getMessage() );
109 | }
110 | }
111 | }
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/gestures/BaseGestureDetector.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera.gestures;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 | import android.view.MotionEvent;
6 |
7 | /**
8 | * @author Almer Thie (code.almeros.com)
9 | * Copyright (c) 2013, Almer Thie (code.almeros.com)
10 | *
11 | * All rights reserved.
12 | *
13 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
14 | *
15 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
16 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
17 | * in the documentation and/or other materials provided with the distribution.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25 | * OF SUCH DAMAGE.
26 | */
27 |
28 |
29 | public abstract class BaseGestureDetector {
30 |
31 | private static final String TAG = "BaseGestureDetector";
32 |
33 | protected final Context mContext;
34 | protected boolean mGestureInProgress;
35 |
36 | protected MotionEvent mPrevEvent;
37 | protected MotionEvent mCurrEvent;
38 |
39 | protected float mCurrPressure;
40 | protected float mPrevPressure;
41 | protected long mTimeDelta;
42 |
43 |
44 | /**
45 | * This value is the threshold ratio between the previous combined pressure
46 | * and the current combined pressure. When pressure decreases rapidly
47 | * between events the position values can often be imprecise, as it usually
48 | * indicates that the user is in the process of lifting a pointer off of the
49 | * device. This value was tuned experimentally.
50 | */
51 | protected static final float PRESSURE_THRESHOLD = 0.67f;
52 |
53 |
54 | public BaseGestureDetector(Context context) {
55 | mContext = context;
56 | }
57 |
58 | /**
59 | * All gesture detectors need to be called through this method to be able to
60 | * detect gestures. This method delegates work to handler methods
61 | * (handleStartProgressEvent, handleInProgressEvent) implemented in
62 | * extending classes.
63 | *
64 | * @param event
65 | * @return
66 | */
67 | public boolean onTouchEvent(MotionEvent event){
68 | final int actionCode = event.getAction() & MotionEvent.ACTION_MASK;
69 | if (!mGestureInProgress) {
70 | handleStartProgressEvent(actionCode, event);
71 | } else {
72 | handleInProgressEvent(actionCode, event);
73 | }
74 | return true;
75 | }
76 |
77 | /**
78 | * Called when the current event occurred when NO gesture is in progress
79 | * yet. The handling in this implementation may set the gesture in progress
80 | * (via mGestureInProgress) or out of progress
81 | * @param actionCode
82 | * @param event
83 | */
84 | protected abstract void handleStartProgressEvent(int actionCode, MotionEvent event);
85 |
86 | /**
87 | * Called when the current event occurred when a gesture IS in progress. The
88 | * handling in this implementation may set the gesture out of progress (via
89 | * mGestureInProgress).
90 | * @param event
91 | */
92 | protected abstract void handleInProgressEvent(int actionCode, MotionEvent event);
93 |
94 |
95 | protected void updateStateByEvent(MotionEvent curr){
96 | final MotionEvent prev = mPrevEvent;
97 |
98 | // Reset mCurrEvent
99 | if (mCurrEvent != null) {
100 | mCurrEvent.recycle();
101 | mCurrEvent = null;
102 | }
103 |
104 | try{
105 | mCurrEvent = MotionEvent.obtain(curr);
106 |
107 |
108 | // Delta time
109 | mTimeDelta = curr.getEventTime() - prev.getEventTime();
110 |
111 | // Pressure
112 | mCurrPressure = curr.getPressure(curr.getActionIndex());
113 | mPrevPressure = prev.getPressure(prev.getActionIndex());
114 | }catch (NullPointerException e){
115 | Log.e(TAG, "updateStateByEvent: NullPointerException: " + e.getMessage() );
116 | }
117 |
118 | }
119 |
120 | protected void resetState() {
121 | if (mPrevEvent != null) {
122 | mPrevEvent.recycle();
123 | mPrevEvent = null;
124 | }
125 | if (mCurrEvent != null) {
126 | mCurrEvent.recycle();
127 | mCurrEvent = null;
128 | }
129 | mGestureInProgress = false;
130 | }
131 |
132 |
133 | /**
134 | * Returns {@code true} if a gesture is currently in progress.
135 | * @return {@code true} if a gesture is currently in progress, {@code false} otherwise.
136 | */
137 | public boolean isInProgress() {
138 | return mGestureInProgress;
139 | }
140 |
141 | /**
142 | * Return the time difference in milliseconds between the previous accepted
143 | * GestureDetector event and the current GestureDetector event.
144 | *
145 | * @return Time difference since the last move event in milliseconds.
146 | */
147 | public long getTimeDelta() {
148 | return mTimeDelta;
149 | }
150 |
151 | /**
152 | * Return the event time of the current GestureDetector event being
153 | * processed.
154 | *
155 | * @return Current GestureDetector event time in milliseconds.
156 | */
157 | public long getEventTime() {
158 | return mCurrEvent.getEventTime();
159 | }
160 |
161 | }
--------------------------------------------------------------------------------
/app/src/main/java/codingwithmitch/com/tabiancustomcamera/gestures/MoveGestureDetector.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera.gestures;
2 |
3 | import android.content.Context;
4 | import android.graphics.PointF;
5 | import android.util.Log;
6 | import android.view.MotionEvent;
7 |
8 | /**
9 | * @author Almer Thie (code.almeros.com)
10 | * Copyright (c) 2013, Almer Thie (code.almeros.com)
11 | *
12 | * All rights reserved.
13 | *
14 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
15 | *
16 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
17 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
18 | * in the documentation and/or other materials provided with the distribution.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
21 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
26 | * OF SUCH DAMAGE.
27 | */
28 | public class MoveGestureDetector extends BaseGestureDetector {
29 |
30 | private static final String TAG = "MoveGestureDetector";
31 |
32 | /**
33 | * Listener which must be implemented which is used by MoveGestureDetector
34 | * to perform callbacks to any implementing class which is registered to a
35 | * MoveGestureDetector via the constructor.
36 | *
37 | * @see MoveGestureDetector.SimpleOnMoveGestureListener
38 | */
39 | public interface OnMoveGestureListener {
40 | public boolean onMove(MoveGestureDetector detector);
41 |
42 | public boolean onMoveBegin(MoveGestureDetector detector);
43 |
44 | public void onMoveEnd(MoveGestureDetector detector);
45 | }
46 |
47 | /**
48 | * Helper class which may be extended and where the methods may be
49 | * implemented. This way it is not necessary to implement all methods
50 | * of OnMoveGestureListener.
51 | */
52 | public static class SimpleOnMoveGestureListener implements OnMoveGestureListener {
53 | public boolean onMove(MoveGestureDetector detector) {
54 | return false;
55 | }
56 |
57 | public boolean onMoveBegin(MoveGestureDetector detector) {
58 | return true;
59 | }
60 |
61 | public void onMoveEnd(MoveGestureDetector detector) {
62 | // Do nothing, overridden implementation may be used
63 | }
64 | }
65 |
66 | private static final PointF FOCUS_DELTA_ZERO = new PointF();
67 |
68 | private final OnMoveGestureListener mListener;
69 |
70 | private PointF mCurrFocusInternal;
71 | private PointF mPrevFocusInternal;
72 | private PointF mFocusExternal = new PointF();
73 | private PointF mFocusDeltaExternal = new PointF();
74 |
75 | public MoveGestureDetector(Context context, OnMoveGestureListener listener) {
76 | super(context);
77 | mListener = listener;
78 | }
79 |
80 | @Override
81 | protected void handleStartProgressEvent(int actionCode, MotionEvent event) {
82 |
83 | switch (actionCode) {
84 |
85 | case MotionEvent.ACTION_DOWN:
86 |
87 | resetState(); // In case we missed an UP/CANCEL event
88 |
89 | mPrevEvent = MotionEvent.obtain(event);
90 | mTimeDelta = 0;
91 |
92 | updateStateByEvent(event);
93 | break;
94 |
95 | case MotionEvent.ACTION_MOVE:
96 |
97 | mGestureInProgress = mListener.onMoveBegin(this);
98 | break;
99 | }
100 | }
101 |
102 | @Override
103 | protected void handleInProgressEvent(int actionCode, MotionEvent event) {
104 | switch (actionCode) {
105 |
106 | case MotionEvent.ACTION_UP:
107 |
108 | case MotionEvent.ACTION_CANCEL:
109 |
110 | mListener.onMoveEnd(this);
111 | resetState();
112 | break;
113 |
114 | case MotionEvent.ACTION_MOVE:
115 |
116 | updateStateByEvent(event);
117 |
118 | // Only accept the event if our relative pressure is within
119 | // a certain limit. This can help filter shaky data as a
120 | // finger is lifted.
121 | if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
122 | final boolean updatePrevious = mListener.onMove(this);
123 | if (updatePrevious) {
124 | mPrevEvent.recycle();
125 | mPrevEvent = MotionEvent.obtain(event);
126 | }
127 | }
128 | break;
129 | }
130 | }
131 |
132 | protected void updateStateByEvent(MotionEvent curr) {
133 | super.updateStateByEvent(curr);
134 |
135 | try{
136 | final MotionEvent prev = mPrevEvent;
137 |
138 | // Focus internal
139 | mCurrFocusInternal = determineFocalPoint(curr);
140 | mPrevFocusInternal = determineFocalPoint(prev);
141 |
142 | // Focus external
143 | // - Prevent skipping of focus delta when a finger is added or removed
144 | boolean mSkipNextMoveEvent = prev.getPointerCount() != curr.getPointerCount();
145 | mFocusDeltaExternal = mSkipNextMoveEvent ? FOCUS_DELTA_ZERO : new PointF(mCurrFocusInternal.x - mPrevFocusInternal.x, mCurrFocusInternal.y - mPrevFocusInternal.y);
146 |
147 | // - Don't directly use mFocusInternal (or skipping will occur). Add
148 | // unskipped delta values to mFocusExternal instead.
149 | mFocusExternal.x += mFocusDeltaExternal.x;
150 | mFocusExternal.y += mFocusDeltaExternal.y;
151 |
152 | }catch (NullPointerException e){
153 | Log.e(TAG, "updateStateByEvent: NullPointerException: " + e.getMessage() );
154 | }
155 | }
156 |
157 | /**
158 | * Determine (multi)finger focal point (a.k.a. center point between all fingers)
159 | *
160 | * @param e detected motion event
161 | * @return PointF focal point
162 | */
163 | private PointF determineFocalPoint(MotionEvent e) {
164 | // Number of fingers on screen
165 | final int pCount = e.getPointerCount();
166 | float x = 0f;
167 | float y = 0f;
168 |
169 | for (int i = 0; i < pCount; i++) {
170 | x += e.getX(i);
171 | y += e.getY(i);
172 | }
173 |
174 | return new PointF(x / pCount, y / pCount);
175 | }
176 |
177 | public float getFocusX() {
178 | return mFocusExternal.x;
179 | }
180 |
181 | public float getFocusY() {
182 | return mFocusExternal.y;
183 | }
184 |
185 | public PointF getFocusDelta() {
186 | return mFocusDeltaExternal;
187 | }
188 |
189 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_in_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_in_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_out_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_out_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_flash_auto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-hdpi/ic_flash_auto.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_flash_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-hdpi/ic_flash_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_flash_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-hdpi/ic_flash_on.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_pen_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-hdpi/ic_pen_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_save_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-hdpi/ic_save_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_sticker_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-hdpi/ic_sticker_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_switch_camera_orient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-hdpi/ic_switch_camera_orient.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_undo_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-hdpi/ic_undo_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_flash_auto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-mdpi/ic_flash_auto.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_flash_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-mdpi/ic_flash_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_flash_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-mdpi/ic_flash_on.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_pen_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-mdpi/ic_pen_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_save_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-mdpi/ic_save_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_sticker_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-mdpi/ic_sticker_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_switch_camera_orient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-mdpi/ic_switch_camera_orient.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_undo_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-mdpi/ic_undo_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_flash_auto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xhdpi/ic_flash_auto.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_flash_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xhdpi/ic_flash_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_flash_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xhdpi/ic_flash_on.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_pen_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xhdpi/ic_pen_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_save_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xhdpi/ic_save_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_sticker_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xhdpi/ic_sticker_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_switch_camera_orient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xhdpi/ic_switch_camera_orient.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_undo_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xhdpi/ic_undo_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_flash_auto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xxhdpi/ic_flash_auto.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_flash_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xxhdpi/ic_flash_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_flash_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xxhdpi/ic_flash_on.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_pen_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xxhdpi/ic_pen_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_save_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xxhdpi/ic_save_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_sticker_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xxhdpi/ic_sticker_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_switch_camera_orient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xxhdpi/ic_switch_camera_orient.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_undo_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable-xxhdpi/ic_undo_small.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/astonished_face_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/astonished_face_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cam_action_capture.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cam_action_stillshot.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cam_circle_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cam_grey_circle_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/circle_opaque.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/circle_white.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cry_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/cry_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/evil_monkey_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/evil_monkey_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
16 |
21 |
26 |
31 |
36 |
41 |
46 |
51 |
56 |
61 |
66 |
71 |
76 |
81 |
86 |
91 |
96 |
101 |
106 |
111 |
116 |
121 |
126 |
131 |
136 |
141 |
146 |
151 |
156 |
161 |
166 |
171 |
172 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/nerd_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/nerd_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/penguin_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/penguin_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sad_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/sad_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/slightly_smiling_face_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/slightly_smiling_face_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/smiley_face_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/smiley_face_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/smiley_face_tightly_closed_eyes_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/smiley_face_tightly_closed_eyes_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/smiley_smiling_eyes_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/smiley_smiling_eyes_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/smiley_with_sweat_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/smiley_with_sweat_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/smirking_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/smirking_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sunglasses_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/sunglasses_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tears_of_joy_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/tears_of_joy_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/unamused_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/unamused_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/upside_down_face_emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/upside_down_face_emoji.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/x_white_border.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/drawable/x_white_border.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_camera2.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
18 |
19 |
20 |
21 |
31 |
32 |
42 |
43 |
44 |
45 |
46 |
47 |
57 |
58 |
64 |
65 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
92 |
93 |
100 |
101 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
123 |
124 |
125 |
129 |
130 |
131 |
142 |
143 |
148 |
149 |
150 |
151 |
152 |
153 |
164 |
165 |
176 |
177 |
178 |
179 |
180 |
192 |
193 |
204 |
205 |
206 |
207 |
208 |
209 |
220 |
221 |
222 |
228 |
229 |
238 |
239 |
240 |
241 |
242 |
243 |
255 |
256 |
264 |
265 |
266 |
267 |
275 |
276 |
281 |
282 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
311 |
312 |
317 |
318 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_view_stickers.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
14 |
15 |
26 |
27 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_sticker_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/array.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF007F
4 | #FF0000
5 | #FF7F00
6 | #FFFF00
7 | #7FFF00
8 | #00FF00
9 | #00FF7F
10 | #00FFFF
11 | #007FFF
12 | #0000FF
13 | #7F00FF
14 | #FF00FF
15 | #000000
16 | #ffffff
17 |
18 |
19 | - @color/white
20 | - @color/bright_pink
21 | - @color/red
22 | - @color/orange
23 | - @color/yellow
24 | - @color/chartreuse
25 | - @color/green
26 | - @color/spring_green
27 | - @color/cyan
28 | - @color/azure
29 | - @color/blue
30 | - @color/violet
31 | - @color/magenta
32 | - @color/black
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 | #af0a0a
8 | #c40909
9 | #e50909
10 | #FF8333
11 | #29CF40
12 | #66a3ff
13 | #0033cc
14 | #4d94ff
15 | #00c4cc
16 | #00aab1
17 | #007f85
18 | #fff
19 | #a6a6a6
20 | #c3c3c3
21 | #f2f2f2
22 | #21737373
23 | #a0737373
24 | #737373
25 | #000
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/default_colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - #ff0000
5 | - #ffff00
6 | - #00ffff
7 | - #ff00ff
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4dp
5 | 8dp
6 | 10dp
7 | 16dp
8 | 32dp
9 | 14sp
10 | 16sp
11 | 36sp
12 | 56dp
13 | 48dp
14 | 20dp
15 | 30dp
16 | 10dp
17 | 10dp
18 | 35dp
19 |
20 |
21 | 10dp
22 | 4dp
23 | 10dp
24 | 10dp
25 | 4dp
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TabianCustomCamera
3 |
4 | Picture
5 | Info
6 | This sample needs camera permission.
7 | This device doesn\'t support Camera2 API.
8 | intro message
9 |
10 |
11 |
12 | Camera2
13 | View Stickers
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/test/java/codingwithmitch/com/tabiancustomcamera/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package codingwithmitch.com.tabiancustomcamera;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.3'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mitchtabian/TabianCustomCamera/b4e90e770958a787a62157720b7471d542fc01fd/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Oct 30 07:19:52 PDT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------