Skip to content

Instantly share code, notes, and snippets.

@colmex
Created August 26, 2015 23:18
Show Gist options
  • Save colmex/1bd19dd2cfc400b2f870 to your computer and use it in GitHub Desktop.
Save colmex/1bd19dd2cfc400b2f870 to your computer and use it in GitHub Desktop.
package me.dontenvy.videotest;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.os.Bundle;
import android.os.HandlerThread;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.os.Handler;
import android.widget.RelativeLayout;
import java.util.Arrays;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class CameraView extends Fragment{
private TextureView myTextureView = null;
private RelativeLayout myRelativeLayout = null;
private String myCameraId = null;
private CameraDevice myCameraDevice = null;
private CameraCaptureSession myCameraCaptureSession = null;
private CaptureRequest.Builder myPreviewRequestBuilder;
private CaptureRequest myPreviewRequest;
private Handler myBackgroundHandler = null;
private HandlerThread myBackgroundThread = null;
private Semaphore myCameraOpenCloseLock =new Semaphore(1);
private final TextureView.SurfaceTextureListener mySurfaceTextureListener =
new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
openCamera();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
private final CameraDevice.StateCallback myStateCallBack = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
myCameraOpenCloseLock.release();
myCameraDevice = camera;
createCameraPreviewSession();
}
@Override
public void onDisconnected(CameraDevice camera) {
myCameraOpenCloseLock.release();
camera.close();
myCameraDevice = null;
}
@Override
public void onError(CameraDevice camera, int error) {
myCameraOpenCloseLock.release();
camera.close();
myCameraDevice = null;
Activity activity = getActivity();
if(activity != null){
activity.finish();
}
}
};
/**
* Camera state: Showing camera preview.
*/
private static final int STATE_PREVIEW = 0;
/**
* Camera state: Waiting for the focus to be locked.
*/
private static final int STATE_WAITING_LOCK = 1;
/**
* Camera state: Waiting for the exposure to be precapture state.
*/
private static final int STATE_WAITING_PRECAPTURE = 2;
/**
* Camera state: Waiting for the exposure state to be something other than precapture.
*/
private static final int STATE_WAITING_NON_PRECAPTURE = 3;
/**
* Camera state: Picture was taken.
*/
private static final int STATE_PICTURE_TAKEN = 4;
private int myState = STATE_PREVIEW;
private CameraCaptureSession.CaptureCallback myCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
};
public static CameraView newInstance(){
CameraView cameraView = new CameraView();
cameraView.setRetainInstance(true);
return cameraView;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_camera_preview, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
myTextureView = (TextureView) view.findViewById(R.id.texture);
myRelativeLayout = (RelativeLayout) view.findViewById(R.id.slide_menu);
}
@Override
public void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}
@Override
public void onResume() {
super.onResume();
startBackgroundThread();
if(myTextureView.isAvailable()){
openCamera();
}else{
myTextureView.setSurfaceTextureListener(mySurfaceTextureListener);
}
}
private void openCamera(){
setUpCameraOutputs();
Activity activity = getActivity();
CameraManager cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try{
if(!myCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)){
throw new RuntimeException("Time Out Waiting For Camera Opening");
}
cameraManager.openCamera(myCameraId,myStateCallBack, myBackgroundHandler);
}catch(CameraAccessException e){
e.printStackTrace();
}catch(InterruptedException e){
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
private void closeCamera(){
try {
myCameraOpenCloseLock.acquire();
if (null != myCameraCaptureSession) {
myCameraCaptureSession.close();
myCameraCaptureSession = null;
}
if (null != myCameraDevice) {
myCameraDevice.close();
myCameraDevice = null;
}
/**if (null != mImageReader) {
mImageReader.close();
mImageReader = null;
}*/
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
myCameraOpenCloseLock.release();
}
}
private void setUpCameraOutputs(){
Activity activity = getActivity();
CameraManager cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try{
for (String cameraId : cameraManager.getCameraIdList()){
CameraCharacteristics cameraCharacteristics =
cameraManager.getCameraCharacteristics(cameraId);
if(cameraCharacteristics.get(CameraCharacteristics.LENS_FACING)
== CameraCharacteristics.LENS_FACING_FRONT){
continue;
}
myCameraId = cameraId;
return;
}
}catch(CameraAccessException e){
e.printStackTrace();
}
}
private void createCameraPreviewSession(){
try{
SurfaceTexture surfaceTexture = myTextureView.getSurfaceTexture();
Surface surface = new Surface(surfaceTexture);
myPreviewRequestBuilder
= myCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
myPreviewRequestBuilder.addTarget(surface);
myCameraDevice.createCaptureSession(Arrays.asList(surface),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
if (null == myCameraDevice) {
return;
}
myCameraCaptureSession = session;
try{
myPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
myPreviewRequest = myPreviewRequestBuilder.build();
myCameraCaptureSession.setRepeatingRequest(myPreviewRequest,
myCaptureCallback, myBackgroundHandler);
}catch (CameraAccessException e){
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
},null
);
}catch (CameraAccessException e){
e.printStackTrace();
}
}
private void startBackgroundThread(){
myBackgroundThread = new HandlerThread("CameraBackground");
myBackgroundThread.start();
myBackgroundHandler = new Handler(myBackgroundThread.getLooper());
}
private void stopBackgroundThread(){
myBackgroundThread.quitSafely();
try {
myBackgroundThread.join();
myBackgroundThread = null;
myBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package me.dontenvy.videotest;
import android.app.Activity;import android.os.Bundle;
public class MainActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null){
getFragmentManager().beginTransaction().replace(R.id.container, CameraView.newInstance()).commit();
}
}
@Override
public void onBackPressed() {
MainMenu myMainMenu = (MainMenu) findViewById(R.id.main_menu);
if (myMainMenu.isOpen()){
myMainMenu.close();
}else{
super.onBackPressed();
}
}
}
package me.dontenvy.videotest;
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
public class MainMenu extends RelativeLayout {
private final double AUTO_OPEN_SPEED_LIMIT = 800.0;
private int myDraggingState = 0;
private Button myButton = null;
private Button takeImageNavButton = null;
private ViewDragHelper myDragHelper;
private int myDraggingBorder;
private int myVerticalRange;
private boolean myIsOpen; // true = slid up, false = at the bottom
public class DragHelperCallback extends ViewDragHelper.Callback {
@Override
public void onViewDragStateChanged(int state) {
if (state == myDraggingState) { // no change
return;
}
if ((myDraggingState == ViewDragHelper.STATE_DRAGGING || myDraggingState == ViewDragHelper.STATE_SETTLING) &&
state == ViewDragHelper.STATE_IDLE) {
// the view stopped from moving.
if (myDraggingBorder == 0) {
} else if (myDraggingBorder == -myVerticalRange) {
myIsOpen = true;
}
}
if (state == ViewDragHelper.STATE_DRAGGING) {
}
myDraggingState = state;
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
myDraggingBorder = top;
}
@Override
public int getViewVerticalDragRange(View child) {
return myVerticalRange;
}
@Override
public boolean tryCaptureView(View view, int i) {
return (view.getId() == R.id.slide_menu);
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
final int topBound = myVerticalRange;
final int bottomBound = getPaddingBottom();
return Math.max(Math.min(top, bottomBound), -topBound);
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
final float rangeToCheck = -myVerticalRange;
if (myDraggingBorder == 0) {
return;
}
if (myDraggingBorder == rangeToCheck) {
return;
}
boolean settleToOpen = false;
if (yvel > AUTO_OPEN_SPEED_LIMIT) { // speed has priority over position
settleToOpen = false;
} else if (yvel < -AUTO_OPEN_SPEED_LIMIT) {
settleToOpen = true;
} else if (myDraggingBorder > rangeToCheck / 2) {
settleToOpen = false;
} else if (myDraggingBorder < rangeToCheck / 2) {
settleToOpen = true;
}
final int settleDestY = settleToOpen ? -myVerticalRange : 0;
if(myDragHelper.settleCapturedViewAt(0, settleDestY)) {
ViewCompat.postInvalidateOnAnimation(MainMenu.this);
}
}
}
class ButtonArea {
int x;
int y;
int diameter;
public ButtonArea(Button b){
int [] bLocation = new int [2];
b.getLocationOnScreen(bLocation);
x = bLocation[0];
y = bLocation[1];
diameter = b.getMeasuredHeight();
}
public boolean isTarget(MotionEvent event){
boolean inY = (event.getRawY() > y) && (event.getRawY() < (y + diameter));
boolean inX = (event.getRawX() > x) && (event.getRawX() < (x + diameter));
return(inY && inX);
}
}
public MainMenu(Context context, AttributeSet attrs) {
super(context, attrs);
myIsOpen = false;
}
@Override
protected void onFinishInflate() {
myButton = (Button) findViewById(R.id.slide_button);
myDragHelper = ViewDragHelper.create(this, 1.0f, new DragHelperCallback());
takeImageNavButton = (Button) findViewById(R.id.take_image_nav_button);
takeImageNavButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
open();
}
});
myIsOpen = false;
super.onFinishInflate();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
myVerticalRange = (h);
super.onSizeChanged(w, h, oldw, oldh);
}
private boolean isQueenTarget(MotionEvent event) {
int[] queenLocation = new int[2];
myButton.getLocationOnScreen(queenLocation);
int upperLimit = queenLocation[1] + myButton.getMeasuredHeight();
int lowerLimit = queenLocation[1];
int y = (int) event.getRawY();
return (y > lowerLimit && y < upperLimit);
}
private boolean isButtonTarget(MotionEvent event){
ButtonArea takeImageNavButtonArea = new ButtonArea(takeImageNavButton);
if (takeImageNavButtonArea.isTarget(event)){
return true;
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if ((!isButtonTarget(event)) && isQueenTarget(event) && myDragHelper.shouldInterceptTouchEvent(event)) {
return true;
} else {
return false;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if ((!isButtonTarget(event)) && (isQueenTarget(event) || isMoving())) {
myDragHelper.processTouchEvent(event);
return true;
} else {
return super.onTouchEvent(event);
}
}
@Override
public void computeScroll() { // needed for automatic settling.
if (myDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
public boolean isMoving() {
return (myDraggingState == ViewDragHelper.STATE_DRAGGING ||
myDraggingState == ViewDragHelper.STATE_SETTLING);
}
public boolean isOpen() {
return (myVerticalRange == -myDraggingBorder || myIsOpen);
}
public void close(){
myDragHelper.smoothSlideViewTo(findViewById(R.id.slide_menu),0,0);
bringChildToFront(findViewById(R.id.slide_menu));
takeImageNavButton.setEnabled(true);
myIsOpen = false;
}
public void open(){
bringChildToFront(findViewById(R.id.camera_container));
takeImageNavButton.setEnabled(false);
myIsOpen = true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment