4 * Authors: Nathaniel McCallum <npmccallum@redhat.com>
6 * Copyright (C) 2013 Nathaniel McCallum, Red Hat
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 package org.fedorahosted.freeotp;
23 import java.util.List;
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;
41 public class CameraDialogFragment extends BaseAlertDialogFragment
42 implements SurfaceHolder.Callback {
43 public static final String FRAGMENT_TAG = "fragment_camera";
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;
51 private static class AutoFocusHandler extends Handler
52 implements Camera.AutoFocusCallback {
53 private final Camera mCamera;
55 public AutoFocusHandler(Camera camera) {
60 public void handleMessage(Message msg) {
61 super.handleMessage(msg);
62 mCamera.autoFocus(this);
66 public void onAutoFocus(boolean success, Camera camera) {
67 sendEmptyMessageDelayed(0, 1000);
71 public CameraDialogFragment() {
72 super(R.string.scan_qr_code, R.layout.camera,
73 android.R.string.cancel, R.string.manual_entry, 0);
75 // Find a back-facing camera, otherwise use the first camera.
77 for (cameraId = Camera.getNumberOfCameras() - 1; cameraId > 0; cameraId--) {
78 Camera.getCameraInfo(cameraId, mCameraInfo);
79 if (mCameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
84 // Create the decoder thread
85 mDecodeAsyncTask = new DecodeAsyncTask() {
87 protected void onPostExecute(String result) {
88 super.onPostExecute(result);
90 ((MainActivity) getActivity()).tokenURIReceived(result);
97 public void onCreate(Bundle savedInstanceState) {
98 super.onCreate(savedInstanceState);
100 // If we have no cameras, open the manual dialog
102 new ManualDialogFragment().show(getFragmentManager(),
103 ManualDialogFragment.FRAGMENT_TAG);
108 mDecodeAsyncTask.execute();
112 public void onDestroy() {
114 mDecodeAsyncTask.cancel(true);
118 protected void onViewInflated(View view) {
119 SurfaceView sv = (SurfaceView) view.findViewById(R.id.camera_surfaceview);
120 sv.getHolder().addCallback(this);
124 public void onClick(DialogInterface dialog, int which) {
125 if (which != AlertDialog.BUTTON_NEUTRAL)
128 new ManualDialogFragment().show(getFragmentManager(),
129 ManualDialogFragment.FRAGMENT_TAG);
133 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
137 // The code in this section comes from the developer docs. See:
138 // http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int)
141 switch (getActivity().getWindowManager().getDefaultDisplay().getRotation()) {
142 case Surface.ROTATION_0:
145 case Surface.ROTATION_90:
148 case Surface.ROTATION_180:
151 case Surface.ROTATION_270:
157 switch (mCameraInfo.facing) {
158 case Camera.CameraInfo.CAMERA_FACING_FRONT:
159 result = (mCameraInfo.orientation + rotation) % 360;
160 result = (360 - result) % 360; // compensate the mirror
163 case Camera.CameraInfo.CAMERA_FACING_BACK:
164 result = (mCameraInfo.orientation - rotation + 360) % 360;
168 mCamera.setDisplayOrientation(result);
169 mCamera.startPreview();
171 if (mHandler != null)
172 mHandler.sendEmptyMessageDelayed(0, 100);
177 public void surfaceCreated(SurfaceHolder holder) {
178 surfaceDestroyed(holder);
182 mCamera = Camera.open(mCameraId);
183 mCamera.setPreviewDisplay(holder);
184 mCamera.setPreviewCallback(mDecodeAsyncTask);
185 } catch (Exception e) {
187 surfaceDestroyed(holder);
189 // Show error message
190 Dialog d = getDialog();
191 SurfaceView sv = (SurfaceView) d.findViewById(R.id.camera_surfaceview);
192 TextView tv = (TextView) d.findViewById(R.id.camera_textview);
193 sv.setVisibility(View.INVISIBLE);
194 tv.setVisibility(View.VISIBLE);
198 // Set auto-focus mode
199 Parameters params = mCamera.getParameters();
200 List<String> modes = params.getSupportedFocusModes();
201 if (modes.contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
202 params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
203 else if (modes.contains(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
204 params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
205 else if (modes.contains(Parameters.FOCUS_MODE_AUTO)) {
206 params.setFocusMode(Parameters.FOCUS_MODE_AUTO);
207 mHandler = new AutoFocusHandler(mCamera);
209 mCamera.setParameters(params);
213 public void surfaceDestroyed(SurfaceHolder holder) {
217 if (mHandler != null) {
218 mCamera.cancelAutoFocus();
219 mHandler.removeMessages(0);
223 mCamera.stopPreview();
224 mCamera.setPreviewCallback(null);