├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── demo
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── desmond
│ │ └── demo
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── desmond
│ │ └── demo
│ │ └── MainActivity.java
│ └── res
│ ├── layout
│ └── activity_main.xml
│ ├── menu
│ └── menu_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── squarecamera
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
├── androidTest
└── java
│ └── com
│ └── desmond
│ └── squarecamera
│ └── ApplicationTest.java
└── main
├── AndroidManifest.xml
├── java
└── com
│ └── desmond
│ └── squarecamera
│ ├── CameraActivity.java
│ ├── CameraFragment.java
│ ├── CameraSettingPreferences.java
│ ├── EditSavePhotoFragment.java
│ ├── ImageParameters.java
│ ├── ImageUtility.java
│ ├── ResizeAnimation.java
│ ├── RuntimePermissionActivity.java
│ ├── SquareCameraPreview.java
│ └── SquareImageView.java
└── res
├── color
├── squarecamera__red_selectable.xml
└── squarecamera__white_selectable.xml
├── drawable-xxhdpi
├── squarecamera__auto.png
├── squarecamera__camera.png
├── squarecamera__camera_snap_selected.png
├── squarecamera__camera_snap_unselected.png
├── squarecamera__cancel_selected.png
├── squarecamera__cancel_unselected.png
├── squarecamera__save_selected.png
├── squarecamera__save_unselected.png
└── squarecamera__toggle_flash.png
├── drawable
├── squarecamera__cancel_drawable.xml
├── squarecamera__capture_photo_button.xml
└── squarecamera__save_photo_drawable.xml
├── layout-land
├── squarecamera__fragment_camera.xml
└── squarecamera__fragment_edit_save_photo.xml
├── layout
├── squarecamera__activity_camera.xml
├── squarecamera__fragment_camera.xml
└── squarecamera__fragment_edit_save_photo.xml
├── menu
├── squarecamera__menu_blank.xml
└── squarecamera__menu_main.xml
├── values-v19
└── styles.xml
├── values-v21
└── styles.xml
├── values-w820dp
└── dimens.xml
└── values
├── colors.xml
├── dimens.xml
├── strings.xml
└── styles.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 |
3 | # generated files
4 | bin/
5 | gen/
6 |
7 | # Ignore gradle files
8 | .gradle
9 | build/
10 |
11 | # Local configuration file (sdk path, etc)
12 | local.properties
13 |
14 | # Proguard folder generated by Eclipse
15 | proguard/
16 |
17 | # Eclipse Metadata
18 | .metadata/
19 |
20 | # Mac OS X clutter
21 | *.DS_Store
22 |
23 | # Windows clutter
24 | Thumbs.db
25 |
26 | # Intellij IDEA (see https://intellij-support.jetbrains.com/entries/23393067)
27 | /.idea
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Ng Yang Yi,Desmond
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SquareCamera
2 | [](http://android-arsenal.com/details/1/1745)
3 | ## Description
4 | Android module that takes a square photo using the native Android Camera APIs. The new Camera2 APIs from the L release is not used because support has to go back to SDK version 14 for my own requirement.
5 |
6 | ## Features
7 | - Tap to focus
8 | - Two fingers zooming
9 | - Front & Back camera
10 | - Flash mode (Saved when the user exits)
11 | - Supports both portrait & landscape
12 | - Runtime permission is supported for saving/viewing photos
13 |
14 | ## SDK Support
15 | Support from SDK version 14 onwards
16 |
17 | ## Download
18 | jCenter:
19 | ```groovy
20 | repositories {
21 | jcenter()
22 | }
23 |
24 | dependencies {
25 | compile 'com.github.boxme:squarecamera:1.1.0'
26 | }
27 | ```
28 |
29 | ## Example
30 | ```java
31 | private static final int REQUEST_CAMERA = 0;
32 |
33 | // Check for camera permission in MashMallow
34 | public void requestForCameraPermission(View view) {
35 | final String permission = Manifest.permission.CAMERA;
36 | if (ContextCompat.checkSelfPermission(MainActivity.this, permission)
37 | != PackageManager.PERMISSION_GRANTED) {
38 | if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, permission)) {
39 | // Show permission rationale
40 | } else {
41 | // Handle the result in Activity#onRequestPermissionResult(int, String[], int[])
42 | ActivityCompat.requestPermissions(YourActivity.this, new String[]{permission}, REQUEST_CAMERA_PERMISSION);
43 | }
44 | } else {
45 | // Start CameraActivity
46 | }
47 | }
48 |
49 | // Start CameraActivity
50 | Intent startCustomCameraIntent = new Intent(this, CameraActivity.class);
51 | startActivityForResult(startCustomCameraIntent, REQUEST_CAMERA);
52 |
53 | // Receive Uri of saved square photo
54 | @Override
55 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
56 | if (resultCode != RESULT_OK) return;
57 |
58 | if (requestCode == REQUEST_CAMERA) {
59 | Uri photoUri = data.getData();
60 | }
61 | super.onActivityResult(requestCode, resultCode, data);
62 | }
63 | ```
64 |
65 | ## Video Demo
66 | Link: https://youtu.be/cSGFiP-gZYU
67 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.3.0'
9 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
10 | classpath 'com.github.dcendents:android-maven-plugin:1.2'
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.0"
6 |
7 | defaultConfig {
8 | applicationId "com.desmond.demo"
9 | minSdkVersion 14
10 | targetSdkVersion 23
11 | versionCode 2
12 | versionName "1.1"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'com.android.support:appcompat-v7:23.0.0'
25 | // compile 'com.github.boxme:squarecamera:1.0.3'
26 | compile project(':squarecamera')
27 | }
28 |
--------------------------------------------------------------------------------
/demo/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/desmond/android-sdks/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/demo/src/androidTest/java/com/desmond/demo/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.desmond.demo;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/demo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/desmond/demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.desmond.demo;
2 |
3 | import android.Manifest;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.content.pm.PackageManager;
7 | import android.graphics.Bitmap;
8 | import android.graphics.Point;
9 | import android.net.Uri;
10 | import android.os.Bundle;
11 | import android.support.annotation.NonNull;
12 | import android.support.v4.app.ActivityCompat;
13 | import android.support.v4.content.ContextCompat;
14 | import android.support.v7.app.AlertDialog;
15 | import android.support.v7.app.AppCompatActivity;
16 | import android.view.Display;
17 | import android.view.View;
18 | import android.widget.ImageView;
19 |
20 | import com.desmond.squarecamera.CameraActivity;
21 | import com.desmond.squarecamera.ImageUtility;
22 |
23 |
24 | public class MainActivity extends AppCompatActivity {
25 |
26 | private static final int REQUEST_CAMERA = 0;
27 | private static final int REQUEST_CAMERA_PERMISSION = 1;
28 | private Point mSize;
29 |
30 | @Override
31 | protected void onCreate(Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | setContentView(R.layout.activity_main);
34 |
35 | Display display = getWindowManager().getDefaultDisplay();
36 | mSize = new Point();
37 | display.getSize(mSize);
38 | }
39 |
40 | @Override
41 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
42 | if (resultCode != RESULT_OK) return;
43 |
44 | if (requestCode == REQUEST_CAMERA) {
45 | Uri photoUri = data.getData();
46 | // Get the bitmap in according to the width of the device
47 | Bitmap bitmap = ImageUtility.decodeSampledBitmapFromPath(photoUri.getPath(), mSize.x, mSize.x);
48 | ((ImageView) findViewById(R.id.image)).setImageBitmap(bitmap);
49 | }
50 | super.onActivityResult(requestCode, resultCode, data);
51 | }
52 |
53 | public void requestForCameraPermission(View view) {
54 | final String permission = Manifest.permission.CAMERA;
55 | if (ContextCompat.checkSelfPermission(MainActivity.this, permission)
56 | != PackageManager.PERMISSION_GRANTED) {
57 | if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, permission)) {
58 | showPermissionRationaleDialog("Test", permission);
59 | } else {
60 | requestForPermission(permission);
61 | }
62 | } else {
63 | launch();
64 | }
65 | }
66 |
67 | private void showPermissionRationaleDialog(final String message, final String permission) {
68 | new AlertDialog.Builder(MainActivity.this)
69 | .setMessage(message)
70 | .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
71 | @Override
72 | public void onClick(DialogInterface dialog, int which) {
73 | MainActivity.this.requestForPermission(permission);
74 | }
75 | })
76 | .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
77 | @Override
78 | public void onClick(DialogInterface dialog, int which) {
79 |
80 | }
81 | })
82 | .create()
83 | .show();
84 | }
85 |
86 | private void requestForPermission(final String permission) {
87 | ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, REQUEST_CAMERA_PERMISSION);
88 | }
89 |
90 | private void launch() {
91 | Intent startCustomCameraIntent = new Intent(this, CameraActivity.class);
92 | startActivityForResult(startCustomCameraIntent, REQUEST_CAMERA);
93 | }
94 |
95 | @Override
96 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
97 | switch (requestCode) {
98 | case REQUEST_CAMERA_PERMISSION:
99 | final int numOfRequest = grantResults.length;
100 | final boolean isGranted = numOfRequest == 1
101 | && PackageManager.PERMISSION_GRANTED == grantResults[numOfRequest - 1];
102 | if (isGranted) {
103 | launch();
104 | }
105 | break;
106 |
107 | default:
108 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/demo/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/demo/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/demo/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/demo/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Demo
3 |
4 | Hello world!
5 | Settings
6 |
7 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 29 23:06:06 SGT 2015
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-2.2.1-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 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/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 ':squarecamera', ':demo'
2 |
--------------------------------------------------------------------------------
/squarecamera/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/squarecamera/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | apply plugin: 'com.jfrog.bintray'
4 |
5 | version = "1.1.0"
6 | group = "com.github.boxme"
7 |
8 | def siteUrl = 'https://github.com/boxme/SquareCamera'
9 | def gitUrl = 'https://github.com/boxme/SquareCamera.git'
10 |
11 | android {
12 | compileSdkVersion 23
13 | buildToolsVersion "23.0.1"
14 | resourcePrefix "squarecamera__"
15 |
16 | defaultConfig {
17 | minSdkVersion 14
18 | targetSdkVersion 23
19 | versionCode 5
20 | versionName "1.1.0"
21 | }
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 |
29 | packagingOptions {
30 | exclude 'META-INF/NOTICE.txt'
31 | exclude 'META-INF/LICENSE.txt'
32 | }
33 | }
34 |
35 | Properties properties = new Properties()
36 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
37 |
38 | bintray {
39 | user = properties.getProperty("bintray.user")
40 | key = properties.getProperty("bintray.apikey")
41 |
42 | configurations = ['archives']
43 | pkg {
44 | repo = "maven"
45 | name = "SquareCamera"
46 | websiteUrl = siteUrl
47 | vcsUrl = gitUrl
48 | licenses = ["MIT"]
49 | publish = true
50 | }
51 | }
52 |
53 | install {
54 | repositories.mavenInstaller {
55 | pom {
56 | project {
57 | packaging 'aar'
58 | name 'A camera that takes square photos'
59 | url siteUrl
60 | licenses {
61 | license {
62 | name 'The MIT License'
63 | url 'https://github.com/boxme/SquareCamera/blob/master/LICENSE'
64 | }
65 | }
66 | developers {
67 | developer {
68 | id 'boxme'
69 | name 'Desmond Ng'
70 | email 'desmond.ng.yang.yi@gmail.com'
71 | }
72 | }
73 | scm {
74 | connection gitUrl
75 | developerConnection gitUrl
76 | url siteUrl
77 |
78 | }
79 | }
80 | }
81 | }
82 | }
83 |
84 | repositories {
85 | maven {
86 | url "http://dl.bintray.com/populov/maven"
87 | }
88 | mavenCentral()
89 | mavenLocal()
90 | }
91 |
92 | dependencies {
93 | compile fileTree(dir: 'libs', include: ['*.jar'])
94 | compile 'com.android.support:appcompat-v7:23.0.1'
95 | compile 'com.android.support:support-v4:23.0.1'
96 | compile 'com.android.support:design:23.0.1'
97 | }
98 |
99 | task sourcesJar(type: Jar) {
100 | from android.sourceSets.main.java.srcDirs
101 | classifier = 'sources'
102 | }
103 |
104 | task javadoc(type: Javadoc) {
105 | source = android.sourceSets.main.java.srcDirs
106 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
107 | }
108 |
109 | task javadocJar(type: Jar, dependsOn: javadoc) {
110 | classifier = 'javadoc'
111 | from javadoc.destinationDir
112 | }
113 |
114 | artifacts {
115 | archives javadocJar
116 | archives sourcesJar
117 | }
118 |
--------------------------------------------------------------------------------
/squarecamera/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/desmond/android-sdks/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/squarecamera/src/androidTest/java/com/desmond/squarecamera/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/squarecamera/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/squarecamera/src/main/java/com/desmond/squarecamera/CameraActivity.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.View;
8 |
9 |
10 | public class CameraActivity extends AppCompatActivity {
11 |
12 | public static final String TAG = CameraActivity.class.getSimpleName();
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | setTheme(R.style.squarecamera__CameraFullScreenTheme);
17 | super.onCreate(savedInstanceState);
18 |
19 | if (getSupportActionBar() != null) {
20 | getSupportActionBar().hide();
21 | }
22 | setContentView(R.layout.squarecamera__activity_camera);
23 |
24 | if (savedInstanceState == null) {
25 | getSupportFragmentManager()
26 | .beginTransaction()
27 | .replace(R.id.fragment_container, CameraFragment.newInstance(), CameraFragment.TAG)
28 | .commit();
29 | }
30 | }
31 |
32 | public void returnPhotoUri(Uri uri) {
33 | Intent data = new Intent();
34 | data.setData(uri);
35 |
36 | if (getParent() == null) {
37 | setResult(RESULT_OK, data);
38 | } else {
39 | getParent().setResult(RESULT_OK, data);
40 | }
41 |
42 | finish();
43 | }
44 |
45 | public void onCancel(View view) {
46 | getSupportFragmentManager().popBackStack();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/squarecamera/src/main/java/com/desmond/squarecamera/CameraFragment.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 |
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.pm.PackageManager;
8 | import android.content.res.Configuration;
9 | import android.hardware.Camera;
10 | import android.hardware.Camera.CameraInfo;
11 | import android.hardware.Camera.Size;
12 | import android.hardware.SensorManager;
13 | import android.net.Uri;
14 | import android.os.Build;
15 | import android.os.Bundle;
16 | import android.support.annotation.Nullable;
17 | import android.support.v4.app.Fragment;
18 | import android.util.Log;
19 | import android.view.LayoutInflater;
20 | import android.view.OrientationEventListener;
21 | import android.view.Surface;
22 | import android.view.SurfaceHolder;
23 | import android.view.View;
24 | import android.view.ViewGroup;
25 | import android.view.ViewTreeObserver;
26 | import android.view.animation.AccelerateDecelerateInterpolator;
27 | import android.widget.ImageView;
28 | import android.widget.TextView;
29 |
30 | import java.io.IOException;
31 | import java.util.List;
32 |
33 | public class CameraFragment extends Fragment implements SurfaceHolder.Callback, Camera.PictureCallback {
34 |
35 | public static final String TAG = CameraFragment.class.getSimpleName();
36 | public static final String CAMERA_ID_KEY = "camera_id";
37 | public static final String CAMERA_FLASH_KEY = "flash_mode";
38 | public static final String IMAGE_INFO = "image_info";
39 |
40 | private static final int PICTURE_SIZE_MAX_WIDTH = 1280;
41 | private static final int PREVIEW_SIZE_MAX_WIDTH = 640;
42 |
43 | private int mCameraID;
44 | private String mFlashMode;
45 | private Camera mCamera;
46 | private SquareCameraPreview mPreviewView;
47 | private SurfaceHolder mSurfaceHolder;
48 |
49 | private boolean mIsSafeToTakePhoto = false;
50 |
51 | private ImageParameters mImageParameters;
52 |
53 | private CameraOrientationListener mOrientationListener;
54 |
55 | public static Fragment newInstance() {
56 | return new CameraFragment();
57 | }
58 |
59 | public CameraFragment() {}
60 |
61 | @Override
62 | public void onAttach(Context context) {
63 | super.onAttach(context);
64 | mOrientationListener = new CameraOrientationListener(context);
65 | }
66 |
67 | @Override
68 | public void onCreate(@Nullable Bundle savedInstanceState) {
69 | super.onCreate(savedInstanceState);
70 | // Restore your state here because a double rotation with this fragment
71 | // in the backstack will cause improper state restoration
72 | // onCreate() -> onSavedInstanceState() instead of going through onCreateView()
73 | if (savedInstanceState == null) {
74 | mCameraID = getBackCameraID();
75 | mFlashMode = CameraSettingPreferences.getCameraFlashMode(getActivity());
76 | mImageParameters = new ImageParameters();
77 | } else {
78 | mCameraID = savedInstanceState.getInt(CAMERA_ID_KEY);
79 | mFlashMode = savedInstanceState.getString(CAMERA_FLASH_KEY);
80 | mImageParameters = savedInstanceState.getParcelable(IMAGE_INFO);
81 | }
82 | }
83 |
84 | @Override
85 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
86 | Bundle savedInstanceState) {
87 | return inflater.inflate(R.layout.squarecamera__fragment_camera, container, false);
88 | }
89 |
90 | @Override
91 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
92 | super.onViewCreated(view, savedInstanceState);
93 | mOrientationListener.enable();
94 |
95 | mPreviewView = (SquareCameraPreview) view.findViewById(R.id.camera_preview_view);
96 | mPreviewView.getHolder().addCallback(CameraFragment.this);
97 |
98 | final View topCoverView = view.findViewById(R.id.cover_top_view);
99 | final View btnCoverView = view.findViewById(R.id.cover_bottom_view);
100 |
101 | mImageParameters.mIsPortrait =
102 | getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
103 |
104 | if (savedInstanceState == null) {
105 | ViewTreeObserver observer = mPreviewView.getViewTreeObserver();
106 | observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
107 | @Override
108 | public void onGlobalLayout() {
109 | mImageParameters.mPreviewWidth = mPreviewView.getWidth();
110 | mImageParameters.mPreviewHeight = mPreviewView.getHeight();
111 |
112 | mImageParameters.mCoverWidth = mImageParameters.mCoverHeight
113 | = mImageParameters.calculateCoverWidthHeight();
114 |
115 | // Log.d(TAG, "parameters: " + mImageParameters.getStringValues());
116 | // Log.d(TAG, "cover height " + topCoverView.getHeight());
117 | resizeTopAndBtmCover(topCoverView, btnCoverView);
118 |
119 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
120 | mPreviewView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
121 | } else {
122 | mPreviewView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
123 | }
124 | }
125 | });
126 | } else {
127 | if (mImageParameters.isPortrait()) {
128 | topCoverView.getLayoutParams().height = mImageParameters.mCoverHeight;
129 | btnCoverView.getLayoutParams().height = mImageParameters.mCoverHeight;
130 | } else {
131 | topCoverView.getLayoutParams().width = mImageParameters.mCoverWidth;
132 | btnCoverView.getLayoutParams().width = mImageParameters.mCoverWidth;
133 | }
134 | }
135 |
136 | final ImageView swapCameraBtn = (ImageView) view.findViewById(R.id.change_camera);
137 | swapCameraBtn.setOnClickListener(new View.OnClickListener() {
138 | @Override
139 | public void onClick(View v) {
140 | if (mCameraID == CameraInfo.CAMERA_FACING_FRONT) {
141 | mCameraID = getBackCameraID();
142 | } else {
143 | mCameraID = getFrontCameraID();
144 | }
145 | restartPreview();
146 | }
147 | });
148 |
149 | final View changeCameraFlashModeBtn = view.findViewById(R.id.flash);
150 | changeCameraFlashModeBtn.setOnClickListener(new View.OnClickListener() {
151 | @Override
152 | public void onClick(View v) {
153 | if (mFlashMode.equalsIgnoreCase(Camera.Parameters.FLASH_MODE_AUTO)) {
154 | mFlashMode = Camera.Parameters.FLASH_MODE_ON;
155 | } else if (mFlashMode.equalsIgnoreCase(Camera.Parameters.FLASH_MODE_ON)) {
156 | mFlashMode = Camera.Parameters.FLASH_MODE_OFF;
157 | } else if (mFlashMode.equalsIgnoreCase(Camera.Parameters.FLASH_MODE_OFF)) {
158 | mFlashMode = Camera.Parameters.FLASH_MODE_AUTO;
159 | }
160 |
161 | setupFlashMode();
162 | setupCamera();
163 | }
164 | });
165 | setupFlashMode();
166 |
167 | final ImageView takePhotoBtn = (ImageView) view.findViewById(R.id.capture_image_button);
168 | takePhotoBtn.setOnClickListener(new View.OnClickListener() {
169 | @Override
170 | public void onClick(View v) {
171 | takePicture();
172 | }
173 | });
174 | }
175 |
176 | private void setupFlashMode() {
177 | View view = getView();
178 | if (view == null) return;
179 |
180 | final TextView autoFlashIcon = (TextView) view.findViewById(R.id.auto_flash_icon);
181 | if (Camera.Parameters.FLASH_MODE_AUTO.equalsIgnoreCase(mFlashMode)) {
182 | autoFlashIcon.setText("Auto");
183 | } else if (Camera.Parameters.FLASH_MODE_ON.equalsIgnoreCase(mFlashMode)) {
184 | autoFlashIcon.setText("On");
185 | } else if (Camera.Parameters.FLASH_MODE_OFF.equalsIgnoreCase(mFlashMode)) {
186 | autoFlashIcon.setText("Off");
187 | }
188 | }
189 |
190 | @Override
191 | public void onSaveInstanceState(Bundle outState) {
192 | // Log.d(TAG, "onSaveInstanceState");
193 | outState.putInt(CAMERA_ID_KEY, mCameraID);
194 | outState.putString(CAMERA_FLASH_KEY, mFlashMode);
195 | outState.putParcelable(IMAGE_INFO, mImageParameters);
196 | super.onSaveInstanceState(outState);
197 | }
198 |
199 | private void resizeTopAndBtmCover( final View topCover, final View bottomCover) {
200 | ResizeAnimation resizeTopAnimation
201 | = new ResizeAnimation(topCover, mImageParameters);
202 | resizeTopAnimation.setDuration(800);
203 | resizeTopAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
204 | topCover.startAnimation(resizeTopAnimation);
205 |
206 | ResizeAnimation resizeBtmAnimation
207 | = new ResizeAnimation(bottomCover, mImageParameters);
208 | resizeBtmAnimation.setDuration(800);
209 | resizeBtmAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
210 | bottomCover.startAnimation(resizeBtmAnimation);
211 | }
212 |
213 | private void getCamera(int cameraID) {
214 | try {
215 | mCamera = Camera.open(cameraID);
216 | mPreviewView.setCamera(mCamera);
217 | } catch (Exception e) {
218 | Log.d(TAG, "Can't open camera with id " + cameraID);
219 | e.printStackTrace();
220 | }
221 | }
222 |
223 | /**
224 | * Restart the camera preview
225 | */
226 | private void restartPreview() {
227 | if (mCamera != null) {
228 | stopCameraPreview();
229 | mCamera.release();
230 | mCamera = null;
231 | }
232 |
233 | getCamera(mCameraID);
234 | startCameraPreview();
235 | }
236 |
237 | /**
238 | * Start the camera preview
239 | */
240 | private void startCameraPreview() {
241 | determineDisplayOrientation();
242 | setupCamera();
243 |
244 | try {
245 | mCamera.setPreviewDisplay(mSurfaceHolder);
246 | mCamera.startPreview();
247 |
248 | setSafeToTakePhoto(true);
249 | setCameraFocusReady(true);
250 | } catch (IOException e) {
251 | Log.d(TAG, "Can't start camera preview due to IOException " + e);
252 | e.printStackTrace();
253 | }
254 | }
255 |
256 | /**
257 | * Stop the camera preview
258 | */
259 | private void stopCameraPreview() {
260 | setSafeToTakePhoto(false);
261 | setCameraFocusReady(false);
262 |
263 | // Nulls out callbacks, stops face detection
264 | mCamera.stopPreview();
265 | mPreviewView.setCamera(null);
266 | }
267 |
268 | private void setSafeToTakePhoto(final boolean isSafeToTakePhoto) {
269 | mIsSafeToTakePhoto = isSafeToTakePhoto;
270 | }
271 |
272 | private void setCameraFocusReady(final boolean isFocusReady) {
273 | if (this.mPreviewView != null) {
274 | mPreviewView.setIsFocusReady(isFocusReady);
275 | }
276 | }
277 |
278 | /**
279 | * Determine the current display orientation and rotate the camera preview
280 | * accordingly
281 | */
282 | private void determineDisplayOrientation() {
283 | CameraInfo cameraInfo = new CameraInfo();
284 | Camera.getCameraInfo(mCameraID, cameraInfo);
285 |
286 | // Clockwise rotation needed to align the window display to the natural position
287 | int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
288 | int degrees = 0;
289 |
290 | switch (rotation) {
291 | case Surface.ROTATION_0: {
292 | degrees = 0;
293 | break;
294 | }
295 | case Surface.ROTATION_90: {
296 | degrees = 90;
297 | break;
298 | }
299 | case Surface.ROTATION_180: {
300 | degrees = 180;
301 | break;
302 | }
303 | case Surface.ROTATION_270: {
304 | degrees = 270;
305 | break;
306 | }
307 | }
308 |
309 | int displayOrientation;
310 |
311 | // CameraInfo.Orientation is the angle relative to the natural position of the device
312 | // in clockwise rotation (angle that is rotated clockwise from the natural position)
313 | if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
314 | // Orientation is angle of rotation when facing the camera for
315 | // the camera image to match the natural orientation of the device
316 | displayOrientation = (cameraInfo.orientation + degrees) % 360;
317 | displayOrientation = (360 - displayOrientation) % 360;
318 | } else {
319 | displayOrientation = (cameraInfo.orientation - degrees + 360) % 360;
320 | }
321 |
322 | mImageParameters.mDisplayOrientation = displayOrientation;
323 | mImageParameters.mLayoutOrientation = degrees;
324 |
325 | mCamera.setDisplayOrientation(mImageParameters.mDisplayOrientation);
326 | }
327 |
328 | /**
329 | * Setup the camera parameters
330 | */
331 | private void setupCamera() {
332 | // Never keep a global parameters
333 | Camera.Parameters parameters = mCamera.getParameters();
334 |
335 | Size bestPreviewSize = determineBestPreviewSize(parameters);
336 | Size bestPictureSize = determineBestPictureSize(parameters);
337 |
338 | parameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
339 | parameters.setPictureSize(bestPictureSize.width, bestPictureSize.height);
340 |
341 |
342 | // Set continuous picture focus, if it's supported
343 | if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
344 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
345 | }
346 |
347 | final View changeCameraFlashModeBtn = getView().findViewById(R.id.flash);
348 | List flashModes = parameters.getSupportedFlashModes();
349 | if (flashModes != null && flashModes.contains(mFlashMode)) {
350 | parameters.setFlashMode(mFlashMode);
351 | changeCameraFlashModeBtn.setVisibility(View.VISIBLE);
352 | } else {
353 | changeCameraFlashModeBtn.setVisibility(View.INVISIBLE);
354 | }
355 |
356 | // Lock in the changes
357 | mCamera.setParameters(parameters);
358 | }
359 |
360 | private Size determineBestPreviewSize(Camera.Parameters parameters) {
361 | return determineBestSize(parameters.getSupportedPreviewSizes(), PREVIEW_SIZE_MAX_WIDTH);
362 | }
363 |
364 | private Size determineBestPictureSize(Camera.Parameters parameters) {
365 | return determineBestSize(parameters.getSupportedPictureSizes(), PICTURE_SIZE_MAX_WIDTH);
366 | }
367 |
368 | private Size determineBestSize(List sizes, int widthThreshold) {
369 | Size bestSize = null;
370 | Size size;
371 | int numOfSizes = sizes.size();
372 | for (int i = 0; i < numOfSizes; i++) {
373 | size = sizes.get(i);
374 | boolean isDesireRatio = (size.width / 4) == (size.height / 3);
375 | boolean isBetterSize = (bestSize == null) || size.width > bestSize.width;
376 |
377 | if (isDesireRatio && isBetterSize) {
378 | bestSize = size;
379 | }
380 | }
381 |
382 | if (bestSize == null) {
383 | Log.d(TAG, "cannot find the best camera size");
384 | return sizes.get(sizes.size() - 1);
385 | }
386 |
387 | return bestSize;
388 | }
389 |
390 | private int getFrontCameraID() {
391 | PackageManager pm = getActivity().getPackageManager();
392 | if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
393 | return CameraInfo.CAMERA_FACING_FRONT;
394 | }
395 |
396 | return getBackCameraID();
397 | }
398 |
399 | private int getBackCameraID() {
400 | return CameraInfo.CAMERA_FACING_BACK;
401 | }
402 |
403 | /**
404 | * Take a picture
405 | */
406 | private void takePicture() {
407 |
408 | if (mIsSafeToTakePhoto) {
409 | setSafeToTakePhoto(false);
410 |
411 | mOrientationListener.rememberOrientation();
412 |
413 | // Shutter callback occurs after the image is captured. This can
414 | // be used to trigger a sound to let the user know that image is taken
415 | Camera.ShutterCallback shutterCallback = null;
416 |
417 | // Raw callback occurs when the raw image data is available
418 | Camera.PictureCallback raw = null;
419 |
420 | // postView callback occurs when a scaled, fully processed
421 | // postView image is available.
422 | Camera.PictureCallback postView = null;
423 |
424 | // jpeg callback occurs when the compressed image is available
425 | mCamera.takePicture(shutterCallback, raw, postView, this);
426 | }
427 | }
428 |
429 | @Override
430 | public void onResume() {
431 | super.onResume();
432 |
433 | if (mCamera == null) {
434 | restartPreview();
435 | }
436 | }
437 |
438 | @Override
439 | public void onStop() {
440 | mOrientationListener.disable();
441 |
442 | // stop the preview
443 | if (mCamera != null) {
444 | stopCameraPreview();
445 | mCamera.release();
446 | mCamera = null;
447 | }
448 |
449 | CameraSettingPreferences.saveCameraFlashMode(getActivity(), mFlashMode);
450 |
451 | super.onStop();
452 | }
453 |
454 | @Override
455 | public void surfaceCreated(SurfaceHolder holder) {
456 | mSurfaceHolder = holder;
457 |
458 | getCamera(mCameraID);
459 | startCameraPreview();
460 | }
461 |
462 | @Override
463 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
464 |
465 | }
466 |
467 | @Override
468 | public void surfaceDestroyed(SurfaceHolder holder) {
469 | // The surface is destroyed with the visibility of the SurfaceView is set to View.Invisible
470 | }
471 |
472 | @Override
473 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
474 | if (resultCode != Activity.RESULT_OK) return;
475 |
476 | switch (requestCode) {
477 | case 1:
478 | Uri imageUri = data.getData();
479 | break;
480 |
481 | default:
482 | super.onActivityResult(requestCode, resultCode, data);
483 | }
484 | }
485 |
486 | /**
487 | * A picture has been taken
488 | * @param data
489 | * @param camera
490 | */
491 | @Override
492 | public void onPictureTaken(byte[] data, Camera camera) {
493 | int rotation = getPhotoRotation();
494 | // Log.d(TAG, "normal orientation: " + orientation);
495 | // Log.d(TAG, "Rotate Picture by: " + rotation);
496 | getFragmentManager()
497 | .beginTransaction()
498 | .replace(
499 | R.id.fragment_container,
500 | EditSavePhotoFragment.newInstance(data, rotation, mImageParameters.createCopy()),
501 | EditSavePhotoFragment.TAG)
502 | .addToBackStack(null)
503 | .commit();
504 |
505 | setSafeToTakePhoto(true);
506 | }
507 |
508 | private int getPhotoRotation() {
509 | int rotation;
510 | int orientation = mOrientationListener.getRememberedNormalOrientation();
511 | CameraInfo info = new CameraInfo();
512 | Camera.getCameraInfo(mCameraID, info);
513 |
514 | if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
515 | rotation = (info.orientation - orientation + 360) % 360;
516 | } else {
517 | rotation = (info.orientation + orientation) % 360;
518 | }
519 |
520 | return rotation;
521 | }
522 |
523 | /**
524 | * When orientation changes, onOrientationChanged(int) of the listener will be called
525 | */
526 | private static class CameraOrientationListener extends OrientationEventListener {
527 |
528 | private int mCurrentNormalizedOrientation;
529 | private int mRememberedNormalOrientation;
530 |
531 | public CameraOrientationListener(Context context) {
532 | super(context, SensorManager.SENSOR_DELAY_NORMAL);
533 | }
534 |
535 | @Override
536 | public void onOrientationChanged(int orientation) {
537 | if (orientation != ORIENTATION_UNKNOWN) {
538 | mCurrentNormalizedOrientation = normalize(orientation);
539 | }
540 | }
541 |
542 | /**
543 | * @param degrees Amount of clockwise rotation from the device's natural position
544 | * @return Normalized degrees to just 0, 90, 180, 270
545 | */
546 | private int normalize(int degrees) {
547 | if (degrees > 315 || degrees <= 45) {
548 | return 0;
549 | }
550 |
551 | if (degrees > 45 && degrees <= 135) {
552 | return 90;
553 | }
554 |
555 | if (degrees > 135 && degrees <= 225) {
556 | return 180;
557 | }
558 |
559 | if (degrees > 225 && degrees <= 315) {
560 | return 270;
561 | }
562 |
563 | throw new RuntimeException("The physics as we know them are no more. Watch out for anomalies.");
564 | }
565 |
566 | public void rememberOrientation() {
567 | mRememberedNormalOrientation = mCurrentNormalizedOrientation;
568 | }
569 |
570 | public int getRememberedNormalOrientation() {
571 | rememberOrientation();
572 | return mRememberedNormalOrientation;
573 | }
574 | }
575 | }
576 |
--------------------------------------------------------------------------------
/squarecamera/src/main/java/com/desmond/squarecamera/CameraSettingPreferences.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.hardware.Camera;
6 | import android.support.annotation.NonNull;
7 |
8 | /**
9 | * Created by desmond on 4/10/15.
10 | */
11 | public class CameraSettingPreferences {
12 |
13 | private static final String FLASH_MODE = "squarecamera__flash_mode";
14 |
15 | private static SharedPreferences getCameraSettingPreferences(@NonNull final Context context) {
16 | return context.getSharedPreferences("com.desmond.squarecamera", Context.MODE_PRIVATE);
17 | }
18 |
19 | protected static void saveCameraFlashMode(@NonNull final Context context, @NonNull final String cameraFlashMode) {
20 | final SharedPreferences preferences = getCameraSettingPreferences(context);
21 |
22 | if (preferences != null) {
23 | final SharedPreferences.Editor editor = preferences.edit();
24 | editor.putString(FLASH_MODE, cameraFlashMode);
25 | editor.apply();
26 | }
27 | }
28 |
29 | protected static String getCameraFlashMode(@NonNull final Context context) {
30 | final SharedPreferences preferences = getCameraSettingPreferences(context);
31 |
32 | if (preferences != null) {
33 | return preferences.getString(FLASH_MODE, Camera.Parameters.FLASH_MODE_AUTO);
34 | }
35 |
36 | return Camera.Parameters.FLASH_MODE_AUTO;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/squarecamera/src/main/java/com/desmond/squarecamera/EditSavePhotoFragment.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 |
4 | import android.Manifest;
5 | import android.app.Activity;
6 | import android.content.Intent;
7 | import android.content.res.Configuration;
8 | import android.graphics.Bitmap;
9 | import android.graphics.Matrix;
10 | import android.graphics.drawable.BitmapDrawable;
11 | import android.net.Uri;
12 | import android.os.Bundle;
13 | import android.support.annotation.NonNull;
14 | import android.support.annotation.Nullable;
15 | import android.support.v4.app.Fragment;
16 | import android.view.LayoutInflater;
17 | import android.view.View;
18 | import android.view.ViewGroup;
19 | import android.widget.ImageView;
20 |
21 |
22 | /**
23 | *
24 | */
25 | public class EditSavePhotoFragment extends Fragment {
26 |
27 | public static final String TAG = EditSavePhotoFragment.class.getSimpleName();
28 | public static final String BITMAP_KEY = "bitmap_byte_array";
29 | public static final String ROTATION_KEY = "rotation";
30 | public static final String IMAGE_INFO = "image_info";
31 |
32 | private static final int REQUEST_STORAGE = 1;
33 |
34 | public static Fragment newInstance(byte[] bitmapByteArray, int rotation,
35 | @NonNull ImageParameters parameters) {
36 | Fragment fragment = new EditSavePhotoFragment();
37 |
38 | Bundle args = new Bundle();
39 | args.putByteArray(BITMAP_KEY, bitmapByteArray);
40 | args.putInt(ROTATION_KEY, rotation);
41 | args.putParcelable(IMAGE_INFO, parameters);
42 |
43 | fragment.setArguments(args);
44 | return fragment;
45 | }
46 |
47 | public EditSavePhotoFragment() {}
48 |
49 | @Override
50 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
51 | Bundle savedInstanceState) {
52 | return inflater.inflate(R.layout.squarecamera__fragment_edit_save_photo, container, false);
53 | }
54 |
55 | @Override
56 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
57 | super.onViewCreated(view, savedInstanceState);
58 |
59 | int rotation = getArguments().getInt(ROTATION_KEY);
60 | byte[] data = getArguments().getByteArray(BITMAP_KEY);
61 | ImageParameters imageParameters = getArguments().getParcelable(IMAGE_INFO);
62 |
63 | if (imageParameters == null) {
64 | return;
65 | }
66 |
67 | final ImageView photoImageView = (ImageView) view.findViewById(R.id.photo);
68 |
69 | imageParameters.mIsPortrait =
70 | getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
71 |
72 | final View topView = view.findViewById(R.id.topView);
73 | if (imageParameters.mIsPortrait) {
74 | topView.getLayoutParams().height = imageParameters.mCoverHeight;
75 | } else {
76 | topView.getLayoutParams().width = imageParameters.mCoverWidth;
77 | }
78 |
79 | rotatePicture(rotation, data, photoImageView);
80 |
81 | view.findViewById(R.id.save_photo).setOnClickListener(new View.OnClickListener() {
82 | @Override
83 | public void onClick(View v) {
84 | savePicture();
85 | }
86 | });
87 | }
88 |
89 | private void rotatePicture(int rotation, byte[] data, ImageView photoImageView) {
90 | Bitmap bitmap = ImageUtility.decodeSampledBitmapFromByte(getActivity(), data);
91 | // Log.d(TAG, "original bitmap width " + bitmap.getWidth() + " height " + bitmap.getHeight());
92 | if (rotation != 0) {
93 | Bitmap oldBitmap = bitmap;
94 |
95 | Matrix matrix = new Matrix();
96 | matrix.postRotate(rotation);
97 |
98 | bitmap = Bitmap.createBitmap(
99 | oldBitmap, 0, 0, oldBitmap.getWidth(), oldBitmap.getHeight(), matrix, false
100 | );
101 |
102 | oldBitmap.recycle();
103 | }
104 |
105 | photoImageView.setImageBitmap(bitmap);
106 | }
107 |
108 | private void savePicture() {
109 | requestForPermission();
110 | }
111 |
112 | private void requestForPermission() {
113 | RuntimePermissionActivity.startActivity(EditSavePhotoFragment.this,
114 | REQUEST_STORAGE,
115 | Manifest.permission.WRITE_EXTERNAL_STORAGE);
116 | }
117 |
118 | @Override
119 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
120 | if (Activity.RESULT_OK != resultCode) return;
121 |
122 | if (REQUEST_STORAGE == requestCode && data != null) {
123 | final boolean isGranted = data.getBooleanExtra(RuntimePermissionActivity.REQUESTED_PERMISSION, false);
124 | final View view = getView();
125 | if (isGranted && view != null) {
126 | ImageView photoImageView = (ImageView) view.findViewById(R.id.photo);
127 |
128 | Bitmap bitmap = ((BitmapDrawable) photoImageView.getDrawable()).getBitmap();
129 | Uri photoUri = ImageUtility.savePicture(getActivity(), bitmap);
130 |
131 | ((CameraActivity) getActivity()).returnPhotoUri(photoUri);
132 | }
133 | } else {
134 | super.onActivityResult(requestCode, resultCode, data);
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/squarecamera/src/main/java/com/desmond/squarecamera/ImageParameters.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | /**
7 | * Created by desmond on 9/8/15.
8 | */
9 | public class ImageParameters implements Parcelable {
10 |
11 | public boolean mIsPortrait;
12 |
13 | public int mDisplayOrientation;
14 | public int mLayoutOrientation;
15 |
16 | public int mCoverHeight, mCoverWidth;
17 | public int mPreviewHeight, mPreviewWidth;
18 |
19 | public ImageParameters(Parcel in) {
20 | mIsPortrait = (in.readByte() == 1);
21 |
22 | mDisplayOrientation = in.readInt();
23 | mLayoutOrientation = in.readInt();
24 |
25 | mCoverHeight = in.readInt();
26 | mCoverWidth = in.readInt();
27 | mPreviewHeight = in.readInt();
28 | mPreviewWidth = in.readInt();
29 | }
30 |
31 | public ImageParameters() {}
32 |
33 | public int calculateCoverWidthHeight() {
34 | return Math.abs(mPreviewHeight - mPreviewWidth) / 2;
35 | }
36 |
37 | public int getAnimationParameter() {
38 | return mIsPortrait ? mCoverHeight : mCoverWidth;
39 | }
40 |
41 | public boolean isPortrait() {
42 | return mIsPortrait;
43 | }
44 |
45 | public ImageParameters createCopy() {
46 | ImageParameters imageParameters = new ImageParameters();
47 |
48 | imageParameters.mIsPortrait = mIsPortrait;
49 | imageParameters.mDisplayOrientation = mDisplayOrientation;
50 | imageParameters.mLayoutOrientation = mLayoutOrientation;
51 |
52 | imageParameters.mCoverHeight = mCoverHeight;
53 | imageParameters.mCoverWidth = mCoverWidth;
54 | imageParameters.mPreviewHeight = mPreviewHeight;
55 | imageParameters.mPreviewWidth = mPreviewWidth;
56 |
57 | return imageParameters;
58 | }
59 |
60 | public String getStringValues() {
61 | return "is Portrait: " + mIsPortrait + "," +
62 | "\ncover height: " + mCoverHeight + " width: " + mCoverWidth
63 | + "\npreview height: " + mPreviewHeight + " width: " + mPreviewWidth;
64 | }
65 |
66 | @Override
67 | public int describeContents() {
68 | return 0;
69 | }
70 |
71 | @Override
72 | public void writeToParcel(Parcel dest, int flags) {
73 | dest.writeByte((byte) (mIsPortrait ? 1 : 0));
74 |
75 | dest.writeInt(mDisplayOrientation);
76 | dest.writeInt(mLayoutOrientation);
77 |
78 | dest.writeInt(mCoverHeight);
79 | dest.writeInt(mCoverWidth);
80 | dest.writeInt(mPreviewHeight);
81 | dest.writeInt(mPreviewWidth);
82 | }
83 |
84 | public static final Creator CREATOR = new Parcelable.Creator() {
85 | @Override
86 | public ImageParameters createFromParcel(Parcel source) {
87 | return new ImageParameters(source);
88 | }
89 |
90 | @Override
91 | public ImageParameters[] newArray(int size) {
92 | return new ImageParameters[size];
93 | }
94 | };
95 | }
96 |
--------------------------------------------------------------------------------
/squarecamera/src/main/java/com/desmond/squarecamera/ImageUtility.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.graphics.Matrix;
8 | import android.graphics.Point;
9 | import android.media.ThumbnailUtils;
10 | import android.net.Uri;
11 | import android.os.Build;
12 | import android.os.Environment;
13 | import android.util.Base64;
14 | import android.view.Display;
15 | import android.view.WindowManager;
16 |
17 | import java.io.ByteArrayOutputStream;
18 | import java.io.File;
19 | import java.io.FileOutputStream;
20 | import java.io.IOException;
21 | import java.text.SimpleDateFormat;
22 | import java.util.Date;
23 |
24 | /**
25 | * Created by desmond on 24/10/14.
26 | */
27 | public class ImageUtility {
28 |
29 | public static String convertBitmapToString(Bitmap bitmap) {
30 | ByteArrayOutputStream out = new ByteArrayOutputStream();
31 | bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
32 |
33 | return Base64.encodeToString(out.toByteArray(), Base64.DEFAULT);
34 | }
35 |
36 | public static byte[] convertBitmapStringToByteArray(String bitmapByteString) {
37 | return Base64.decode(bitmapByteString, Base64.DEFAULT);
38 | }
39 |
40 | public static Bitmap rotatePicture(Context context, int rotation, byte[] data) {
41 | Bitmap bitmap = decodeSampledBitmapFromByte(context, data);
42 |
43 | if (rotation != 0) {
44 | Bitmap oldBitmap = bitmap;
45 |
46 | Matrix matrix = new Matrix();
47 | matrix.postRotate(rotation);
48 |
49 | bitmap = Bitmap.createBitmap(
50 | oldBitmap, 0, 0, oldBitmap.getWidth(), oldBitmap.getHeight(), matrix, false
51 | );
52 |
53 | oldBitmap.recycle();
54 | }
55 |
56 | return bitmap;
57 | }
58 |
59 | public static Uri savePicture(Context context, Bitmap bitmap) {
60 | int cropHeight;
61 | if (bitmap.getHeight() > bitmap.getWidth()) cropHeight = bitmap.getWidth();
62 | else cropHeight = bitmap.getHeight();
63 |
64 | bitmap = ThumbnailUtils.extractThumbnail(bitmap, cropHeight, cropHeight, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
65 |
66 | File mediaStorageDir = new File(
67 | Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
68 | context.getString(R.string.squarecamera__app_name)
69 | );
70 |
71 | if (!mediaStorageDir.exists()) {
72 | if (!mediaStorageDir.mkdirs()) {
73 | return null;
74 | }
75 | }
76 |
77 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
78 | File mediaFile = new File(
79 | mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"
80 | );
81 |
82 | // Saving the bitmap
83 | try {
84 | ByteArrayOutputStream out = new ByteArrayOutputStream();
85 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
86 |
87 | FileOutputStream stream = new FileOutputStream(mediaFile);
88 | stream.write(out.toByteArray());
89 | stream.close();
90 |
91 | } catch (IOException exception) {
92 | exception.printStackTrace();
93 | }
94 |
95 | // Mediascanner need to scan for the image saved
96 | Intent mediaScannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
97 | Uri fileContentUri = Uri.fromFile(mediaFile);
98 | mediaScannerIntent.setData(fileContentUri);
99 | context.sendBroadcast(mediaScannerIntent);
100 |
101 | return fileContentUri;
102 | }
103 |
104 | public static Bitmap decodeSampledBitmapFromPath(String path, int reqWidth, int reqHeight) {
105 | final BitmapFactory.Options options = new BitmapFactory.Options();
106 | options.inJustDecodeBounds = true;
107 | options.inMutable = true;
108 | options.inBitmap = BitmapFactory.decodeFile(path, options);
109 |
110 | options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
111 |
112 | options.inScaled = true;
113 | options.inDensity = options.outWidth;
114 | options.inTargetDensity = reqWidth * options.inSampleSize;
115 |
116 | options.inJustDecodeBounds = false;
117 | options.inPurgeable = true;
118 | options.inInputShareable = true;
119 |
120 | return BitmapFactory.decodeFile(path, options);
121 | }
122 | /**
123 | * Decode and sample down a bitmap from a byte stream
124 | */
125 | public static Bitmap decodeSampledBitmapFromByte(Context context, byte[] bitmapBytes) {
126 | Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
127 |
128 | int reqWidth, reqHeight;
129 | Point point = new Point();
130 |
131 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
132 | display.getSize(point);
133 | reqWidth = point.x;
134 | reqHeight = point.y;
135 | } else {
136 | reqWidth = display.getWidth();
137 | reqHeight = display.getHeight();
138 | }
139 |
140 |
141 | final BitmapFactory.Options options = new BitmapFactory.Options();
142 | options.inJustDecodeBounds = true;
143 | options.inMutable = true;
144 | options.inBitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length, options);
145 |
146 | // Calculate inSampleSize
147 | options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
148 |
149 | // Load & resize the image to be 1/inSampleSize dimensions
150 | // Use when you do not want to scale the image with a inSampleSize that is a power of 2
151 | options.inScaled = true;
152 | options.inDensity = options.outWidth;
153 | options.inTargetDensity = reqWidth * options.inSampleSize;
154 |
155 | // Decode bitmap with inSampleSize set
156 | options.inJustDecodeBounds = false; // If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.
157 | options.inPurgeable = true; // Tell to gc that whether it needs free memory, the Bitmap can be cleared
158 | options.inInputShareable = true; // Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
159 |
160 | return BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length, options);
161 | }
162 |
163 | /**
164 | * Calculate an inSampleSize for use in a {@link android.graphics.BitmapFactory.Options} object when decoding
165 | * bitmaps using the decode* methods from {@link android.graphics.BitmapFactory}. This implementation calculates
166 | * the closest inSampleSize that is a power of 2 and will result in the final decoded bitmap
167 | * having a width and height equal to or larger than the requested width and height
168 | *
169 | * The function rounds up the sample size to a power of 2 or multiple
170 | * of 8 because BitmapFactory only honors sample size this way.
171 | * For example, BitmapFactory downsamples an image by 2 even though the
172 | * request is 3. So we round up the sample size to avoid OOM.
173 | */
174 | public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
175 | int initialInSampleSize = computeInitialSampleSize(options, reqWidth, reqHeight);
176 |
177 | int roundedInSampleSize;
178 | if (initialInSampleSize <= 8) {
179 | roundedInSampleSize = 1;
180 | while (roundedInSampleSize < initialInSampleSize) {
181 | // Shift one bit to left
182 | roundedInSampleSize <<= 1;
183 | }
184 | } else {
185 | roundedInSampleSize = (initialInSampleSize + 7) / 8 * 8;
186 | }
187 |
188 | return roundedInSampleSize;
189 | }
190 |
191 | private static int computeInitialSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
192 | // Raw height and width of image
193 | final double height = options.outHeight;
194 | final double width = options.outWidth;
195 |
196 | final long maxNumOfPixels = reqWidth * reqHeight;
197 | final int minSideLength = Math.min(reqHeight, reqWidth);
198 |
199 | int lowerBound = (maxNumOfPixels < 0) ? 1 :
200 | (int) Math.ceil(Math.sqrt(width * height / maxNumOfPixels));
201 | int upperBound = (minSideLength < 0) ? 128 :
202 | (int) Math.min(Math.floor(width / minSideLength),
203 | Math.floor(height / minSideLength));
204 |
205 | if (upperBound < lowerBound) {
206 | // return the larger one when there is no overlapping zone.
207 | return lowerBound;
208 | }
209 |
210 | if (maxNumOfPixels < 0 && minSideLength < 0) {
211 | return 1;
212 | } else if (minSideLength < 0) {
213 | return lowerBound;
214 | } else {
215 | return upperBound;
216 | }
217 | }
218 |
219 | }
220 |
--------------------------------------------------------------------------------
/squarecamera/src/main/java/com/desmond/squarecamera/ResizeAnimation.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.view.View;
5 | import android.view.animation.Animation;
6 | import android.view.animation.Transformation;
7 |
8 | /**
9 | * Created by desmond on 4/8/15.
10 | */
11 | public class ResizeAnimation extends Animation {
12 | // public static final String TAG = ResizeAnimation.class.getSimpleName();
13 |
14 | final int mStartLength;
15 | final int mFinalLength;
16 | final boolean mIsPortrait;
17 | final View mView;
18 |
19 | public ResizeAnimation(@NonNull View view, final ImageParameters imageParameters) {
20 | mIsPortrait = imageParameters.isPortrait();
21 | mView = view;
22 | mStartLength = mIsPortrait ? mView.getHeight() : mView.getWidth();
23 | mFinalLength = imageParameters.getAnimationParameter();
24 | // Log.d(TAG, "Start: " + mStartLength + " final: " + mFinalLength);
25 | }
26 |
27 | @Override
28 | protected void applyTransformation(float interpolatedTime, Transformation t) {
29 | int newLength = (int) (mStartLength + (mFinalLength - mStartLength) * interpolatedTime);
30 |
31 | if (mIsPortrait) {
32 | mView.getLayoutParams().height = newLength;
33 | } else {
34 | mView.getLayoutParams().width = newLength;
35 | }
36 |
37 | mView.requestLayout();
38 | }
39 |
40 | @Override
41 | public void initialize(int width, int height, int parentWidth, int parentHeight) {
42 | super.initialize(width, height, parentWidth, parentHeight);
43 | }
44 |
45 | @Override
46 | public boolean willChangeBounds() {
47 | return true;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/squarecamera/src/main/java/com/desmond/squarecamera/RuntimePermissionActivity.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 | import android.app.Activity;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.content.pm.PackageManager;
7 | import android.os.Bundle;
8 | import android.support.annotation.NonNull;
9 | import android.support.v4.app.ActivityCompat;
10 | import android.support.v4.app.Fragment;
11 | import android.support.v4.content.ContextCompat;
12 | import android.support.v7.app.AlertDialog;
13 | import android.support.v7.app.AppCompatActivity;
14 |
15 | import java.util.ArrayList;
16 | import java.util.Arrays;
17 |
18 | public class RuntimePermissionActivity extends AppCompatActivity {
19 |
20 | public static final String REQUESTED_PERMISSION = "requested_permission";
21 | private static final int REQUEST_CODE = 1;
22 |
23 | public static void startActivity(@NonNull final Fragment fragment,
24 | final int requestCode,
25 | @NonNull final String requestedPermission,
26 | final String... permissions) {
27 |
28 | final Intent intent = new Intent(fragment.getActivity(), RuntimePermissionActivity.class);
29 |
30 | final int capacity = 1 + (permissions != null ? permissions.length : 0);
31 | final ArrayList requestedPermissions = new ArrayList<>(capacity);
32 | requestedPermissions.add(requestedPermission);
33 | if (permissions != null) {
34 | requestedPermissions.addAll(Arrays.asList(permissions));
35 | }
36 |
37 | intent.putStringArrayListExtra(REQUESTED_PERMISSION, requestedPermissions);
38 | fragment.startActivityForResult(intent, requestCode);
39 | }
40 |
41 | /* https://code.google.com/p/android-developer-preview/issues/detail?id=2353 */
42 | @Override
43 | protected void onStart() {
44 | super.onStart();
45 | setVisible(true);
46 | }
47 |
48 | @Override
49 | protected void onCreate(Bundle savedInstanceState) {
50 | super.onCreate(savedInstanceState);
51 |
52 | final ArrayList reqPermissions = getIntent().getStringArrayListExtra(REQUESTED_PERMISSION);
53 | final ArrayList permissionsNeeded = getPermissionNeeded(reqPermissions);
54 | final ArrayList permissionRationaleNeeded = getPermissionRationaleNeeded(permissionsNeeded);
55 |
56 | if (!permissionRationaleNeeded.isEmpty()) {
57 | String message = getString(R.string.squarecamera__request_write_storage_permission_text);
58 | for (int i = 1; i < permissionRationaleNeeded.size(); ++i) {
59 | message += ", " + permissionRationaleNeeded.get(i);
60 | }
61 |
62 | showPermissionRationaleDialog(message, permissionsNeeded.toArray(new String[permissionsNeeded.size()]));
63 | } else if (!permissionsNeeded.isEmpty()) {
64 | requestForPermission(permissionsNeeded.toArray(new String[permissionsNeeded.size()]));
65 | } else {
66 | sendResult(true);
67 | }
68 | }
69 |
70 | private ArrayList getPermissionNeeded(@NonNull final ArrayList reqPermissions) {
71 | final ArrayList permissionNeeded = new ArrayList<>(reqPermissions.size());
72 |
73 | for (String reqPermission : reqPermissions) {
74 | if (ContextCompat.checkSelfPermission(RuntimePermissionActivity.this, reqPermission)
75 | != PackageManager.PERMISSION_GRANTED) {
76 | permissionNeeded.add(reqPermission);
77 | }
78 | }
79 |
80 | return permissionNeeded;
81 | }
82 |
83 | private ArrayList getPermissionRationaleNeeded(@NonNull final ArrayList permissionsNeeded) {
84 | final ArrayList rationaleNeeded = new ArrayList<>(permissionsNeeded.size());
85 |
86 | for (String permissionNeeded : permissionsNeeded) {
87 |
88 | if (ActivityCompat.shouldShowRequestPermissionRationale(
89 | RuntimePermissionActivity.this, permissionNeeded)) {
90 | rationaleNeeded.add(permissionNeeded);
91 | }
92 | }
93 |
94 | return rationaleNeeded;
95 | }
96 |
97 | @Override
98 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
99 | switch (requestCode) {
100 | case REQUEST_CODE:
101 | final int numOfRequest = grantResults.length;
102 | boolean isGranted = true;
103 | for (int i = 0; i < numOfRequest; i++) {
104 | if (PackageManager.PERMISSION_GRANTED != grantResults[i]) {
105 | isGranted = false;
106 | break;
107 | }
108 | }
109 | sendResult(isGranted);
110 | break;
111 |
112 | default:
113 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
114 | }
115 | }
116 |
117 | private void showPermissionRationaleDialog(final String message, final String[] permissions) {
118 | new AlertDialog.Builder(RuntimePermissionActivity.this)
119 | .setMessage(message)
120 | .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
121 | @Override
122 | public void onClick(DialogInterface dialog, int which) {
123 | RuntimePermissionActivity.this.requestForPermission(permissions);
124 | }
125 | })
126 | .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
127 | @Override
128 | public void onClick(DialogInterface dialog, int which) {
129 | RuntimePermissionActivity.this.sendResult(false);
130 | }
131 | })
132 | .setOnCancelListener(new DialogInterface.OnCancelListener() {
133 | @Override
134 | public void onCancel(DialogInterface dialog) {
135 | RuntimePermissionActivity.this.sendResult(false);
136 | }
137 | })
138 | .setOnDismissListener(new DialogInterface.OnDismissListener() {
139 | @Override
140 | public void onDismiss(DialogInterface dialog) {
141 | RuntimePermissionActivity.this.sendResult(false);
142 | }
143 | })
144 | .create()
145 | .show();
146 | }
147 |
148 | private void requestForPermission(final String[] permissions) {
149 | ActivityCompat.requestPermissions(RuntimePermissionActivity.this, permissions, REQUEST_CODE);
150 | }
151 |
152 | private void sendResult(final boolean isPermissionGranted) {
153 | final Intent resultIntent = new Intent();
154 | resultIntent.putExtra(REQUESTED_PERMISSION, isPermissionGranted);
155 | setResult(Activity.RESULT_OK, resultIntent);
156 | finish();
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/squarecamera/src/main/java/com/desmond/squarecamera/SquareCameraPreview.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 | import android.content.Context;
4 | import android.content.res.Configuration;
5 | import android.graphics.Rect;
6 | import android.hardware.Camera;
7 | import android.util.AttributeSet;
8 | import android.util.Log;
9 | import android.view.MotionEvent;
10 | import android.view.ScaleGestureDetector;
11 | import android.view.SurfaceView;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | /**
17 | *
18 | */
19 | public class SquareCameraPreview extends SurfaceView {
20 |
21 | public static final String TAG = SquareCameraPreview.class.getSimpleName();
22 | private static final int INVALID_POINTER_ID = -1;
23 |
24 | private static final int ZOOM_OUT = 0;
25 | private static final int ZOOM_IN = 1;
26 | private static final int ZOOM_DELTA = 1;
27 |
28 | private static final int FOCUS_SQR_SIZE = 100;
29 | private static final int FOCUS_MAX_BOUND = 1000;
30 | private static final int FOCUS_MIN_BOUND = -FOCUS_MAX_BOUND;
31 |
32 | private static final double ASPECT_RATIO = 3.0 / 4.0;
33 | private Camera mCamera;
34 |
35 | private float mLastTouchX;
36 | private float mLastTouchY;
37 |
38 | // For scaling
39 | private int mMaxZoom;
40 | private boolean mIsZoomSupported;
41 | private int mActivePointerId = INVALID_POINTER_ID;
42 | private int mScaleFactor = 1;
43 | private ScaleGestureDetector mScaleDetector;
44 |
45 | // For focus
46 | private boolean mIsFocus;
47 | private boolean mIsFocusReady;
48 | private Camera.Area mFocusArea;
49 | private ArrayList mFocusAreas;
50 |
51 | public SquareCameraPreview(Context context) {
52 | super(context);
53 | init(context);
54 | }
55 |
56 | public SquareCameraPreview(Context context, AttributeSet attrs) {
57 | super(context, attrs);
58 | init(context);
59 | }
60 |
61 | public SquareCameraPreview(Context context, AttributeSet attrs, int defStyle) {
62 | super(context, attrs, defStyle);
63 | init(context);
64 | }
65 |
66 | private void init(Context context) {
67 | mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
68 | mFocusArea = new Camera.Area(new Rect(), 1000);
69 | mFocusAreas = new ArrayList<>();
70 | mFocusAreas.add(mFocusArea);
71 | }
72 |
73 | /**
74 | * Measure the view and its content to determine the measured width and the
75 | * measured height
76 | */
77 | @Override
78 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
79 | int height = MeasureSpec.getSize(heightMeasureSpec);
80 | int width = MeasureSpec.getSize(widthMeasureSpec);
81 |
82 | final boolean isPortrait =
83 | getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
84 |
85 | if (isPortrait) {
86 | if (width > height * ASPECT_RATIO) {
87 | width = (int) (height * ASPECT_RATIO + 0.5);
88 | } else {
89 | height = (int) (width / ASPECT_RATIO + 0.5);
90 | }
91 | } else {
92 | if (height > width * ASPECT_RATIO) {
93 | height = (int) (width * ASPECT_RATIO + 0.5);
94 | } else {
95 | width = (int) (height / ASPECT_RATIO + 0.5);
96 | }
97 | }
98 |
99 | setMeasuredDimension(width, height);
100 | }
101 |
102 | public int getViewWidth() {
103 | return getWidth();
104 | }
105 |
106 | public int getViewHeight() {
107 | return getHeight();
108 | }
109 |
110 | public void setCamera(Camera camera) {
111 | mCamera = camera;
112 |
113 | if (camera != null) {
114 | Camera.Parameters params = camera.getParameters();
115 | mIsZoomSupported = params.isZoomSupported();
116 | if (mIsZoomSupported) {
117 | mMaxZoom = params.getMaxZoom();
118 | }
119 | }
120 | }
121 |
122 | @Override
123 | public boolean onTouchEvent(MotionEvent event) {
124 | mScaleDetector.onTouchEvent(event);
125 |
126 | final int action = event.getAction();
127 | switch (action & MotionEvent.ACTION_MASK) {
128 | case MotionEvent.ACTION_DOWN: {
129 | mIsFocus = true;
130 |
131 | mLastTouchX = event.getX();
132 | mLastTouchY = event.getY();
133 |
134 | mActivePointerId = event.getPointerId(0);
135 | break;
136 | }
137 | case MotionEvent.ACTION_UP: {
138 | if (mIsFocus && mIsFocusReady) {
139 | handleFocus(mCamera.getParameters());
140 | }
141 | mActivePointerId = INVALID_POINTER_ID;
142 | break;
143 | }
144 | case MotionEvent.ACTION_POINTER_DOWN: {
145 | mCamera.cancelAutoFocus();
146 | mIsFocus = false;
147 | break;
148 | }
149 | case MotionEvent.ACTION_CANCEL: {
150 | mActivePointerId = INVALID_POINTER_ID;
151 | break;
152 | }
153 | }
154 |
155 | return true;
156 | }
157 |
158 | private void handleZoom(Camera.Parameters params) {
159 | int zoom = params.getZoom();
160 | if (mScaleFactor == ZOOM_IN) {
161 | if (zoom < mMaxZoom) zoom += ZOOM_DELTA;
162 | } else if (mScaleFactor == ZOOM_OUT) {
163 | if (zoom > 0) zoom -= ZOOM_DELTA;
164 | }
165 | params.setZoom(zoom);
166 | mCamera.setParameters(params);
167 | }
168 |
169 | private void handleFocus(Camera.Parameters params) {
170 | float x = mLastTouchX;
171 | float y = mLastTouchY;
172 |
173 | if (!setFocusBound(x, y)) return;
174 |
175 | List supportedFocusModes = params.getSupportedFocusModes();
176 | if (supportedFocusModes != null
177 | && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
178 | Log.d(TAG, mFocusAreas.size() + "");
179 | params.setFocusAreas(mFocusAreas);
180 | params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
181 | mCamera.setParameters(params);
182 | mCamera.autoFocus(new Camera.AutoFocusCallback() {
183 | @Override
184 | public void onAutoFocus(boolean success, Camera camera) {
185 | // Callback when the auto focus completes
186 | }
187 | });
188 | }
189 | }
190 |
191 | public void setIsFocusReady(final boolean isFocusReady) {
192 | mIsFocusReady = isFocusReady;
193 | }
194 |
195 | private boolean setFocusBound(float x, float y) {
196 | int left = (int) (x - FOCUS_SQR_SIZE / 2);
197 | int right = (int) (x + FOCUS_SQR_SIZE / 2);
198 | int top = (int) (y - FOCUS_SQR_SIZE / 2);
199 | int bottom = (int) (y + FOCUS_SQR_SIZE / 2);
200 |
201 | if (FOCUS_MIN_BOUND > left || left > FOCUS_MAX_BOUND) return false;
202 | if (FOCUS_MIN_BOUND > right || right > FOCUS_MAX_BOUND) return false;
203 | if (FOCUS_MIN_BOUND > top || top > FOCUS_MAX_BOUND) return false;
204 | if (FOCUS_MIN_BOUND > bottom || bottom > FOCUS_MAX_BOUND) return false;
205 |
206 | mFocusArea.rect.set(left, top, right, bottom);
207 |
208 | return true;
209 | }
210 |
211 | private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
212 |
213 | @Override
214 | public boolean onScale(ScaleGestureDetector detector) {
215 | mScaleFactor = (int) detector.getScaleFactor();
216 | handleZoom(mCamera.getParameters());
217 | return true;
218 | }
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/squarecamera/src/main/java/com/desmond/squarecamera/SquareImageView.java:
--------------------------------------------------------------------------------
1 | package com.desmond.squarecamera;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.ImageView;
6 |
7 | /**
8 | * Created by desmond on 9/8/15.
9 | */
10 | public class SquareImageView extends ImageView {
11 |
12 | public SquareImageView(Context context) {
13 | super(context);
14 | }
15 |
16 | public SquareImageView(Context context, AttributeSet attrs) {
17 | super(context, attrs);
18 | }
19 |
20 | public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr) {
21 | super(context, attrs, defStyleAttr);
22 | }
23 |
24 | @Override
25 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
26 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
27 |
28 | int width = getMeasuredWidth();
29 | int height = getMeasuredHeight();
30 |
31 | int squareLen = width > height ? height : width;
32 | setMeasuredDimension(squareLen, squareLen);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/color/squarecamera__red_selectable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
9 |
11 |
12 |
14 |
16 |
18 |
20 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/color/squarecamera__white_selectable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
9 |
11 |
12 |
14 |
16 |
18 |
20 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__auto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__auto.png
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__camera.png
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__camera_snap_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__camera_snap_selected.png
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__camera_snap_unselected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__camera_snap_unselected.png
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__cancel_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__cancel_selected.png
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__cancel_unselected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__cancel_unselected.png
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__save_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__save_selected.png
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__save_unselected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__save_unselected.png
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__toggle_flash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxme/SquareCamera/aa1d02be33104e312c8658bec3f896a7181ebacd/squarecamera/src/main/res/drawable-xxhdpi/squarecamera__toggle_flash.png
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable/squarecamera__cancel_drawable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable/squarecamera__capture_photo_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/drawable/squarecamera__save_photo_drawable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/layout-land/squarecamera__fragment_camera.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
19 |
20 |
26 |
27 |
37 |
38 |
45 |
46 |
51 |
52 |
62 |
63 |
64 |
65 |
71 |
72 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/layout-land/squarecamera__fragment_edit_save_photo.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
30 |
31 |
39 |
40 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/layout/squarecamera__activity_camera.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/layout/squarecamera__fragment_camera.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
19 |
20 |
26 |
27 |
37 |
38 |
44 |
45 |
51 |
52 |
59 |
60 |
65 |
66 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/layout/squarecamera__fragment_edit_save_photo.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
19 |
20 |
29 |
30 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/menu/squarecamera__menu_blank.xml:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/menu/squarecamera__menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/values-v19/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
9 | 64dp
10 |
11 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #F0001D
4 | #B3F0001D
5 | #FFFFFF
6 | #99FFFFFF
7 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 300dp
6 | 250dp
7 |
8 | 16dp
9 | 16dp
10 | 16dp
11 |
12 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SquareCamera
5 | Settings
6 | Take New Picture!
7 | Snap It!
8 | Save
9 | Cancel
10 | Swap
11 | Flash
12 | Auto Flash
13 | No Flash
14 | Retake Picture
15 | Taking New Picture
16 | Done
17 | Approval is needed to save your photo on your device
18 |
19 |
--------------------------------------------------------------------------------
/squarecamera/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
15 |
16 |
18 |
19 |
21 |
22 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------