studio programacion herramientas fundamentos con avanzado aplicaciones android android-camera android-hardware

programacion - manual de android en pdf



Cámara Android android.hardware.Camera en desuso (4)

Documentación API

Según la guía de desarrolladores de Android para android.hardware.Camera , afirman:

Recomendamos utilizar la nueva API android.hardware.camera2 para nuevas aplicaciones.

En la página de información sobre android.hardware.camera2 , (vinculada anteriormente), se indica:

El paquete android.hardware.camera2 proporciona una interfaz para dispositivos de cámara individuales conectados a un dispositivo Android. Reemplaza la clase de cámara obsoleta.

El problema

Cuando revise esa documentación, encontrará que la implementación de estas 2 API de cámara es muy diferente.

Por ejemplo, obtener orientación de la cámara en android.hardware.camera

@Override public int getOrientation(final int cameraId) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(cameraId, info); return info.orientation; }

Versus android.hardware.camera2

@Override public int getOrientation(final int cameraId) { try { CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); String[] cameraIds = manager.getCameraIdList(); CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraIds[cameraId]); return characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); } catch (CameraAccessException e) { // TODO handle error properly or pass it on return 0; } }

Esto hace que sea difícil cambiar de uno a otro y escribir código que pueda manejar ambas implementaciones.

Tenga en cuenta que en este ejemplo de código único ya tuve que evitar el hecho de que la API de cámara antigua funciona con primitivas int para ID de cámara, mientras que la nueva funciona con objetos String . Para este ejemplo, lo arreglé rápidamente usando el int como índice en la nueva API. Si la cámara devuelta no siempre está en el mismo orden, esto ya causará problemas. El enfoque alternativo es trabajar con objetos String y la representación String de los viejos int cameraIDs, lo que probablemente sea más seguro.

Uno alrededor

Ahora, para evitar esta gran diferencia, primero puede implementar una interfaz y hacer referencia a esa interfaz en su código.

Aquí enumeraré un código para esa interfaz y las 2 implementaciones. Puede limitar la implementación a lo que realmente usa de la API de la cámara para limitar la cantidad de trabajo.

En la siguiente sección, explicaré rápidamente cómo cargar uno u otro.

La interfaz envuelve todo lo que necesita, para limitar este ejemplo, solo tengo 2 métodos aquí.

public interface CameraSupport { CameraSupport open(int cameraId); int getOrientation(int cameraId); }

Ahora tenga una clase para la antigua API de hardware de la cámara:

@SuppressWarnings("deprecation") public class CameraOld implements CameraSupport { private Camera camera; @Override public CameraSupport open(final int cameraId) { this.camera = Camera.open(cameraId); return this; } @Override public int getOrientation(final int cameraId) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(cameraId, info); return info.orientation; } }

Y otro para la nueva API de hardware:

public class CameraNew implements CameraSupport { private CameraDevice camera; private CameraManager manager; public CameraNew(final Context context) { this.manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); } @Override public CameraSupport open(final int cameraId) { try { String[] cameraIds = manager.getCameraIdList(); manager.openCamera(cameraIds[cameraId], new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { CameraNew.this.camera = camera; } @Override public void onDisconnected(CameraDevice camera) { CameraNew.this.camera = camera; // TODO handle } @Override public void onError(CameraDevice camera, int error) { CameraNew.this.camera = camera; // TODO handle } }, null); } catch (Exception e) { // TODO handle } return this; } @Override public int getOrientation(final int cameraId) { try { String[] cameraIds = manager.getCameraIdList(); CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraIds[cameraId]); return characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); } catch (CameraAccessException e) { // TODO handle return 0; } } }

Cargando la API adecuada

Ahora para cargar su clase CameraOld o CameraNew , tendrá que verificar el nivel de API ya que CameraNew solo está disponible desde el nivel 21 de la API.

Si ya tiene configurada la inyección de dependencia, puede hacerlo en su módulo al proporcionar la implementación de CameraSupport . Ejemplo:

@Module public class CameraModule { @Provides CameraSupport provideCameraSupport(){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return new CameraNew(context); } else { return new CameraOld(); } } }

Si no usa DI, simplemente puede hacer una utilidad o usar el patrón Factory para crear el apropiado. Parte importante es que el nivel API está marcado.

si android.hardware.Camera está en desuso y no puede usar la Camera variable, ¿cuál sería la alternativa a esto?


Las respuestas proporcionadas aquí como qué cámara api usar están mal. O mejor decir que son insuficientes.

Algunos teléfonos (por ejemplo, Samsung Galaxy S6) podrían estar por encima del nivel 21 de la API, pero aún así podrían no ser compatibles con la API de Camera2.

CameraCharacteristics mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId); Integer level = mCameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); if (level == null || level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) { return false; }

La clase CameraManager en Camera2Api tiene un método para leer las características de la cámara. Debe verificar si el dispositivo inteligente es compatible con Camera2 Api o no.

Pero hay más problemas que manejar si realmente desea que funcione para una aplicación seria: por ejemplo, la opción de flash automático puede no funcionar para algunos dispositivos o el nivel de batería del teléfono podría crear una RuntimeException en la cámara o el teléfono podría devolver un valor no válido identificación de la cámara y etc.

Entonces, el mejor enfoque es tener un mecanismo alternativo, ya que por alguna razón Camera2 no se inicia, puede probar Camera1 y si esto falla también, puede llamar a Android para abrir la cámara predeterminada por usted.


Ahora tenemos que usar android.hardware.camera2 como android.hardware.Camera está en desuso, lo que solo funcionará en API> 23 FlashLight

public class MainActivity extends AppCompatActivity { Button button; Boolean light=true; CameraDevice cameraDevice; private CameraManager cameraManager; private CameraCharacteristics cameraCharacteristics; String cameraId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button=(Button)findViewById(R.id.button); cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { cameraId = cameraManager.getCameraIdList()[0]; } catch (CameraAccessException e) { e.printStackTrace(); } button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(light){ try { cameraManager.setTorchMode(cameraId,true); } catch (CameraAccessException e) { e.printStackTrace(); } light=false;} else { try { cameraManager.setTorchMode(cameraId,false); } catch (CameraAccessException e) { e.printStackTrace(); } light=true; } } }); } }


Enfrentado con el mismo problema , admitiendo dispositivos más antiguos a través de la API de cámara obsoleta y necesitando la nueva API de Camera2 para ambos dispositivos actuales y avanzando hacia el futuro; Me encontré con los mismos problemas, y no he encontrado una biblioteca de terceros que conecte las 2 API, probablemente porque son muy diferentes, recurrí a los directores básicos de OOP .

Las 2 API son marcadamente diferentes, lo que hace que su intercambio sea problemático para los objetos del cliente que esperan las interfaces presentadas en la antigua API. La nueva API tiene diferentes objetos con diferentes métodos, construidos usando una arquitectura diferente. ¡Tengo amor por Google, pero ragnabbit! Eso es frustrante.

Así que creé una interfaz centrada solo en la funcionalidad de la cámara que necesita mi aplicación, y creé un contenedor simple para ambas API que implementa esa interfaz. De esa manera, mi actividad de cámara no tiene que preocuparse sobre en qué plataforma se está ejecutando ...

También configuré un Singleton para administrar las API; Instalar el contenedor de API más antiguo con mi interfaz para dispositivos Android OS más antiguos y la nueva clase de contenedor de API para dispositivos más nuevos que utilizan la nueva API. El singleton tiene un código típico para obtener el nivel de API y luego instancia el objeto correcto.

Ambas clases de contenedor usan la misma interfaz , por lo que no importa si la aplicación se ejecuta en Jellybean o Marshmallow, siempre que la interfaz proporcione a mi aplicación lo que necesita de la API de la cámara, utilizando las mismas firmas de método; la cámara se ejecuta en la aplicación de la misma manera para las versiones más nuevas y más antiguas de Android.

Singleton también puede hacer algunas cosas relacionadas que no están vinculadas a las API, como detectar que efectivamente hay una cámara en el dispositivo y guardarlas en la biblioteca de medios.

Espero que la idea te ayude.