Android Fundamentos: Crear un Espejo
Spanish (Español) translation by Rodney Martinez (you can also view the original English article)
¡Aprenda como hacer una sencilla aplicación "espejo" en este rápido tutorial!
Uno de los usos inesperados de los teléfonos celulares con sus pantallas brillantes es que las personas comienzan a usarlas como espejos -para revisar su cabello, labios o sólo para asegurarse que no tienen ningún brocoli se ha quedado atrapada entre los dientes. Cuando apareciendo las cámaras en los teléfonos, las personas de inmediato convirtieron los lentes mismos en auto-retratos, incluso si esto significaba retorcer en formas extrañas para conseguir una foto. Los fabricantes de hardware capitalizados en esto para crear una generación nueva de teléfonos inteligentes con dos cámaras: una hacia afuera y otra hacia adentro, la cámara del frente. Este hardware presto todo tipo de aplicaciones prácticas.
Desde la API Nivel 9, el Android SDK ha proporcionado un método para acceder a múltiples cámaras en dispositivos. Y desde entonces, la mayoría de los fabricantes han incluido una cámara en el lado frontal. Esta cámara es, por lo general, utilizada para tomar auto-retratos o para el propósito de chatear en vídeo.
Paso 0: Comenzando
El código abierto para este proyecto puede ser descargado y utilizado de forma local o explorado en línea. De forma alternativa, puede crear su propio proyecto. Este es un proyecto solo de actividad, así que podría añadir la actividad a su propio proyecto. Asumiremos que tiene un proyecto listo para trabajar.
Paso 1: Composición de la Cámara
Una forma normal de presentar la cámara es por medio de crear una composición —la que usted desee— que tenga un control FrameLayout para sostener la vista previa de la cámara. Por lo general, también hay algún tipo de botón para tomar la fotografía. Con eso en mente, aquí está la composición que hemos usado para un modo retrato.
1 |
|
2 |
<?xml version="1.0" encoding="utf-8"?>
|
3 |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
4 |
android:layout_width="match_parent" |
5 |
android:layout_height="match_parent" > |
6 |
<FrameLayout
|
7 |
android:id="@+id/camPreview" |
8 |
android:layout_width="wrap_content" |
9 |
android:layout_height="wrap_content" |
10 |
android:layout_centerHorizontal="true" |
11 |
android:layout_centerVertical="true" > |
12 |
</FrameLayout>
|
13 |
<Button
|
14 |
android:id="@+id/capture" |
15 |
android:layout_width="wrap_content" |
16 |
android:layout_height="wrap_content" |
17 |
android:layout_alignParentBottom="true" |
18 |
android:layout_centerHorizontal="true" |
19 |
android:text="@string/capture" /> |
20 |
</RelativeLayout>
|
La composición horizontal es igual, pero el botón está localizado en la parte lateral.
Paso 2: Iniciando la Cámara
Los dispositivos con cámaras tienen accesos usando la clase Camara (android.hardware.Camera) de Android SDK. Un lugar razonable para configurar e iniciar la cámara es en el método onCreate() de su clase Activity, así:
1 |
|
2 |
private Camera mCam; |
3 |
private MirrorView mCamPreview; |
4 |
private int mCameraId = 0; |
5 |
private FrameLayout mPreviewLayout; |
6 |
|
7 |
@Override
|
8 |
public void onCreate(Bundle savedInstanceState) { |
9 |
super.onCreate(savedInstanceState); |
10 |
setContentView(R.layout.main); |
11 |
|
12 |
mCameraId = findFirstFrontFacingCamera(); |
13 |
|
14 |
mPreviewLayout = (FrameLayout) findViewById(R.id.camPreview); |
15 |
mPreviewLayout.removeAllViews(); |
16 |
|
17 |
startCameraInLayout(mPreviewLayout, mCameraId); |
18 |
|
19 |
}
|
Primero, determinamos cual cámara es la cámara al frente. Ya que API proporciona para la posibilidad de más de una cámara al frente, nosotros usamos la primera. Luego, FrameLayout es cargado y despejado. Solamente queremos la vista previa de la cámara en él. Luego, finalmente, iniciamos la cámara en éste formato.
Ahora vamos a ver a cada uno de éstos métodos auxiliares.
Paso 3: Encontrando una Cámara al Frente
Use el método getNumberOfCameras() del objeto Camera para iterar sobre cada instancia de cámara y extraiga un objeto CameraInfo. Use la casilla opuesta para determinar si la cámara es una CAMERA_FACING_FRONT. Si es así, devuelva este id de cámara, hemos encontrado una cámara opuesta para usar.
1 |
|
2 |
private int findFirstFrontFacingCamera() { |
3 |
int foundId = -1; |
4 |
int numCams = Camera.getNumberOfCameras(); |
5 |
for (int camId = 0; camId < numCams; camId++) { |
6 |
CameraInfo info = new CameraInfo(); |
7 |
Camera.getCameraInfo(camId, info); |
8 |
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { |
9 |
foundId = camId; |
10 |
break; |
11 |
}
|
12 |
}
|
13 |
return foundId; |
14 |
}
|
Paso 4: Iniciando la Cámara Frontal
Después, saque una instancia del objeto Camera con una llamada al método Camera.open() usando el identificador de cámara para la cámara en el frente. Al instanciar un objeto MirrorView usando la cámara abierta y añada el objeto MirrorView al formato.
1 |
|
2 |
private void startCameraInLayout(FrameLayout layout, int cameraId) { |
3 |
mCam = Camera.open(cameraId); |
4 |
if (mCam != null) { |
5 |
mCamPreview = new MirrorView(this, mCam); |
6 |
layout.addView(mCamPreview); |
7 |
}
|
8 |
}
|
Ahora vamos a echar un vistazo a la clase MirrorView.
Paso 5: Creando MirrorView
Para colocar una vista previa en la pantalla para mostrar lo que la cámara está capturando, debemos hacer un nuevo SurfaceView tal que podamos asignar su soporte (SurfaceHolder) para el equipo de la cámara. Esto permite al equipo de la cámara escribir directamente a la cara.
Aquí está la implementación de nuestro MirrorView:
1 |
|
2 |
public class MirrorView extends SurfaceView implements |
3 |
SurfaceHolder.Callback { |
4 |
private SurfaceHolder mHolder; |
5 |
private Camera mCamera; |
6 |
|
7 |
public MirrorView(Context context, Camera camera) { |
8 |
super(context); |
9 |
mCamera = camera; |
10 |
mHolder = getHolder(); |
11 |
mHolder.addCallback(this); |
12 |
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); |
13 |
}
|
14 |
|
15 |
public void surfaceCreated(SurfaceHolder holder) { |
16 |
try { |
17 |
mCamera.setPreviewDisplay(holder); |
18 |
mCamera.startPreview(); |
19 |
} catch (Exception error) { |
20 |
Log.d(DEBUG_TAG, |
21 |
"Error starting mPreviewLayout: " + error.getMessage()); |
22 |
}
|
23 |
}
|
24 |
|
25 |
public void surfaceDestroyed(SurfaceHolder holder) { |
26 |
}
|
27 |
|
28 |
public void surfaceChanged(SurfaceHolder holder, int format, int w, |
29 |
int h) { |
30 |
if (mHolder.getSurface() == null) { |
31 |
return; |
32 |
}
|
33 |
|
34 |
// can't make changes while mPreviewLayout is active
|
35 |
try { |
36 |
mCamera.stopPreview(); |
37 |
} catch (Exception e) { |
38 |
|
39 |
}
|
40 |
|
41 |
try { |
42 |
|
43 |
// start up the mPreviewLayout
|
44 |
mCamera.setPreviewDisplay(mHolder); |
45 |
mCamera.startPreview(); |
46 |
|
47 |
} catch (Exception error) { |
48 |
Log.d(DEBUG_TAG, |
49 |
"Error starting mPreviewLayout: " + error.getMessage()); |
50 |
}
|
51 |
}
|
52 |
}
|
Cuando la cara es creada, en la llamada onSurfaceCreated(), el SurfaceHolder de la cámara que está ajustado en la vista previa está iniciado con una llamada al método startPreview(). Cuando la cara es cambiada, en la llamada a onSurfaceChanged(), entonces la cámara es detenida y reiniciada con el holder actualizado. Para la implementación completa de esta solución, con las declaraciones para DEBUG_TAG y demás, vea el código abierto completo.
Si esto es todo lo que usted hace, entonces la aplicación funcionará. Sin embargo, los resultados no serán los ideales. Es posible que la vista previa salga hacia los lados y la proporción de radio no será la correcta, haciendo que su cara luzca estirada o aplastada. ¡No es bueno!
Paso 6: Ajustando la Orientación de la Cámara y la Proporción de Radio
La orientación de la vista previa de la cámara debe coincidir con la orientación del dispositivo de la pantalla para que todo salga correctamente. De manera adicional, la proporción de radio de la vista previa de la cámara debería coincidir con el tamaño de la vista previa, de otro modo, la imagen aparecerá deformada. Todos estos datos están disponibles, desde las clases Display, CameraInfo y Camera.Parameters. Aquí hemos escrito un método simple que ajusta las características de visualización de SurfaceHolder para arreglar estos problemas:
1 |
|
2 |
public void setCameraDisplayOrientationAndSize() { |
3 |
CameraInfo info = new CameraInfo(); |
4 |
Camera.getCameraInfo(mCameraId, info); |
5 |
int rotation = getWindowManager().getDefaultDisplay().getRotation(); |
6 |
int degrees = rotation * 90; |
7 |
|
8 |
int result; |
9 |
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { |
10 |
result = (info.orientation + degrees) % 360; |
11 |
result = (360 - result) % 360; |
12 |
} else { |
13 |
result = (info.orientation - degrees + 360) % 360; |
14 |
}
|
15 |
mCamera.setDisplayOrientation(result); |
16 |
|
17 |
Camera.Size previewSize = mCam.getParameters().getPreviewSize(); |
18 |
if (result == 90 || result == 270) { |
19 |
mHolder.setFixedSize(previewSize.height, previewSize.width); |
20 |
} else { |
21 |
mHolder.setFixedSize(previewSize.width, previewSize.height); |
22 |
|
23 |
}
|
24 |
}
|
En este punto, el espejo debería de ser completamente funcional.


