package org.fedorahosted.freeotp;
+import java.util.List;
+
+import android.annotation.TargetApi;
import android.app.AlertDialog;
-import android.content.Context;
+import android.app.Dialog;
import android.content.DialogInterface;
import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
-import android.view.WindowManager;
import android.widget.TextView;
-public class CameraDialogFragment extends BaseAlertDialogFragment implements SurfaceHolder.Callback {
+public class CameraDialogFragment extends BaseAlertDialogFragment
+ implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
public static final String FRAGMENT_TAG = "fragment_camera";
- private DecodeAsyncTask mDecodeAsyncTask;
+ private final CameraInfo mCameraInfo = new CameraInfo();
+ private final DecodeAsyncTask mDecodeAsyncTask;
+ private final int mCameraId;
+ private Handler mHandler;
private Camera mCamera;
public CameraDialogFragment() {
super(R.string.scan_qr_code, R.layout.camera,
android.R.string.cancel, R.string.manual_entry, 0);
+
+ // Find a back-facing camera, otherwise use the first camera.
+ int cameraId;
+ for (cameraId = Camera.getNumberOfCameras() - 1; cameraId > 0; cameraId--) {
+ Camera.getCameraInfo(cameraId, mCameraInfo);
+ if (mCameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
+ break;
+ }
+ mCameraId = cameraId;
+
+ // Create the decoder thread
+ mDecodeAsyncTask = new DecodeAsyncTask() {
+ @Override
+ protected void onPostExecute(String result) {
+ super.onPostExecute(result);
+ if (result != null)
+ ((MainActivity) getActivity()).tokenURIReceived(result);
+ dismiss();
+ }
+ };
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // If we have no cameras, open the manual dialog
+ if (mCameraId < 0) {
+ new ManualDialogFragment().show(getFragmentManager(),
+ ManualDialogFragment.FRAGMENT_TAG);
+ dismiss();
+ return;
+ }
+
+ mDecodeAsyncTask.execute();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mDecodeAsyncTask.cancel(true);
}
@Override
@Override
public void onClick(DialogInterface dialog, int which) {
- if (which == AlertDialog.BUTTON_NEUTRAL) {
- new AddTokenDialog(getActivity()) {
- @Override
- public void addToken(String uri) {
- ((MainActivity) getActivity()).tokenURIReceived(uri);
- }
- }.show();
- }
- }
-
- @Override
- public void onDestroyView() {
- if (mDecodeAsyncTask != null)
- mDecodeAsyncTask.cancel(true);
+ if (which != AlertDialog.BUTTON_NEUTRAL)
+ return;
- super.onDestroyView();
+ new ManualDialogFragment().show(getFragmentManager(),
+ ManualDialogFragment.FRAGMENT_TAG);
}
@Override
if (mCamera == null)
return;
- WindowManager wm = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
- switch (wm.getDefaultDisplay().getRotation()) {
+ // The code in this section comes from the developer docs. See:
+ // http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int)
+
+ int rotation = 0;
+ switch (getActivity().getWindowManager().getDefaultDisplay().getRotation()) {
case Surface.ROTATION_0:
- mCamera.setDisplayOrientation(90);
+ rotation = 0;
+ break;
+ case Surface.ROTATION_90:
+ rotation = 90;
+ break;
+ case Surface.ROTATION_180:
+ rotation = 180;
break;
case Surface.ROTATION_270:
- mCamera.setDisplayOrientation(180);
+ rotation = 270;
+ break;
+ }
+
+ int result = 0;
+ switch (mCameraInfo.facing) {
+ case Camera.CameraInfo.CAMERA_FACING_FRONT:
+ result = (mCameraInfo.orientation + rotation) % 360;
+ result = (360 - result) % 360; // compensate the mirror
+ break;
+
+ case Camera.CameraInfo.CAMERA_FACING_BACK:
+ result = (mCameraInfo.orientation - rotation + 360) % 360;
break;
}
+ mCamera.setDisplayOrientation(result);
mCamera.startPreview();
+
+ if (mHandler != null)
+ mHandler.sendEmptyMessageDelayed(0, 100);
}
@Override
+ @TargetApi(14)
public void surfaceCreated(SurfaceHolder holder) {
+ surfaceDestroyed(holder);
+
try {
- mCamera = Camera.open();
+ // Open the camera
+ mCamera = Camera.open(mCameraId);
mCamera.setPreviewDisplay(holder);
-
- // Create the decoder thread
- mDecodeAsyncTask = new DecodeAsyncTask() {
- @Override
- protected void onPostExecute(String result) {
- super.onPostExecute(result);
- if (result != null)
- ((MainActivity) getActivity()).tokenURIReceived(result);
- mDecodeAsyncTask = null;
- dismiss();
- }
- };
- mDecodeAsyncTask.execute();
mCamera.setPreviewCallback(mDecodeAsyncTask);
-
- // Set auto-focus mode
- Parameters params = mCamera.getParameters();
- params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
- mCamera.setParameters(params);
} catch (Exception e) {
- SurfaceView sv = (SurfaceView) getDialog().findViewById(R.id.camera_surfaceview);
+ e.printStackTrace();
+ surfaceDestroyed(holder);
+
+ // Show error message
+ Dialog d = getDialog();
+ SurfaceView sv = (SurfaceView) d.findViewById(R.id.camera_surfaceview);
+ TextView tv = (TextView) d.findViewById(R.id.camera_textview);
sv.setVisibility(View.INVISIBLE);
- TextView tv = (TextView) getDialog().findViewById(R.id.camera_textview);
tv.setVisibility(View.VISIBLE);
- e.printStackTrace();
+ return;
+ }
+
+ // Set auto-focus mode
+ Parameters params = mCamera.getParameters();
+ List<String> modes = params.getSupportedFocusModes();
+ if (modes.contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
+ params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
+ else if (modes.contains(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
+ params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
+ else if (modes.contains(Parameters.FOCUS_MODE_AUTO)) {
+ params.setFocusMode(Parameters.FOCUS_MODE_AUTO);
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ mCamera.autoFocus(CameraDialogFragment.this);
+ }
+ };
}
+ mCamera.setParameters(params);
}
@Override
if (mCamera == null)
return;
+ if (mHandler != null) {
+ mCamera.cancelAutoFocus();
+ mHandler.removeMessages(0);
+ mHandler = null;
+ }
+
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
+
+ @Override
+ public void onAutoFocus(boolean success, Camera camera) {
+ if (mHandler != null)
+ mHandler.sendEmptyMessageDelayed(0, 1000);
+ }
}