]> Pileus Git - ~andy/freeotp/blob - src/org/fedorahosted/freeotp/CameraDialogFragment.java
Enable support for non-continuous autofocus
[~andy/freeotp] / src / org / fedorahosted / freeotp / CameraDialogFragment.java
1 /*
2  * FreeOTP
3  *
4  * Authors: Nathaniel McCallum <npmccallum@redhat.com>
5  *
6  * Copyright (C) 2013  Nathaniel McCallum, Red Hat
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 package org.fedorahosted.freeotp;
22
23 import java.util.List;
24
25 import android.annotation.TargetApi;
26 import android.app.AlertDialog;
27 import android.app.Dialog;
28 import android.content.DialogInterface;
29 import android.hardware.Camera;
30 import android.hardware.Camera.CameraInfo;
31 import android.hardware.Camera.Parameters;
32 import android.os.Bundle;
33 import android.os.Handler;
34 import android.os.Message;
35 import android.view.Surface;
36 import android.view.SurfaceHolder;
37 import android.view.SurfaceView;
38 import android.view.View;
39 import android.widget.TextView;
40
41 public class CameraDialogFragment extends BaseAlertDialogFragment
42                         implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
43         public static final String FRAGMENT_TAG = "fragment_camera";
44
45         private final CameraInfo mCameraInfo = new CameraInfo();
46         private final DecodeAsyncTask mDecodeAsyncTask;
47         private final int mCameraId;
48         private Handler mHandler;
49         private Camera mCamera;
50
51         public CameraDialogFragment() {
52                 super(R.string.scan_qr_code, R.layout.camera,
53                         android.R.string.cancel, R.string.manual_entry, 0);
54
55                 // Find a back-facing camera
56                 int cameraId;
57                 for (cameraId = Camera.getNumberOfCameras() - 1; cameraId >= 0; cameraId--) {
58                         Camera.getCameraInfo(cameraId, mCameraInfo);
59                         if (mCameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
60                                 break;
61                 }
62                 mCameraId = cameraId;
63
64                 // Create the decoder thread
65                 mDecodeAsyncTask = new DecodeAsyncTask() {
66                         @Override
67                         protected void onPostExecute(String result) {
68                                 super.onPostExecute(result);
69                                 if (result != null)
70                                         ((MainActivity) getActivity()).tokenURIReceived(result);
71                                 dismiss();
72                         }
73                 };
74         }
75
76         @Override
77         public void onCreate(Bundle savedInstanceState) {
78                 super.onCreate(savedInstanceState);
79
80                 // If we have no back facing camera, open the manual dialog
81                 if (mCameraId < 0) {
82                         new ManualDialogFragment().show(getFragmentManager(),
83                                         ManualDialogFragment.FRAGMENT_TAG);
84                         dismiss();
85                         return;
86                 }
87
88                 mDecodeAsyncTask.execute();
89         }
90
91         @Override
92         public void onDestroy() {
93                 super.onDestroy();
94                 mDecodeAsyncTask.cancel(true);
95         }
96
97         @Override
98         protected void onViewInflated(View view) {
99                 SurfaceView sv = (SurfaceView) view.findViewById(R.id.camera_surfaceview);
100                 sv.getHolder().addCallback(this);
101         }
102
103         @Override
104         public void onClick(DialogInterface dialog, int which) {
105                 if (which != AlertDialog.BUTTON_NEUTRAL)
106                         return;
107
108                 new ManualDialogFragment().show(getFragmentManager(),
109                                 ManualDialogFragment.FRAGMENT_TAG);
110         }
111
112         @Override
113         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
114                 if (mCamera == null)
115                         return;
116
117                 int rotation = 0;
118                 switch (getActivity().getWindowManager().getDefaultDisplay().getRotation()) {
119                 case Surface.ROTATION_0:
120                         rotation = 0;
121                         break;
122                 case Surface.ROTATION_90:
123                         rotation = 90;
124                         break;
125                 case Surface.ROTATION_180:
126                         rotation = 180;
127                         break;
128                 case Surface.ROTATION_270:
129                         rotation = 270;
130                         break;
131                 }
132
133                 mCamera.setDisplayOrientation((mCameraInfo.orientation - rotation + 360) % 360);
134                 mCamera.startPreview();
135
136                 if (mHandler != null)
137                         mHandler.sendEmptyMessageDelayed(0, 100);
138         }
139
140         @Override
141         @TargetApi(14)
142         public void surfaceCreated(SurfaceHolder holder) {
143                 surfaceDestroyed(holder);
144
145                 try {
146                         // Open the camera
147                         mCamera = Camera.open(mCameraId);
148                         mCamera.setPreviewDisplay(holder);
149                         mCamera.setPreviewCallback(mDecodeAsyncTask);
150                 } catch (Exception e) {
151                         e.printStackTrace();
152                         surfaceDestroyed(holder);
153
154                         // Show error message
155                         Dialog d = getDialog();
156                         SurfaceView sv = (SurfaceView) d.findViewById(R.id.camera_surfaceview);
157                         TextView tv = (TextView) d.findViewById(R.id.camera_textview);
158                         sv.setVisibility(View.INVISIBLE);
159                         tv.setVisibility(View.VISIBLE);
160                         return;
161                 }
162
163                 // Set auto-focus mode
164                 Parameters params = mCamera.getParameters();
165                 List<String> modes = params.getSupportedFocusModes();
166                 if (modes.contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
167                         params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
168                 else if (modes.contains(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
169                         params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
170                 else if (modes.contains(Parameters.FOCUS_MODE_AUTO)) {
171                         params.setFocusMode(Parameters.FOCUS_MODE_AUTO);
172                         mHandler = new Handler() {
173                                 @Override
174                                 public void handleMessage(Message msg) {
175                                         super.handleMessage(msg);
176                                         mCamera.autoFocus(CameraDialogFragment.this);
177                                 }
178                         };
179                 }
180                 mCamera.setParameters(params);
181         }
182
183         @Override
184         public void surfaceDestroyed(SurfaceHolder holder) {
185                 if (mCamera == null)
186                         return;
187
188                 if (mHandler != null) {
189                         mCamera.cancelAutoFocus();
190                         mHandler.removeMessages(0);
191                         mHandler = null;
192                 }
193
194                 mCamera.stopPreview();
195                 mCamera.setPreviewCallback(null);
196                 mCamera.release();
197                 mCamera = null;
198         }
199
200         @Override
201         public void onAutoFocus(boolean success, Camera camera) {
202                 if (mHandler != null)
203                         mHandler.sendEmptyMessageDelayed(0, 1000);
204         }
205 }