Paso 7: Mejorando
El objeto Camera debe ser publicado tan pronto como su aplicación esté lista con él. En el caso de la muestra Activity, podemos descargar la cámara en el método onPause() e iniciarlo en onResume(), como este:
1 |
|
2 |
@Override
|
3 |
protected void onResume() { |
4 |
super.onResume(); |
5 |
if (mCam == null && mPreviewLayout != null) { |
6 |
mPreviewLayout.removeAllViews(); |
7 |
startCameraInLayout(mPreviewLayout, mCameraId); |
8 |
}
|
9 |
}
|
10 |
|
11 |
@Override
|
12 |
protected void onPause() { |
13 |
if (mCam != null) { |
14 |
mCam.release(); |
15 |
mCam = null; |
16 |
}
|
17 |
super.onPause(); |
18 |
}
|
En conclusión
Nunca subestime cuántos les encanta a los usuarios sus cámaras frontales. Muchos de los teléfonos inteligentes de última generación tienen está característica, pero sólo algunas aplicaciones toman el benefició de esto, ¡aunque usted debería! Ha aprendido a cómo identificar y usar las cámaras frontales en este tutorial. Además, ha aprendido a ajustar la orientación de la pantalla y la proporción de radio de la sección de vista previa.
¿Ahora puede guardar una foto? (Pista: Descargo el código abierto, ¿cierto?).
Sobre los Autores
Desarrolladores de Celulares; Lauren Darcey y Shane Conder son coautores de varios libros sobre el desarrollo en Android: un libro de programación a fondo titulado: Desarrollo de Aplicaciones Inalámbricas de Android y Sams Aprenda usted mismo a Desarrollar Aplicaciones para Android en 24 horas. Cuando no escriben, ellos pasan su tiempo desarrollando programas para celulares en sus empresas y proporcionando servicios de consultoría. Ellos pueden ser localizado a través de correo electrónico: androidwirelessdev+mt@gmail.com o por medio de su blog en androidbook.blogspot.com y en Twitter @androidwireless.



