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
17package com.android.example.rscamera;
18
19import android.app.Activity;
20import android.content.Context;
21import android.hardware.camera2.CameraAccessException;
22import android.hardware.camera2.CameraCaptureSession;
23import android.hardware.camera2.CameraManager;
24import android.hardware.camera2.CaptureRequest;
25import android.hardware.camera2.TotalCaptureResult;
26import android.renderscript.RenderScript;
27import android.util.AttributeSet;
28import android.util.Log;
29import android.util.Size;
30import android.view.MotionEvent;
31import android.view.Surface;
32import android.view.SurfaceHolder;
33import android.view.View;
34
35import com.android.example.rscamera.rscamera.R;
36
37import java.util.ArrayList;
38import java.util.List;
39
40/**
41 * Created by hoford on 2/27/15.
42 */
43public 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
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
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
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     */
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
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
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
251    public void setMode(byte mode) {
252        this.mode = mode;
253    }
254
255    public byte getMode() {
256        return mode;
257    }
258
259    public int getIso() {
260        return mCameraOps.getIso();
261    }
262
263    public void setIso(int iso) {
264        mCameraOps.setIso(iso);
265        if (mParametersChangedCallback != null) {
266            mParametersChangedCallback.parametersChanged();
267        }
268        mCameraOps.setParameters();
269    }
270
271    public long getExposure() {
272        return mCameraOps.getExposure();
273    }
274
275    public void setExposure(long exposure) {
276        mCameraOps.setExposure(exposure);
277        if (mParametersChangedCallback != null) {
278            mParametersChangedCallback.parametersChanged();
279        }
280        mCameraOps.setParameters();
281    }
282
283    public float getFocusDist() {
284        return mCameraOps.getFocusDistance();
285    }
286
287    public void setFocusInMeters(float dist) {
288        float min = mCameraOps.getFocusMin();
289        float d = 10 / (dist + 10 / min);
290        setFocusDist(d);
291    }
292
293    public void setFocusDist(float dist) {
294        mCameraOps.setFocusDistance(dist);
295        mCameraOps.setParameters();
296    }
297
298    public float getMinFocusDistance() {
299        return mCameraOps.getFocusMin();
300    }
301
302    public void setAutofocus(boolean autofocus) {
303        mCameraOps.setAutoFocus(autofocus);
304        mCameraOps.setParameters();
305    }
306
307    public boolean isAutoExposure() {
308        return mCameraOps.isAutoExposure();
309    }
310
311    public boolean isAutofocus() {
312        return mCameraOps.isAutoFocus();
313    }
314
315    public void setAutoExposure(boolean autoExposure) {
316        mCameraOps.setAutoExposure(autoExposure);
317        mCameraOps.setParameters();
318    }
319
320    public static interface ErrorCallback {
321        public void showError(String errorMessage);
322    }
323
324    public void setErrorCallback(ErrorCallback errorCallback) {
325        mErrorCallback = errorCallback;
326    }
327
328    public static interface ParametersChangedCallback {
329        public void parametersChanged();
330    }
331
332    public void setParametersChangedCallback(ParametersChangedCallback parametersChangedCallback) {
333        mParametersChangedCallback = parametersChangedCallback;
334    }
335
336    float getFps() {
337        return mProcessor.getmFps();
338    }
339}
340