diff --git a/README.md b/README.md
index 05ed858a..cb5af06d 100644
--- a/README.md
+++ b/README.md
@@ -14,8 +14,9 @@ compile 'com.otaliastudios:cameraview:1.2.1'
```
-
-
+
+
+
*This was a fork of [CameraKit-Android library](https://github.com/gogopop/CameraKit-Android), originally a fork of [Google's CameraView library](https://github.com/google/cameraview), but has been [completely rewritten](https://github.com/natario1/CameraView/graphs/contributors?type=d). See [below](#roadmap) for a list of what was done. Feel free to contribute - this is under active development.*
diff --git a/art/screen1.png b/art/old_screen1.png
similarity index 100%
rename from art/screen1.png
rename to art/old_screen1.png
diff --git a/art/screen2.png b/art/old_screen2.png
similarity index 100%
rename from art/screen2.png
rename to art/old_screen2.png
diff --git a/art/screen1.jpg b/art/screen1.jpg
new file mode 100644
index 00000000..4c132942
Binary files /dev/null and b/art/screen1.jpg differ
diff --git a/art/screen2.jpg b/art/screen2.jpg
new file mode 100644
index 00000000..2f0d3a29
Binary files /dev/null and b/art/screen2.jpg differ
diff --git a/art/screen3.jpg b/art/screen3.jpg
new file mode 100644
index 00000000..5abf710b
Binary files /dev/null and b/art/screen3.jpg differ
diff --git a/demo/build.gradle b/demo/build.gradle
index 72c1e043..fb063b1f 100644
--- a/demo/build.gradle
+++ b/demo/build.gradle
@@ -23,6 +23,5 @@ android {
dependencies {
compile project(':cameraview')
compile "com.android.support:appcompat-v7:$supportLibVersion"
- compile 'com.jakewharton:butterknife:8.4.0'
- annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
+ compile "com.android.support:design:$supportLibVersion"
}
diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml
index f3c04d1c..9447b52c 100644
--- a/demo/src/main/AndroidManifest.xml
+++ b/demo/src/main/AndroidManifest.xml
@@ -13,7 +13,7 @@
android:theme="@style/AppTheme">
diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/AutoUnfocusEditText.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/AutoUnfocusEditText.java
deleted file mode 100644
index 59c651b6..00000000
--- a/demo/src/main/java/com/otaliastudios/cameraview/demo/AutoUnfocusEditText.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.otaliastudios.cameraview.demo;
-
-import android.content.Context;
-import android.support.v7.widget.AppCompatEditText;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.inputmethod.InputMethodManager;
-
-public class AutoUnfocusEditText extends AppCompatEditText {
-
- public AutoUnfocusEditText(Context context) {
- super(context);
- }
-
- public AutoUnfocusEditText(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public AutoUnfocusEditText(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- public boolean onKeyPreIme(int keyCode, KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- closeKeyboard();
- clearFocus();
- return true;
- }
-
- return super.dispatchKeyEvent(event);
- }
-
- private void closeKeyboard() {
- InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(getWindowToken(), 0);
- }
-
-}
diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java
new file mode 100644
index 00000000..7be67483
--- /dev/null
+++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java
@@ -0,0 +1,211 @@
+package com.otaliastudios.cameraview.demo;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.design.widget.BottomSheetBehavior;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.Toast;
+
+import com.otaliastudios.cameraview.Audio;
+import com.otaliastudios.cameraview.CameraListener;
+import com.otaliastudios.cameraview.CameraLogger;
+import com.otaliastudios.cameraview.CameraOptions;
+import com.otaliastudios.cameraview.CameraView;
+import com.otaliastudios.cameraview.Flash;
+import com.otaliastudios.cameraview.Grid;
+import com.otaliastudios.cameraview.SessionType;
+import com.otaliastudios.cameraview.Size;
+import com.otaliastudios.cameraview.VideoQuality;
+import com.otaliastudios.cameraview.WhiteBalance;
+
+import java.io.File;
+
+
+public class CameraActivity extends AppCompatActivity implements View.OnClickListener, ControlView.Callback {
+
+ private CameraView camera;
+ private ViewGroup controlPanel;
+
+ private boolean mCapturingPicture;
+ private boolean mCapturingVideo;
+
+ // To show stuff in the callback
+ private Size mCaptureNativeSize;
+ private long mCaptureTime;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_camera);
+ CameraLogger.setLogLevel(CameraLogger.LEVEL_VERBOSE);
+
+ camera = findViewById(R.id.camera);
+ camera.addCameraListener(new CameraListener() {
+ public void onCameraOpened(CameraOptions options) { onOpened(); }
+ public void onPictureTaken(byte[] jpeg) { onPicture(jpeg); }
+ public void onVideoTaken(File video) { onVideo(video); }
+ });
+
+ findViewById(R.id.edit).setOnClickListener(this);
+ findViewById(R.id.capturePhoto).setOnClickListener(this);
+ findViewById(R.id.captureVideo).setOnClickListener(this);
+ findViewById(R.id.toggleCamera).setOnClickListener(this);
+
+ controlPanel = findViewById(R.id.controls);
+ ViewGroup group = (ViewGroup) controlPanel.getChildAt(0);
+ Control[] controls = Control.values();
+ for (Control control : controls) {
+ ControlView view = new ControlView(this, control, this);
+ group.addView(view, ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ }
+
+ controlPanel.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ BottomSheetBehavior b = BottomSheetBehavior.from(controlPanel);
+ b.setState(BottomSheetBehavior.STATE_HIDDEN);
+ }
+ });
+ }
+
+ private void message(String content, boolean important) {
+ int length = important ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT;
+ Toast.makeText(this, content, length).show();
+ }
+
+ private void onOpened() {
+ ViewGroup group = (ViewGroup) controlPanel.getChildAt(0);
+ for (int i = 0; i < group.getChildCount(); i++) {
+ ControlView view = (ControlView) group.getChildAt(i);
+ view.onCameraOpened(camera);
+ }
+ }
+
+ private void onPicture(byte[] jpeg) {
+ mCapturingPicture = false;
+ long callbackTime = System.currentTimeMillis();
+ if (mCapturingVideo) {
+ message("Captured while taking video. Size="+mCaptureNativeSize, false);
+ return;
+ }
+
+ // This can happen if picture was taken with a gesture.
+ if (mCaptureTime == 0) mCaptureTime = callbackTime - 300;
+ if (mCaptureNativeSize == null) mCaptureNativeSize = camera.getCaptureSize();
+
+ PicturePreviewActivity.setImage(jpeg);
+ Intent intent = new Intent(CameraActivity.this, PicturePreviewActivity.class);
+ intent.putExtra("delay", callbackTime - mCaptureTime);
+ intent.putExtra("nativeWidth", mCaptureNativeSize.getWidth());
+ intent.putExtra("nativeHeight", mCaptureNativeSize.getHeight());
+ startActivity(intent);
+
+ mCaptureTime = 0;
+ mCaptureNativeSize = null;
+ }
+
+ private void onVideo(File video) {
+ mCapturingVideo = false;
+ Intent intent = new Intent(CameraActivity.this, VideoPreviewActivity.class);
+ intent.putExtra("video", Uri.fromFile(video));
+ startActivity(intent);
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.edit: edit(); break;
+ case R.id.capturePhoto: capturePhoto(); break;
+ case R.id.captureVideo: captureVideo(); break;
+ case R.id.toggleCamera: toggleCamera(); break;
+ }
+ }
+
+ private void edit() {
+ BottomSheetBehavior b = BottomSheetBehavior.from(controlPanel);
+ b.setState(BottomSheetBehavior.STATE_COLLAPSED);
+ }
+
+ private void capturePhoto() {
+ if (mCapturingPicture) return;
+ mCapturingPicture = true;
+ mCaptureTime = System.currentTimeMillis();
+ mCaptureNativeSize = camera.getCaptureSize();
+ message("Capturing picture...", false);
+ camera.capturePicture();
+ }
+
+ private void captureVideo() {
+ if (camera.getSessionType() != SessionType.VIDEO) {
+ message("Can't record video while session type is 'picture'.", false);
+ return;
+ }
+ if (mCapturingPicture || mCapturingVideo) return;
+ mCapturingVideo = true;
+ message("Recording for 8 seconds...", true);
+ camera.startCapturingVideo(null, 8000);
+ }
+
+ private void toggleCamera() {
+ if (mCapturingPicture) return;
+ switch (camera.toggleFacing()) {
+ case BACK:
+ message("Switched to back camera!", false);
+ break;
+
+ case FRONT:
+ message("Switched to front camera!", false);
+ break;
+ }
+ }
+
+ @Override
+ public void onValueChanged(Control control, Object value, String name) {
+ control.applyValue(camera, value);
+ BottomSheetBehavior b = BottomSheetBehavior.from(controlPanel);
+ b.setState(BottomSheetBehavior.STATE_HIDDEN);
+ message("Changed " + control.getName() + " to " + name, false);
+ }
+
+ //region Boilerplate
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ camera.start();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ camera.stop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ camera.destroy();
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ boolean valid = true;
+ for (int grantResult : grantResults) {
+ valid = valid && grantResult == PackageManager.PERMISSION_GRANTED;
+ }
+ if (valid && !camera.isStarted()) {
+ camera.start();
+ }
+ }
+
+ //endregion
+}
diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/Control.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/Control.java
new file mode 100644
index 00000000..74fbccb3
--- /dev/null
+++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/Control.java
@@ -0,0 +1,176 @@
+package com.otaliastudios.cameraview.demo;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.otaliastudios.cameraview.Audio;
+import com.otaliastudios.cameraview.CameraOptions;
+import com.otaliastudios.cameraview.CameraView;
+import com.otaliastudios.cameraview.Flash;
+import com.otaliastudios.cameraview.Gesture;
+import com.otaliastudios.cameraview.GestureAction;
+import com.otaliastudios.cameraview.Grid;
+import com.otaliastudios.cameraview.SessionType;
+import com.otaliastudios.cameraview.VideoQuality;
+import com.otaliastudios.cameraview.WhiteBalance;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Controls that we want to display in a ControlView.
+ */
+public enum Control {
+
+ WIDTH("Width", false),
+ HEIGHT("Height", true),
+ SESSION("Session type", false),
+ CROP_OUTPUT("Crop output", true),
+ FLASH("Flash", false),
+ WHITE_BALANCE("White balance", false),
+ GRID("Grid", true),
+ VIDEO_QUALITY("Video quality", false),
+ AUDIO("Audio", true),
+ PINCH("Pinch gesture", false),
+ HSCROLL("Horizontal scroll gesture", false),
+ VSCROLL("Vertical scroll gesture", false),
+ TAP("Single tap gesture", false),
+ LONG_TAP("Long tap gesture", true);
+
+ private String name;
+ private boolean last;
+
+ Control(String n, boolean l) {
+ name = n;
+ last = l;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isSectionLast() {
+ return last;
+ }
+
+ public Collection> getValues(CameraView view) {
+ CameraOptions options = view.getCameraOptions();
+ switch (this) {
+ case WIDTH:
+ case HEIGHT:
+ View root = (View) view.getParent();
+ ArrayList list = new ArrayList<>();
+ int boundary = this == WIDTH ? root.getWidth() : root.getHeight();
+ if (boundary == 0) boundary = 1000;
+ int step = boundary / 10;
+ list.add(ViewGroup.LayoutParams.WRAP_CONTENT);
+ list.add(ViewGroup.LayoutParams.MATCH_PARENT);
+ for (int i = step; i < boundary; i += step) {
+ list.add(i);
+ }
+ return list;
+ case SESSION: return Arrays.asList(SessionType.values());
+ case CROP_OUTPUT: return Arrays.asList(true, false);
+ case FLASH: return options.getSupportedFlash();
+ case WHITE_BALANCE: return options.getSupportedWhiteBalance();
+ case GRID: return Arrays.asList(Grid.values());
+ case VIDEO_QUALITY: return Arrays.asList(VideoQuality.values());
+ case AUDIO: return Arrays.asList(Audio.values());
+ case PINCH:
+ case HSCROLL:
+ case VSCROLL:
+ ArrayList list1 = new ArrayList<>();
+ addIfSupported(options, list1, GestureAction.NONE);
+ addIfSupported(options, list1, GestureAction.ZOOM);
+ addIfSupported(options, list1, GestureAction.EXPOSURE_CORRECTION);
+ return list1;
+ case TAP:
+ case LONG_TAP:
+ ArrayList list2 = new ArrayList<>();
+ addIfSupported(options, list2, GestureAction.NONE);
+ addIfSupported(options, list2, GestureAction.CAPTURE);
+ addIfSupported(options, list2, GestureAction.FOCUS);
+ addIfSupported(options, list2, GestureAction.FOCUS_WITH_MARKER);
+ return list2;
+
+ }
+ return null;
+ }
+
+ private void addIfSupported(CameraOptions options, List list, GestureAction value) {
+ if (options.supports(value)) list.add(value);
+ }
+
+ public Object getCurrentValue(CameraView view) {
+ switch (this) {
+ case WIDTH: return view.getLayoutParams().width;
+ case HEIGHT: return view.getLayoutParams().height;
+ case SESSION: return view.getSessionType();
+ case CROP_OUTPUT: return view.getCropOutput();
+ case FLASH: return view.getFlash();
+ case WHITE_BALANCE: return view.getWhiteBalance();
+ case GRID: return view.getGrid();
+ case VIDEO_QUALITY: return view.getVideoQuality();
+ case AUDIO: return view.getAudio();
+ case PINCH: return view.getGestureAction(Gesture.PINCH);
+ case HSCROLL: return view.getGestureAction(Gesture.SCROLL_HORIZONTAL);
+ case VSCROLL: return view.getGestureAction(Gesture.SCROLL_VERTICAL);
+ case TAP: return view.getGestureAction(Gesture.TAP);
+ case LONG_TAP: return view.getGestureAction(Gesture.LONG_TAP);
+ }
+ return null;
+ }
+
+ public void applyValue(CameraView camera, Object value) {
+ switch (this) {
+ case WIDTH:
+ camera.getLayoutParams().width = (int) value;
+ camera.setLayoutParams(camera.getLayoutParams());
+ break;
+ case HEIGHT:
+ camera.getLayoutParams().height = (int) value;
+ camera.setLayoutParams(camera.getLayoutParams());
+ break;
+ case SESSION:
+ camera.setSessionType((SessionType) value);
+ break;
+ case CROP_OUTPUT:
+ camera.setCropOutput((boolean) value);
+ break;
+ case FLASH:
+ camera.setFlash((Flash) value);
+ break;
+ case WHITE_BALANCE:
+ camera.setWhiteBalance((WhiteBalance) value);
+ break;
+ case GRID:
+ camera.setGrid((Grid) value);
+ break;
+ case VIDEO_QUALITY:
+ camera.setVideoQuality((VideoQuality) value);
+ break;
+ case AUDIO:
+ camera.setAudio((Audio) value);
+ break;
+ case PINCH:
+ camera.mapGesture(Gesture.PINCH, (GestureAction) value);
+ break;
+ case HSCROLL:
+ camera.mapGesture(Gesture.SCROLL_HORIZONTAL, (GestureAction) value);
+ break;
+ case VSCROLL:
+ camera.mapGesture(Gesture.SCROLL_VERTICAL, (GestureAction) value);
+ break;
+ case TAP:
+ camera.mapGesture(Gesture.TAP, (GestureAction) value);
+ break;
+ case LONG_TAP:
+ camera.mapGesture(Gesture.LONG_TAP, (GestureAction) value);
+ break;
+ }
+ }
+
+
+}
diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/ControlView.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/ControlView.java
new file mode 100644
index 00000000..bab55baa
--- /dev/null
+++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/ControlView.java
@@ -0,0 +1,103 @@
+package com.otaliastudios.cameraview.demo;
+
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+import android.widget.TextView;
+
+import com.otaliastudios.cameraview.CameraOptions;
+import com.otaliastudios.cameraview.CameraView;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class ControlView extends LinearLayout implements Spinner.OnItemSelectedListener {
+
+ interface Callback {
+ void onValueChanged(Control control, Object value, String name);
+ }
+
+ private Value value;
+ private ArrayList values;
+ private ArrayList valuesStrings;
+ private Control control;
+ private Callback callback;
+ private Spinner spinner;
+
+ public ControlView(Context context, Control control, Callback callback) {
+ super(context);
+ this.control = control;
+ this.callback = callback;
+ setOrientation(VERTICAL);
+
+ inflate(context, R.layout.control_view, this);
+ TextView title = findViewById(R.id.title);
+ title.setText(control.getName());
+ View divider = findViewById(R.id.divider);
+ divider.setVisibility(control.isSectionLast() ? View.VISIBLE : View.GONE);
+
+ ViewGroup content = findViewById(R.id.content);
+ spinner = new Spinner(context, Spinner.MODE_DROPDOWN);
+ content.addView(spinner);
+ }
+
+ public Value getValue() {
+ return value;
+ }
+
+ @SuppressWarnings("all")
+ public void onCameraOpened(CameraView view) {
+ values = new ArrayList(control.getValues(view));
+ value = (Value) control.getCurrentValue(view);
+ valuesStrings = new ArrayList<>();
+ for (Value value : values) {
+ valuesStrings.add(stringify(value));
+ }
+
+ if (values.isEmpty()) {
+ spinner.setOnItemSelectedListener(null);
+ spinner.setEnabled(false);
+ spinner.setAlpha(0.8f);
+ spinner.setAdapter(new ArrayAdapter(getContext(),
+ R.layout.spinner_text, new String[]{ "Not supported." }));
+ spinner.setSelection(0, false);
+ } else {
+ spinner.setEnabled(true);
+ spinner.setAlpha(1f);
+ spinner.setAdapter(new ArrayAdapter(getContext(),
+ R.layout.spinner_text, valuesStrings));
+ spinner.setSelection(values.indexOf(value), false);
+ spinner.setOnItemSelectedListener(this);
+ }
+ }
+
+ @Override
+ public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
+ if (values.get(i) != value) {
+ Log.e("ControlView", "curr: " + value + " new: " + values.get(i));
+ callback.onValueChanged(control, values.get(i), valuesStrings.get(i));
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView) {}
+
+ private String stringify(Value value) {
+ if (value instanceof Integer) {
+ if ((Integer) value == ViewGroup.LayoutParams.MATCH_PARENT) return "match parent";
+ if ((Integer) value == ViewGroup.LayoutParams.WRAP_CONTENT) return "wrap content";
+ }
+ return String.valueOf(value).replace("_", " ").toLowerCase();
+ }
+}
diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/MainActivity.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/MainActivity.java
deleted file mode 100644
index 8c3cee08..00000000
--- a/demo/src/main/java/com/otaliastudios/cameraview/demo/MainActivity.java
+++ /dev/null
@@ -1,375 +0,0 @@
-package com.otaliastudios.cameraview.demo;
-
-import android.content.Intent;
-import android.location.Location;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.RadioGroup;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.otaliastudios.cameraview.CameraListener;
-import com.otaliastudios.cameraview.CameraLogger;
-import com.otaliastudios.cameraview.CameraView;
-import com.otaliastudios.cameraview.Grid;
-import com.otaliastudios.cameraview.SessionType;
-import com.otaliastudios.cameraview.Size;
-import com.otaliastudios.cameraview.VideoQuality;
-
-import java.io.File;
-
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import butterknife.OnClick;
-
-public class MainActivity extends AppCompatActivity implements View.OnLayoutChangeListener {
-
- @BindView(R.id.activity_main)
- ViewGroup parent;
-
- @BindView(R.id.camera)
- CameraView camera;
-
- // Capture Mode:
- @BindView(R.id.sessionTypeRadioGroup)
- RadioGroup sessionTypeRadioGroup;
-
- // Crop Mode:
- @BindView(R.id.cropModeRadioGroup)
- RadioGroup cropModeRadioGroup;
-
- // Video Quality:
- @BindView(R.id.videoQualityRadioGroup)
- RadioGroup videoQualityRadioGroup;
-
- // Grid mode:
- @BindView(R.id.gridModeRadioGroup)
- RadioGroup gridModeRadioGroup;
-
- // Width:
- @BindView(R.id.screenWidth)
- TextView screenWidth;
- @BindView(R.id.width)
- EditText width;
- @BindView(R.id.widthUpdate)
- Button widthUpdate;
- @BindView(R.id.widthModeRadioGroup)
- RadioGroup widthModeRadioGroup;
-
- // Height:
- @BindView(R.id.screenHeight)
- TextView screenHeight;
- @BindView(R.id.height)
- EditText height;
- @BindView(R.id.heightUpdate)
- Button heightUpdate;
- @BindView(R.id.heightModeRadioGroup)
- RadioGroup heightModeRadioGroup;
-
- private boolean mCapturingPicture;
- private boolean mCapturingVideo;
-
- // To show stuff in the callback
- private Size mCaptureNativeSize;
- private long mCaptureTime;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- ButterKnife.bind(this);
- CameraLogger.setLogLevel(CameraLogger.LEVEL_VERBOSE);
-
- parent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- screenWidth.setText("screen: " + parent.getWidth() + "px");
- screenHeight.setText("screen: " + parent.getHeight() + "px");
- }
- });
-
- sessionTypeRadioGroup.setOnCheckedChangeListener(sessionTypeChangedListener);
- cropModeRadioGroup.setOnCheckedChangeListener(cropModeChangedListener);
- widthModeRadioGroup.setOnCheckedChangeListener(widthModeChangedListener);
- heightModeRadioGroup.setOnCheckedChangeListener(heightModeChangedListener);
- videoQualityRadioGroup.setOnCheckedChangeListener(videoQualityChangedListener);
- gridModeRadioGroup.setOnCheckedChangeListener(gridModeChangedListener);
-
- camera.addOnLayoutChangeListener(this);
- camera.addCameraListener(new CameraListener() {
- @Override
- public void onPictureTaken(byte[] jpeg) {
- super.onPictureTaken(jpeg);
- mCapturingPicture = false;
- long callbackTime = System.currentTimeMillis();
- if (mCapturingVideo) {
- message("Captured while taking video. Size="+mCaptureNativeSize, false);
- return;
- }
- PicturePreviewActivity.setImage(jpeg);
- Intent intent = new Intent(MainActivity.this, PicturePreviewActivity.class);
- intent.putExtra("delay", callbackTime - mCaptureTime);
- intent.putExtra("nativeWidth", mCaptureNativeSize.getWidth());
- intent.putExtra("nativeHeight", mCaptureNativeSize.getHeight());
- startActivity(intent);
- }
-
- @Override
- public void onVideoTaken(File video) {
- super.onVideoTaken(video);
- mCapturingVideo = false;
- Intent intent = new Intent(MainActivity.this, VideoPreviewActivity.class);
- intent.putExtra("video", Uri.fromFile(video));
- startActivity(intent);
- }
- });
-
- // Debug location.
- /* camera.postDelayed(new Runnable() {
- @Override
- public void run() {
- message("set Location", false);
- camera.setLocation(-20, 40.12345);
- }
- }, 4500); */
- }
-
- private void message(String content, boolean important) {
- int length = important ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT;
- Toast.makeText(this, content, length).show();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- camera.start();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- camera.stop();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- camera.destroy();
- }
-
-
- @OnClick(R.id.capturePhoto)
- void capturePhoto() {
- if (mCapturingPicture) return;
- mCapturingPicture = true;
- mCaptureTime = System.currentTimeMillis();
- mCaptureNativeSize = camera.getCaptureSize();
- message("Capturing picture...", false);
- camera.capturePicture();
- }
-
- @OnClick(R.id.captureVideo)
- void captureVideo() {
- if (camera.getSessionType() != SessionType.VIDEO) {
- message("Can't record video while session type is 'picture'.", false);
- return;
- }
- if (mCapturingPicture || mCapturingVideo) return;
- mCapturingVideo = true;
- message("Recording for 8 seconds...", true);
- camera.startCapturingVideo(null, 8000);
- }
-
- @OnClick(R.id.toggleCamera)
- void toggleCamera() {
- if (mCapturingPicture) return;
- switch (camera.toggleFacing()) {
- case BACK:
- message("Switched to back camera!", false);
- break;
-
- case FRONT:
- message("Switched to front camera!", false);
- break;
- }
- }
-
- @OnClick(R.id.toggleFlash)
- void toggleFlash() {
- if (mCapturingPicture) return;
- switch (camera.toggleFlash()) {
- case ON:
- message("Flash on!", false);
- break;
-
- case OFF:
- message("Flash off!", false);
- break;
-
- case AUTO:
- message("Flash auto!", false);
- break;
- }
- }
-
- RadioGroup.OnCheckedChangeListener sessionTypeChangedListener = new RadioGroup.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(RadioGroup group, int checkedId) {
- if (mCapturingPicture) return;
- boolean pic = checkedId == R.id.sessionTypePicture;
- camera.setSessionType(pic ? SessionType.PICTURE : SessionType.VIDEO);
- message("Session type set to" + (pic ? " picture!" : " video!"), true);
- }
- };
-
- RadioGroup.OnCheckedChangeListener cropModeChangedListener = new RadioGroup.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(RadioGroup group, int checkedId) {
- if (mCapturingPicture) return;
- camera.setCropOutput(checkedId == R.id.modeCropVisible);
- message("Picture cropping is" + (checkedId == R.id.modeCropVisible ? " on!" : " off!"), false);
- }
- };
-
- RadioGroup.OnCheckedChangeListener videoQualityChangedListener = new RadioGroup.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(RadioGroup group, int checkedId) {
- if (mCapturingVideo) return;
- VideoQuality videoQuality = VideoQuality.HIGHEST;
- switch (checkedId) {
- case R.id.videoQualityLowest: videoQuality = VideoQuality.LOWEST; break;
- case R.id.videoQualityQvga: videoQuality = VideoQuality.MAX_QVGA; break;
- case R.id.videoQuality480p: videoQuality = VideoQuality.MAX_480P; break;
- case R.id.videoQuality720p: videoQuality = VideoQuality.MAX_720P; break;
- case R.id.videoQuality1080p: videoQuality = VideoQuality.MAX_1080P; break;
- case R.id.videoQuality2160p: videoQuality = VideoQuality.MAX_2160P; break;
- case R.id.videoQualityHighest: videoQuality = VideoQuality.HIGHEST; break;
- }
- camera.setVideoQuality(videoQuality);
- message("Video quality changed!", false);
- }
- };
-
-
- RadioGroup.OnCheckedChangeListener gridModeChangedListener = new RadioGroup.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(RadioGroup group, int checkedId) {
- Grid grid = Grid.OFF;
- switch (checkedId) {
- case R.id.gridModeOff: grid = Grid.OFF; break;
- case R.id.gridMode3x3: grid = Grid.DRAW_3X3; break;
- case R.id.gridMode4x4: grid = Grid.DRAW_4X4; break;
- case R.id.gridModeGolden: grid = Grid.DRAW_PHI; break;
- }
- camera.setGrid(grid);
- message("Grid mode changed!", false);
- }
- };
-
-
- @OnClick(R.id.widthUpdate)
- void widthUpdateClicked() {
- if (mCapturingPicture) return;
- if (widthUpdate.getAlpha() >= 1) {
- updateCamera(true, false);
- }
- }
-
- RadioGroup.OnCheckedChangeListener widthModeChangedListener = new RadioGroup.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(RadioGroup group, int checkedId) {
- if (mCapturingPicture) return;
- widthUpdate.setEnabled(checkedId == R.id.widthCustom);
- widthUpdate.setAlpha(checkedId == R.id.widthCustom ? 1f : 0.3f);
- width.clearFocus();
- width.setEnabled(checkedId == R.id.widthCustom);
- width.setAlpha(checkedId == R.id.widthCustom ? 1f : 0.5f);
-
- updateCamera(true, false);
- }
- };
-
- @OnClick(R.id.heightUpdate)
- void heightUpdateClicked() {
- if (mCapturingPicture) return;
- if (heightUpdate.getAlpha() >= 1) {
- updateCamera(false, true);
- }
- }
-
- RadioGroup.OnCheckedChangeListener heightModeChangedListener = new RadioGroup.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(RadioGroup group, int checkedId) {
- if (mCapturingPicture) return;
- heightUpdate.setEnabled(checkedId == R.id.heightCustom);
- heightUpdate.setAlpha(checkedId == R.id.heightCustom ? 1f : 0.3f);
- height.clearFocus();
- height.setEnabled(checkedId == R.id.heightCustom);
- height.setAlpha(checkedId == R.id.heightCustom ? 1f : 0.5f);
-
- updateCamera(false, true);
- }
- };
-
- private void updateCamera(boolean updateWidth, boolean updateHeight) {
- if (mCapturingPicture) return;
- ViewGroup.LayoutParams cameraLayoutParams = camera.getLayoutParams();
- int width = cameraLayoutParams.width;
- int height = cameraLayoutParams.height;
-
- if (updateWidth) {
- switch (widthModeRadioGroup.getCheckedRadioButtonId()) {
- case R.id.widthCustom:
- String widthInput = this.width.getText().toString();
- try { width = Integer.valueOf(widthInput); } catch (Exception e) {}
- break;
- case R.id.widthWrapContent:
- width = ViewGroup.LayoutParams.WRAP_CONTENT;
- break;
- case R.id.widthMatchParent:
- width = ViewGroup.LayoutParams.MATCH_PARENT;
- break;
- }
- }
-
- if (updateHeight) {
- switch (heightModeRadioGroup.getCheckedRadioButtonId()) {
- case R.id.heightCustom:
- String heightInput = this.height.getText().toString();
- try { height = Integer.valueOf(heightInput); } catch (Exception e) {}
- break;
- case R.id.heightWrapContent:
- height = ViewGroup.LayoutParams.WRAP_CONTENT;
- break;
- case R.id.heightMatchParent:
- // We are in a vertically scrolling container, match parent would not work at all.
- height = parent.getHeight();
- break;
- }
- }
-
- cameraLayoutParams.width = width;
- cameraLayoutParams.height = height;
- camera.addOnLayoutChangeListener(this);
- camera.setLayoutParams(cameraLayoutParams);
-
- String what = (updateWidth && updateHeight ? "Width and height" : updateWidth ? "Width" : "Height");
- message(what + " updated! Internal preview size: " + camera.getPreviewSize(), false);
- }
-
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
- int mCameraWidth = right - left;
- int mCameraHeight = bottom - top;
- width.setText(String.valueOf(mCameraWidth));
- height.setText(String.valueOf(mCameraHeight));
- camera.removeOnLayoutChangeListener(this);
- }
-
-}
diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/MessageView.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/MessageView.java
new file mode 100644
index 00000000..d123ceea
--- /dev/null
+++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/MessageView.java
@@ -0,0 +1,50 @@
+package com.otaliastudios.cameraview.demo;
+
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.otaliastudios.cameraview.CameraView;
+
+import java.util.ArrayList;
+
+public class MessageView extends LinearLayout {
+
+ private TextView message;
+ private TextView title;
+
+ public MessageView(Context context) {
+ this(context, null);
+ }
+
+ public MessageView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public MessageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setOrientation(VERTICAL);
+ inflate(context, R.layout.control_view, this);
+ ViewGroup content = findViewById(R.id.content);
+ inflate(context, R.layout.spinner_text, content);
+ title = findViewById(R.id.title);
+ message = (TextView) content.getChildAt(0);
+ }
+
+ public void setTitle(String title) {
+ this.title.setText(title);
+ }
+
+ public void setMessage(String message) {
+ this.message.setText(message);
+ }
+}
diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/PicturePreviewActivity.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/PicturePreviewActivity.java
index 0426be27..4770fdca 100644
--- a/demo/src/main/java/com/otaliastudios/cameraview/demo/PicturePreviewActivity.java
+++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/PicturePreviewActivity.java
@@ -12,26 +12,9 @@ import com.otaliastudios.cameraview.CameraUtils;
import java.lang.ref.WeakReference;
-import butterknife.BindView;
-import butterknife.ButterKnife;
public class PicturePreviewActivity extends Activity {
- @BindView(R.id.image)
- ImageView imageView;
-
- @BindView(R.id.nativeCaptureResolution)
- TextView nativeCaptureResolution;
-
- @BindView(R.id.actualResolution)
- TextView actualResolution;
-
- @BindView(R.id.approxUncompressedSize)
- TextView approxUncompressedSize;
-
- @BindView(R.id.captureLatency)
- TextView captureLatency;
-
private static WeakReference image;
public static void setImage(@Nullable byte[] im) {
@@ -42,7 +25,11 @@ public class PicturePreviewActivity extends Activity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_picture_preview);
- ButterKnife.bind(this);
+ final ImageView imageView = findViewById(R.id.image);
+ final MessageView nativeCaptureResolution = findViewById(R.id.nativeCaptureResolution);
+ final MessageView actualResolution = findViewById(R.id.actualResolution);
+ final MessageView approxUncompressedSize = findViewById(R.id.approxUncompressedSize);
+ final MessageView captureLatency = findViewById(R.id.captureLatency);
final long delay = getIntent().getLongExtra("delay", 0);
final int nativeWidth = getIntent().getIntExtra("nativeWidth", 0);
@@ -57,14 +44,21 @@ public class PicturePreviewActivity extends Activity {
@Override
public void onBitmapReady(Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
- approxUncompressedSize.setText(getApproximateFileMegabytes(bitmap) + "MB");
- captureLatency.setText(delay + " milliseconds");
+
+ approxUncompressedSize.setTitle("Approx. uncompressed size");
+ approxUncompressedSize.setMessage(getApproximateFileMegabytes(bitmap) + "MB");
+
+ captureLatency.setTitle("Capture latency");
+ captureLatency.setMessage(delay + " milliseconds");
// ncr and ar might be different when cropOutput is true.
AspectRatio nativeRatio = AspectRatio.of(nativeWidth, nativeHeight);
AspectRatio finalRatio = AspectRatio.of(bitmap.getWidth(), bitmap.getHeight());
- nativeCaptureResolution.setText(nativeWidth + "x" + nativeHeight + " (" + nativeRatio + ")");
- actualResolution.setText(bitmap.getWidth() + "x" + bitmap.getHeight() + " (" + finalRatio + ")");
+ nativeCaptureResolution.setTitle("Native capture resolution");
+ nativeCaptureResolution.setMessage(nativeWidth + "x" + nativeHeight + " (" + nativeRatio + ")");
+
+ actualResolution.setTitle("Actual resolution");
+ actualResolution.setMessage(bitmap.getWidth() + "x" + bitmap.getHeight() + " (" + finalRatio + ")");
}
});
diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/VideoPreviewActivity.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/VideoPreviewActivity.java
index 23bfced9..59a870d9 100644
--- a/demo/src/main/java/com/otaliastudios/cameraview/demo/VideoPreviewActivity.java
+++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/VideoPreviewActivity.java
@@ -5,28 +5,29 @@ import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
+import android.view.View;
import android.view.ViewGroup;
import android.widget.MediaController;
import android.widget.TextView;
import android.widget.VideoView;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import butterknife.OnClick;
public class VideoPreviewActivity extends Activity {
- @BindView(R.id.video)
- VideoView videoView;
-
- @BindView(R.id.actualResolution)
- TextView actualResolution;
+ private VideoView videoView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_preview);
- ButterKnife.bind(this);
+ videoView = findViewById(R.id.video);
+ videoView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ playVideo();
+ }
+ });
+ final MessageView actualResolution = findViewById(R.id.actualResolution);
Uri videoUri = getIntent().getParcelableExtra("video");
MediaController controller = new MediaController(this);
@@ -38,7 +39,8 @@ public class VideoPreviewActivity extends Activity {
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
- actualResolution.setText(mp.getVideoWidth() + " x " + mp.getVideoHeight());
+ actualResolution.setTitle("Actual resolution");
+ actualResolution.setMessage(mp.getVideoWidth() + " x " + mp.getVideoHeight());
ViewGroup.LayoutParams lp = videoView.getLayoutParams();
float videoWidth = mp.getVideoWidth();
float videoHeight = mp.getVideoHeight();
@@ -50,8 +52,6 @@ public class VideoPreviewActivity extends Activity {
});
}
-
- @OnClick(R.id.video)
void playVideo() {
if (videoView.isPlaying()) return;
videoView.start();
diff --git a/demo/src/main/res/drawable/background.xml b/demo/src/main/res/drawable/background.xml
index 548d368c..19bc1308 100644
--- a/demo/src/main/res/drawable/background.xml
+++ b/demo/src/main/res/drawable/background.xml
@@ -1,6 +1,6 @@
-
-
-
-
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/drawable/ic_flash.xml b/demo/src/main/res/drawable/ic_edit.xml
similarity index 57%
rename from demo/src/main/res/drawable/ic_flash.xml
rename to demo/src/main/res/drawable/ic_edit.xml
index e9364686..35a774a5 100644
--- a/demo/src/main/res/drawable/ic_flash.xml
+++ b/demo/src/main/res/drawable/ic_edit.xml
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
+ android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
diff --git a/demo/src/main/res/layout/activity_camera.xml b/demo/src/main/res/layout/activity_camera.xml
new file mode 100644
index 00000000..fdc520ff
--- /dev/null
+++ b/demo/src/main/res/layout/activity_camera.xml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/src/main/res/layout/activity_main.xml b/demo/src/main/res/layout/activity_main.xml
deleted file mode 100644
index e6588043..00000000
--- a/demo/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,555 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/demo/src/main/res/layout/activity_picture_preview.xml b/demo/src/main/res/layout/activity_picture_preview.xml
index 21b0f228..2411758d 100644
--- a/demo/src/main/res/layout/activity_picture_preview.xml
+++ b/demo/src/main/res/layout/activity_picture_preview.xml
@@ -3,180 +3,37 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_gravity="center_horizontal"
+ android:adjustViewBounds="true" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
diff --git a/demo/src/main/res/layout/activity_video_preview.xml b/demo/src/main/res/layout/activity_video_preview.xml
index 68158f7d..db4dd3d7 100644
--- a/demo/src/main/res/layout/activity_video_preview.xml
+++ b/demo/src/main/res/layout/activity_video_preview.xml
@@ -1,9 +1,9 @@
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="wrap_content"/>
diff --git a/demo/src/main/res/layout/control_view.xml b/demo/src/main/res/layout/control_view.xml
new file mode 100644
index 00000000..b3f12f4f
--- /dev/null
+++ b/demo/src/main/res/layout/control_view.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/src/main/res/layout/spinner_text.xml b/demo/src/main/res/layout/spinner_text.xml
new file mode 100644
index 00000000..65ee9a33
--- /dev/null
+++ b/demo/src/main/res/layout/spinner_text.xml
@@ -0,0 +1,8 @@
+
+
diff --git a/demo/src/main/res/values/colors.xml b/demo/src/main/res/values/colors.xml
index 755f50b0..269ab9ab 100644
--- a/demo/src/main/res/values/colors.xml
+++ b/demo/src/main/res/values/colors.xml
@@ -2,5 +2,5 @@
#009966
#00734d
- #65FF2D
+ #57db27
diff --git a/demo/src/main/res/values/styles.xml b/demo/src/main/res/values/styles.xml
index ee8c90f1..d1cf4963 100644
--- a/demo/src/main/res/values/styles.xml
+++ b/demo/src/main/res/values/styles.xml
@@ -8,11 +8,7 @@
- @color/colorAccent
-
-
-
+
+