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.cannylive;
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.cannylive.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             }
99 
100             @Override
101             public String getErrorString(CameraAccessException e) {
102                 switch (e.getReason()) {
103                     case CameraAccessException.CAMERA_DISABLED:
104                         return mContext.getString(R.string.camera_disabled);
105                     case CameraAccessException.CAMERA_DISCONNECTED:
106                         return mContext.getString(R.string.camera_disconnected);
107                     case CameraAccessException.CAMERA_ERROR:
108                         return mContext.getString(R.string.camera_error);
109                     default:
110                         return mContext.getString(R.string.camera_unknown, e.getReason());
111 
112                 }
113             }
114         };
115 
116         CameraOps.CameraReadyListener cameraReadyListener = new CameraOps.CameraReadyListener() {
117             @Override
118             public void onCameraReady() {
119                 mCameraOps.setUpCamera(mProcessingNormalSurface);
120             }
121         };
122         setOnTouchListener(new View.OnTouchListener() {
123             @Override
124             public boolean onTouch(View v, MotionEvent event) {
125                 return touchScreen(event);
126             }
127         });
128         mCameraOps = new CameraOps(mCameraManager,
129                 errorDisplayer,
130                 cameraReadyListener);
131     }
132 
resume(Activity activity)133     public void resume(Activity activity) {
134         mActivity = activity;
135 
136         String errorMessage = mCameraOps.resume();
137         if (errorMessage != null) {
138             if (mErrorCallback != null) {
139                 mErrorCallback.showError(errorMessage);
140             }
141         } else {
142 
143             Size outputSize = mCameraOps.getBestSize();
144             mProcessor = new ViewfinderProcessor(mRS, outputSize);
145             // Configure the output view - this will fire surfaceChanged
146             setAspectRatio((float) outputSize.getWidth() / outputSize.getHeight());
147             getHolder().setFixedSize(outputSize.getWidth(), outputSize.getHeight());
148         }
149     }
150 
pause()151     public void pause() {
152         mProcessor.close();
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(int mode)167     public void takePicture(int mode) {
168         // Orientation
169         Log.v(TAG,"Taking picture");
170         int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
171         int jpegRotation = Surface.ROTATION_0;
172         switch (rotation) {
173             case 90:
174                 jpegRotation = Surface.ROTATION_0;
175                 break;
176             case 0:
177                 jpegRotation = Surface.ROTATION_90;
178                 break;
179             case 180:
180                 jpegRotation = Surface.ROTATION_270;
181                 break;
182             case 270:
183                 jpegRotation = Surface.ROTATION_180;
184                 break;
185         }
186         String name = "Simple" + System.currentTimeMillis() + ".jpg";
187         mCameraOps.captureStillPicture(jpegRotation, name, mContext, mode);
188     }
189 
190     private CameraCaptureSession.CaptureCallback mPhotoCallback
191             = new CameraCaptureSession.CaptureCallback() {
192 
193         public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
194                                        TotalCaptureResult result) {
195             Log.v(TAG, "onCaptureCompleted " + result.toString());
196         }
197     };
198 
199     float mDownY;
200     long mExposureDown;
201     float mFocusDistDown;
202 
touchScreen(MotionEvent event)203     public boolean touchScreen(MotionEvent event) {
204         if (event.getAction() == MotionEvent.ACTION_DOWN) {
205             mDownY = event.getY();
206             mExposureDown = mCameraOps.getExposure();
207             mFocusDistDown = mCameraOps.getFocusDistance();
208             if (mFocusDistDown == 0.0) {
209                 mFocusDistDown = 0.01f;
210             }
211         }
212         float distanceY = event.getY() - mDownY;
213         float width = getWidth();
214         float height = getHeight();
215 
216         float yDistNorm = distanceY / height;
217 
218         float ACCELERATION_FACTOR = 8;
219         float scaleFactor = (float) Math.pow(2.f, yDistNorm * ACCELERATION_FACTOR);
220 
221         switch (mode) {
222             case MODE_SPEED:
223                 long exp = (long) (mExposureDown * scaleFactor);
224                 exp = Math.min(mCameraOps.getExpMax(), exp);
225                 mCameraOps.setExposure(Math.max(mCameraOps.getExpMin(), exp));
226                 Log.v(TAG, "mExposure =" + mCameraOps.getExposure());
227                 break;
228             case MODE_FOCUS:
229                 float focusDist = mFocusDistDown * scaleFactor;
230                 focusDist = Math.max(0.0f, Math.min(mCameraOps.getFocusMin(), focusDist));
231                 if (focusDist < 0.01) focusDist = 0;
232                 mCameraOps.setFocusDistance(focusDist);
233                 Log.v(TAG, "mFocusDist =" + focusDist);
234                 break;
235             case MODE_ISO:
236                 ACCELERATION_FACTOR = 2;
237                 scaleFactor = (float) Math.pow(2.f, yDistNorm * ACCELERATION_FACTOR);
238                 int iso = (int) (getIso() * scaleFactor);
239                 iso = Math.min(mCameraOps.getIsoMax(), iso);
240                 mCameraOps.setIso(Math.max(mCameraOps.getIsoMin(), iso));
241                 break;
242         }
243 
244         if (mParametersChangedCallback != null) {
245             mParametersChangedCallback.parametersChanged();
246         }
247         mCameraOps.setParameters();
248 
249         return true;
250     }
251 
setMode(byte mode)252     public void setMode(byte mode) {
253         this.mode = mode;
254     }
255 
getMode()256     public byte getMode() {
257         return mode;
258     }
259 
getIso()260     public int getIso() {
261         return mCameraOps.getIso();
262     }
263 
setIso(int iso)264     public void setIso(int iso) {
265         mCameraOps.setIso(iso);
266         if (mParametersChangedCallback != null) {
267             mParametersChangedCallback.parametersChanged();
268         }
269         mCameraOps.setParameters();
270     }
271 
getExposure()272     public long getExposure() {
273         return mCameraOps.getExposure();
274     }
275 
setExposure(long exposure)276     public void setExposure(long exposure) {
277         mCameraOps.setExposure(exposure);
278         if (mParametersChangedCallback != null) {
279             mParametersChangedCallback.parametersChanged();
280         }
281         mCameraOps.setParameters();
282     }
283 
getFocusDist()284     public float getFocusDist() {
285         return mCameraOps.getFocusDistance();
286     }
287 
setFocusInMeters(float dist)288     public void setFocusInMeters(float dist) {
289         float min = mCameraOps.getFocusMin();
290         float d = 10 / (dist + 10 / min);
291         setFocusDist(d);
292     }
293 
setFocusDist(float dist)294     public void setFocusDist(float dist) {
295         mCameraOps.setFocusDistance(dist);
296         mCameraOps.setParameters();
297     }
changeEffectMode()298     public void changeEffectMode() {
299         mProcessor.changeEffectMode();
300     }
getMinFocusDistance()301     public float getMinFocusDistance() {
302         return mCameraOps.getFocusMin();
303     }
304 
setAutofocus(boolean autofocus)305     public void setAutofocus(boolean autofocus) {
306         mCameraOps.setAutoFocus(autofocus);
307         mCameraOps.setParameters();
308     }
309 
isAutoExposure()310     public boolean isAutoExposure() {
311         return mCameraOps.isAutoExposure();
312     }
313 
isAutofocus()314     public boolean isAutofocus() {
315         return mCameraOps.isAutoFocus();
316     }
317 
setAutoExposure(boolean autoExposure)318     public void setAutoExposure(boolean autoExposure) {
319         mCameraOps.setAutoExposure(autoExposure);
320         mCameraOps.setParameters();
321     }
322 
getEffect()323     public int getEffect() {
324         return mProcessor.getMode();
325     }
326 
327 
328     public static interface ErrorCallback {
showError(String errorMessage)329         public void showError(String errorMessage);
330     }
331 
setErrorCallback(ErrorCallback errorCallback)332     public void setErrorCallback(ErrorCallback errorCallback) {
333         mErrorCallback = errorCallback;
334     }
335 
336     public static interface ParametersChangedCallback {
parametersChanged()337         public void parametersChanged();
338     }
339 
setParametersChangedCallback(ParametersChangedCallback parametersChangedCallback)340     public void setParametersChangedCallback(ParametersChangedCallback parametersChangedCallback) {
341         mParametersChangedCallback = parametersChangedCallback;
342     }
343 
getFps()344     float getFps() {
345         if (mProcessor==null) {
346             return 0.0f;
347         }
348         return mProcessor.getmFps();
349     }
350 }
351