1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.example.rscamera;
18 
19 import android.app.Activity;
20 import android.content.Context;
21 import android.hardware.camera2.CameraAccessException;
22 import android.hardware.camera2.CameraCaptureSession;
23 import android.hardware.camera2.CameraManager;
24 import android.hardware.camera2.CaptureRequest;
25 import android.hardware.camera2.TotalCaptureResult;
26 import android.renderscript.RenderScript;
27 import android.util.AttributeSet;
28 import android.util.Log;
29 import android.util.Size;
30 import android.view.MotionEvent;
31 import android.view.Surface;
32 import android.view.SurfaceHolder;
33 import android.view.View;
34 
35 import com.android.example.rscamera.rscamera.R;
36 
37 import java.util.ArrayList;
38 import java.util.List;
39 
40 /**
41  * Created by hoford on 2/27/15.
42  */
43 public class CameraView extends FixedAspectSurfaceView {
44     private static final String TAG = "CameraPreView";
45 
46     private static final long MICRO_SECOND = 1000;
47     private static final long MILLI_SECOND = MICRO_SECOND * 1000;
48     private static final long ONE_SECOND = MILLI_SECOND * 1000;
49 
50     private Surface mPreviewSurface;
51     ViewfinderProcessor mProcessor;
52     private Surface mProcessingNormalSurface;
53     CameraOps mCameraOps;
54     CameraManager mCameraManager;
55     Activity mActivity;
56     Context mContext;
57     byte mode = 0;
58     public static final byte MODE_NONE = 0;
59     public static final byte MODE_SPEED = 1;
60     public static final byte MODE_FOCUS = 2;
61     public static final byte MODE_ISO = 3;
62     RenderScript mRS;
63     ErrorCallback mErrorCallback;
64     ParametersChangedCallback mParametersChangedCallback;
65 
CameraView(Context context, AttributeSet attrs)66     public CameraView(Context context, AttributeSet attrs) {
67         super(context, attrs);
68         mContext = context;
69 
70         mRS = RenderScript.create(mContext);
71         SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
72             @Override
73             public void surfaceCreated(SurfaceHolder holder) {
74             }
75 
76             @Override
77             public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
78                 mPreviewSurface = holder.getSurface();
79                 setupProcessor();
80             }
81 
82             @Override
83             public void surfaceDestroyed(SurfaceHolder holder) {
84                 mPreviewSurface = null;
85             }
86         };
87         getHolder().addCallback(callback);
88         mCameraManager = (CameraManager) mContext.getSystemService(mContext.CAMERA_SERVICE);
89 
90         CameraOps.ErrorDisplayer errorDisplayer = new CameraOps.ErrorDisplayer() {
91 
92             @Override
93             public void showErrorDialog(String errorMessage) {
94                 Log.v(TAG, "ERROR");
95                 if (mErrorCallback != null) {
96                     mErrorCallback.showError(errorMessage);
97                 }
98                 //MessageDialogFragment.newInstance(errorMessage).show(getFragmentManager(), FRAGMENT_DIALOG);
99             }
100 
101             @Override
102             public String getErrorString(CameraAccessException e) {
103                 switch (e.getReason()) {
104                     case CameraAccessException.CAMERA_DISABLED:
105                         return mContext.getString(R.string.camera_disabled);
106                     case CameraAccessException.CAMERA_DISCONNECTED:
107                         return mContext.getString(R.string.camera_disconnected);
108                     case CameraAccessException.CAMERA_ERROR:
109                         return mContext.getString(R.string.camera_error);
110                     default:
111                         return mContext.getString(R.string.camera_unknown, e.getReason());
112 
113                 }
114             }
115         };
116 
117         CameraOps.CameraReadyListener cameraReadyListener = new CameraOps.CameraReadyListener() {
118             @Override
119             public void onCameraReady() {
120                 mCameraOps.setUpCamera(mProcessingNormalSurface);
121             }
122         };
123         setOnTouchListener(new View.OnTouchListener() {
124             @Override
125             public boolean onTouch(View v, MotionEvent event) {
126                 return touchScreen(event);
127             }
128         });
129         mCameraOps = new CameraOps(mCameraManager,
130                 errorDisplayer,
131                 cameraReadyListener);
132     }
133 
resume(Activity activity)134     public void resume(Activity activity) {
135         mActivity = activity;
136 
137         String errorMessage = mCameraOps.resume();
138         if (errorMessage != null) {
139             if (mErrorCallback != null) {
140                 mErrorCallback.showError(errorMessage);
141             }
142         } else {
143 
144             Size outputSize = mCameraOps.getBestSize();
145             mProcessor = new ViewfinderProcessor(mRS, outputSize);
146             // Configure the output view - this will fire surfaceChanged
147             setAspectRatio((float) outputSize.getWidth() / outputSize.getHeight());
148             getHolder().setFixedSize(outputSize.getWidth(), outputSize.getHeight());
149         }
150     }
151 
pause()152     public void pause() {
153         mCameraOps.pause();
154     }
155 
156     /**
157      * Once camera is open and output surfaces are ready, configure the RS processing
158      * and the camera device inputs/outputs.
159      */
setupProcessor()160     private void setupProcessor() {
161         if (mProcessor == null || mPreviewSurface == null) return;
162         mProcessor.setOutputSurface(mPreviewSurface);
163         mProcessingNormalSurface = mProcessor.getInputSurface();
164         mCameraOps.setSurface(mProcessingNormalSurface);
165     }
166 
takePicture()167     public void takePicture() {
168         // Orientation
169         int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
170         int jpegRotation = Surface.ROTATION_0;
171         switch (rotation) {
172             case 90:
173                 jpegRotation = Surface.ROTATION_0;
174                 break;
175             case 0:
176                 jpegRotation = Surface.ROTATION_90;
177                 break;
178             case 180:
179                 jpegRotation = Surface.ROTATION_270;
180                 break;
181             case 270:
182                 jpegRotation = Surface.ROTATION_180;
183                 break;
184         }
185         String name = "Simple" + System.currentTimeMillis() + ".jpg";
186         mCameraOps.captureStillPicture(jpegRotation, name, mContext.getContentResolver());
187     }
188 
189     private CameraCaptureSession.CaptureCallback mPhotoCallback
190             = new CameraCaptureSession.CaptureCallback() {
191 
192         public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
193                                        TotalCaptureResult result) {
194             Log.v(TAG, "onCaptureCompleted " + result.toString());
195         }
196     };
197 
198     float mDownY;
199     long mExposureDown;
200     float mFocusDistDown;
201 
touchScreen(MotionEvent event)202     public boolean touchScreen(MotionEvent event) {
203         if (event.getAction() == MotionEvent.ACTION_DOWN) {
204             mDownY = event.getY();
205             mExposureDown = mCameraOps.getExposure();
206             mFocusDistDown = mCameraOps.getFocusDistance();
207             if (mFocusDistDown == 0.0) {
208                 mFocusDistDown = 0.01f;
209             }
210         }
211         float distanceY = event.getY() - mDownY;
212         float width = getWidth();
213         float height = getHeight();
214 
215         float yDistNorm = distanceY / height;
216 
217         float ACCELERATION_FACTOR = 8;
218         float scaleFactor = (float) Math.pow(2.f, yDistNorm * ACCELERATION_FACTOR);
219 
220         switch (mode) {
221             case MODE_SPEED:
222                 long exp = (long) (mExposureDown * scaleFactor);
223                 exp = Math.min(mCameraOps.getExpMax(), exp);
224                 mCameraOps.setExposure(Math.max(mCameraOps.getExpMin(), exp));
225                 Log.v(TAG, "mExposure =" + mCameraOps.getExposure());
226                 break;
227             case MODE_FOCUS:
228                 float focusDist = mFocusDistDown * scaleFactor;
229                 focusDist = Math.max(0.0f, Math.min(mCameraOps.getFocusMin(), focusDist));
230                 if (focusDist < 0.01) focusDist = 0;
231                 mCameraOps.setFocusDistance(focusDist);
232                 Log.v(TAG, "mFocusDist =" + focusDist);
233                 break;
234             case MODE_ISO:
235                 ACCELERATION_FACTOR = 2;
236                 scaleFactor = (float) Math.pow(2.f, yDistNorm * ACCELERATION_FACTOR);
237                 int iso = (int) (getIso() * scaleFactor);
238                 iso = Math.min(mCameraOps.getIsoMax(), iso);
239                 mCameraOps.setIso(Math.max(mCameraOps.getIsoMin(), iso));
240                 break;
241         }
242 
243         if (mParametersChangedCallback != null) {
244             mParametersChangedCallback.parametersChanged();
245         }
246         mCameraOps.setParameters();
247 
248         return true;
249     }
250 
setMode(byte mode)251     public void setMode(byte mode) {
252         this.mode = mode;
253     }
254 
getMode()255     public byte getMode() {
256         return mode;
257     }
258 
getIso()259     public int getIso() {
260         return mCameraOps.getIso();
261     }
262 
setIso(int iso)263     public void setIso(int iso) {
264         mCameraOps.setIso(iso);
265         if (mParametersChangedCallback != null) {
266             mParametersChangedCallback.parametersChanged();
267         }
268         mCameraOps.setParameters();
269     }
270 
getExposure()271     public long getExposure() {
272         return mCameraOps.getExposure();
273     }
274 
setExposure(long exposure)275     public void setExposure(long exposure) {
276         mCameraOps.setExposure(exposure);
277         if (mParametersChangedCallback != null) {
278             mParametersChangedCallback.parametersChanged();
279         }
280         mCameraOps.setParameters();
281     }
282 
getFocusDist()283     public float getFocusDist() {
284         return mCameraOps.getFocusDistance();
285     }
286 
setFocusInMeters(float dist)287     public void setFocusInMeters(float dist) {
288         float min = mCameraOps.getFocusMin();
289         float d = 10 / (dist + 10 / min);
290         setFocusDist(d);
291     }
292 
setFocusDist(float dist)293     public void setFocusDist(float dist) {
294         mCameraOps.setFocusDistance(dist);
295         mCameraOps.setParameters();
296     }
297 
getMinFocusDistance()298     public float getMinFocusDistance() {
299         return mCameraOps.getFocusMin();
300     }
301 
setAutofocus(boolean autofocus)302     public void setAutofocus(boolean autofocus) {
303         mCameraOps.setAutoFocus(autofocus);
304         mCameraOps.setParameters();
305     }
306 
isAutoExposure()307     public boolean isAutoExposure() {
308         return mCameraOps.isAutoExposure();
309     }
310 
isAutofocus()311     public boolean isAutofocus() {
312         return mCameraOps.isAutoFocus();
313     }
314 
setAutoExposure(boolean autoExposure)315     public void setAutoExposure(boolean autoExposure) {
316         mCameraOps.setAutoExposure(autoExposure);
317         mCameraOps.setParameters();
318     }
319 
320     public static interface ErrorCallback {
showError(String errorMessage)321         public void showError(String errorMessage);
322     }
323 
setErrorCallback(ErrorCallback errorCallback)324     public void setErrorCallback(ErrorCallback errorCallback) {
325         mErrorCallback = errorCallback;
326     }
327 
328     public static interface ParametersChangedCallback {
parametersChanged()329         public void parametersChanged();
330     }
331 
setParametersChangedCallback(ParametersChangedCallback parametersChangedCallback)332     public void setParametersChangedCallback(ParametersChangedCallback parametersChangedCallback) {
333         mParametersChangedCallback = parametersChangedCallback;
334     }
335 
getFps()336     float getFps() {
337         return mProcessor.getmFps();
338     }
339 }
340