Tutorial+sobre+cámara+en+Android

** CÓDIGO: ** [] La cámara es un dispositivo muy usado en diversas aplicaciones, podemos encontrar aplicaciones que llamar a la aplicación de la cámara por defecto para almacenar, enviar o utilizar la imagen de alguna u otra manera. También podemos encontrar aplicaciones que directamente utilizan la cámara para su propio beneficio sin necesidad de llamar a la aplicación nativa que lleva nuestro dispositivo. Tras investigar un poco por internet y seguir varios tutoriales he decidido que para realmente saber trabajar con la cámara, es conveniente hacer nuestra propia aplicación de cámara. La aplicación será una previsualización de la cámara y un botón para realizar una fotografía. El botón va a ser toda la pantalla con el objetivo de poder realizar la imagen tan solo tocando la pantalla. Posteriormente la aplicación se cerrará. En caso de querer utilizar esta aplicación con algún otro fin se podría llamar y la imagen que es guardada en la galería ser recuperada. Para ello debemos dar permisos de uso de la cámara en nuestro archivo AndroidManifest.xml. mediante: < uses-permission android:name = // "android.permission.CAMERA" // /> NOTA: en caso de no dar este permiso, la aplicación lanzará una excepción al tratar de utilizar la cámara. Las clases que vamos a usar son: Camera, la cual trabaja con el dispositivo hardware de la cámara. Camera.Parameters, clase que recoge características como calidad, flash, etc. SurfaceView, clase que utilizaremos para mostrar un “streaming” de la cámara para realizar la fotografía. A continuación vamos a definir la interfaz de usuario, en el archivo activity_main.xml: Pongo el código para obtener una interfaz igual a la que realicé. <? xml version = // "1.0" // encoding = // "utf-8" // ?> < LinearLayout xmlns:android = // "http://schemas.android.com/apk/res/android" // android:orientation = // "vertical" // android:layout_width = // "fill_parent" // android:layout_height = // "fill_parent" // > < SurfaceView android:id = // "@+id/surface" // android:layout_width = // "fill_parent" // android:layout_height = // "fill_parent" // >   En este fragmento de código he definido un surface, para poder ver en streaming la cámara antes de realizar la fotografía. Con este otro fragmento definimos el botón, lo colocamos en otro fichero .xml para poder posicionarlo encima del surface de forma que ocupe toda la superficie. <? xml version = // "1.0" // encoding = // "utf-8" // ?> < LinearLayout xmlns:android = // "http://schemas.android.com/apk/res/android" // android:layout_width = // "fill_parent" // android:layout_height = // "fill_parent" // android:layout_gravity = // "top" // android:gravity = // "bottom" // android:orientation = // "horizontal" // >
 * Tutorial sobre cámara en Android **

< Button android:id = // "@+id/button" // android:layout_width = // "match_parent" // android:layout_height = // "match_parent" // android:background = // "@android:color/transparent" // android:drawableLeft = // "@drawable/ic_launcher" // />

 Una vez realizada la interfaz de usuario, vamos al fichero .java para definir las actividad. Fui importando mediante Eclipse me recordaba que no había importado lo necesario, los imports fueron los siguientes: ** import ** android.widget.Toast; Ahora voy a ir explicando poco a poco las funcionalidades y actividades, y añadiéndolas una por una. Comenzamos con la declaración de la clase, que debe extender Activity e implementar surfaceHolder.Callback para poder controlar la interfaz de usuario. Las variables que vamos a necesitar son las siguientes: Camera myCamera ; Button takePicture ; He tratado de seguir nombres de variables en inglés lo más descriptivos posibles. El siguiente paso es sobreescribir el método onCreate, el cual queda de la siguiente forma: @Override
 * import ** android.app.Activity;
 * import ** android.content.Intent;
 * import ** android.graphics.Bitmap;
 * import ** android.graphics.BitmapFactory;
 * import ** android.graphics.PixelFormat;
 * import ** android.hardware.Camera;
 * import ** android.hardware.Camera.PictureCallback;
 * import ** android.hardware.Camera.ShutterCallback;
 * import ** android.os.Bundle;
 * import ** android.provider.MediaStore.Images;
 * import ** android.view.LayoutInflater;
 * import ** android.view.SurfaceHolder;
 * import ** android.view.SurfaceView;
 * import ** android.view.View;
 * import ** android.view.Window;
 * import ** android.view.WindowManager;
 * import ** android.view.View.OnClickListener;
 * import ** android.view.ViewGroup.LayoutParams;
 * import ** android.widget.Button;
 * public **** class ** MainActivity ** extends ** Activity ** implements ** SurfaceHolder.Callback{
 * private ** LayoutInflater __ myInflater __ = ** null ** ;
 * byte ** [] tempdata ;
 * boolean ** myPreviewRunning = ** false ** ;
 * private ** SurfaceHolder __ mySurfaceHolder __ ;
 * private ** SurfaceView __ mySurfaceView __ ;
 * public **** void ** onCreate(Bundle savedInstanceState) {
 * super ** .onCreate(savedInstanceState);

getWindow.setFormat(PixelFormat. // TRANSLUCENT // ); requestWindowFeature(Window. // FEATURE_NO_TITLE // ); getWindow.setFlags(WindowManager.LayoutParams. // FLAG_FULLSCREEN //, WindowManager.LayoutParams. // FLAG_FULLSCREEN // );

setContentView(R.layout. // activity_main // ); }  De esta forma hacemos que la ventana cargue en pantalla completa, es decir, que no veamos el título ni la barra de notificaciones. Cargamos el archivo .xml con el SurferView. Ahora vamos a decirle que el surface muestre un streaming de la cámara. mySurfaceView = (SurfaceView) findViewById(R.id. // surface // ); mySurfaceHolder = mySurfaceView .getHolder; mySurfaceHolder .addCallback( ** this ** );

Utilizamos la clase LayoutInflater para superponer dos ficheros xml de interfaz usuario. De esta forma podemos conseguir colocar un botón encima del Surface. myInflater = LayoutInflater.//from//( ** this ** ); View overView = myInflater .inflate(R.layout. // capa_boton //, ** null ** ); Continuamos definiendo la acción del botón, para ello lo hacemos definiendo el método setOnClickListener de nuestro botón llamado takePicture. takePicture = (Button) findViewById(R.id. // button // ); takePicture .setOnClickListener( ** new ** OnClickListener { @Override  myCamera .takePicture(__myShutterCallback__, __myPictureCallback__, __myJpeg__);  }   }); Tan solo queda sobre escribir tres métodos, correspondientes a cada uno de los argumentos de la función takePicture. El primero de ellos es ShutterCallback, utilizado para los efectos de la cámara, como el sonido de lanzar la foto, por ejemplo. ShutterCallback __myShutterCallback__ = ** new ** ShutterCallback { @Override }  };   También necesitamos sobre escribir el método PictureCallback: PictureCallback __myPictureCallback__ = ** new ** PictureCallback { @Override // ** TODO ** Auto-generated method stub } };
 * this ** .addContentView(overView, ** new ** LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
 * public **** void ** onClick(View v) {
 * public **** void ** onShutter {
 * public **** void ** onPictureTaken( ** byte ** [] data, Camera myCamera) {

PictureCallback __myJpeg__ = ** new ** PictureCallback { @Override // ** TODO ** Auto-generated method stub tempdata = data; __ done __ ; } }   };   Con la función local done, almacenaremos la imagen. Para ello usaremos el tipo de dato Bitmap. Bitmap bm = BitmapFactory.//decodeByteArray//( tempdata, 0, tempdata . length ); String url = Images.Media.//insertImage//(getContentResolver, bm, ** null **, ** null ** ); bm.recycle; Bundle bundle = ** new ** Bundle; bundle.putString( "url" ,url); Intent mIntent = ** new ** Intent; mIntent.putExtras(bundle); setResult( // RESULT_OK //, mIntent); } ** else ** { Toast.//makeText//( ** this **, "La imagen no ha podido ser guardada" , Toast. // LENGTH_SHORT // ).show; } finish; }
 * public **** void ** onPictureTaken( ** byte ** [] data, Camera myCamera) {
 * if ** (data != ** null ** ){
 * void ** done{
 * if ** (url != ** null ** ){

Gracias a eclipse podemos ver que nos faltan tres métodos por sobre escribir, al decir que implementamos SurfaceHolder.Callback. Estos son surfaceCreated, constructor del surface; surfaceChanged, invocado cuando el surface es modificado de alguna manera y surfaceDestroyed, para liberar memoria. @Override // ** TODO ** Auto-generated method stub myCamera = Camera.open; } }
 * public **** void ** surfaceCreated(SurfaceHolder holder) {

@Override // ** TODO ** Auto-generated method stub myCamera .stopPreview; myPreviewRunning = ** false ** ; } Camera.Parameters p = myCamera .getParameters; p.setPreviewSize(width,height);
 * public **** void ** surfaceChanged(SurfaceHolder holder, ** int ** format, ** int ** width, ** int ** height) {
 * try ** {
 * if ** ( myPreviewRunning ){

myCamera .setParameters(p); myCamera .setPreviewDisplay(holder); myCamera .startPreview; myPreviewRunning = ** true ** ; } ** catch ** (Exception e){} }

@Override // ** TODO ** Auto-generated method stub myCamera .stopPreview; myPreviewRunning = ** false ** ; myCamera .release; myCamera = ** null ** ; }
 * public **** void ** surfaceDestroyed(SurfaceHolder holder) {

A la hora de utilizarlo en Eclipse hay que tener en cuenta que la virtualización debemos indicar que posee cámara, ya sea una simulada, o la cámara web en caso de poseerla. También es importante dar memoria a la tarjeta SD para poder almacenar las imágenes. Una captura de pantalla de las características del dispositivo virtualizado: La aplicación posee un icono, este mismo icono será la imagen utilizada en el botón. El botón ocupa toda la pantalla para poder hacer click en cualquier lugar y tomar la foto, pero el icono será más pequeño y estará colocado en el centro a la izquierda. El código completo puede consultarse en el repositorio de github: - []