Cámara de Android android.hardware.Camera obsoleta

97

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

raja121
fuente
1
Tuve este problema con una aplicación y lo encontré muy útil. Si usa la intención, está limitado. Así que este tutorial explica una alternativa: developer.android.com/guide/topics/media/…
Ronaldo Bahia

Respuestas:

102

Documentación de API

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

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

En la página de información android.hardware.camera2(enlazada arriba), se indica:

El paquete android.hardware.camera2 proporciona una interfaz para dispositivos de cámara individuales conectados a un dispositivo Android. Reemplaza la clase Camera 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, activar la orientación de la cámara 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 solucionar el hecho de que la API de la cámara antigua funciona con intprimitivas para los ID de cámara, mientras que la nueva funciona con Stringobjetos. Para este ejemplo, lo solucioné rápidamente usando int como índice en la nueva API. Si la cámara se devuelve no siempre en el mismo orden, esto ya causará problemas. El enfoque alternativo es trabajar con objetos String y la representación String de los antiguos ID de cámara int, que probablemente sea más seguro.

Uno de distancia

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

Aquí enumeraré algunos códigos 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 CameraOldo CameraNew, tendrá que verificar el nivel de API, ya CameraNewque solo está disponible desde el nivel 21 de API.

Si ya tiene configurada la inyección de dependencia, puede hacerlo en su módulo cuando proporcione la CameraSupportimplementación. 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, puede crear una utilidad o usar el patrón Factory para crear el adecuado. La parte importante es que se comprueba el nivel de API.

Comunidad
fuente
25
¿Qué sucede si necesito admitir un nivel de API de Android inferior a 21?
niveuseverto
1
@Angelius tal vez esta documentación sea de ayuda para developer.android.com/guide/topics/media/camera.html - pero esa podría ser una pregunta separada, o buscar preguntas sobre tener que usar variables obsoletas.
@Angelius aquí hay información sobre @SuppressWarningseste control de calidad stackoverflow.com/questions/7397996/…
5
Estoy pensando no solo en usar clases @deprecated, sino en cómo hacer una aplicación con compatibilidad con versiones anteriores. alguna ayuda oficial en esto? Tengo una idea sobre esto: interfaz ICamera, que está respaldada con el objeto Camera correspondiente a la versión actual del teléfono, pero esto es un poco sencillo y difícil de mantener ...
niveuseverto
@Angelius, lo que está describiendo podría ser una pregunta separada (verifique primero si se ha preguntado antes).
5

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

Las 2 API son marcadamente diferentes, por lo que intercambiarlas es problemático para los objetos de cliente que esperan las interfaces presentadas en la API anterior. La nueva API tiene diferentes objetos con diferentes métodos, construidos con una arquitectura diferente. Tengo amor por Google, ¡pero ragnabbit! eso es frustrante.

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

También configuré un Singleton para administrar las API; instalando el contenedor de la API anterior con mi interfaz para los dispositivos con sistema operativo Android más antiguos, y la clase de contenedor de la nueva API para los 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 instancias del objeto correcto.

Ambas clases contenedoras utilizan 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étodos; la cámara se ejecuta en la aplicación de la misma manera para las versiones más nuevas y 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 guardar en la biblioteca de medios.

Espero que la idea te ayude.

Robert Sherman
fuente
Por ejemplo:public interface AllCameraInterface { void open(); boolean setDirection(); Bitmap preview(); Bitmap takePhoto(); void close(); }
Robert Sherman
ex: public interface AllCameraInterface { void open(); Bitmap takePhoto(); void close(); etc... } public class NCamera implements AllCameraInterface... public class OCamera implements AllCameraInterface... public class AllCamera { private static AllCamera ourInstance = new AllCamera(); public static AllCamera getInstance() {...} private AllCameraInterface camera; private AllCamera() { if (android.os.Build.VERSION.SDK_INT <= 20) { camera = new OCamera(); } else { camera = new NCamera(); } }Entonces un método para devolverlo ...
Robert Sherman
aparentemente no se permiten saltos de línea en los comentarios ;-) pero realmente funciona.
Robert Sherman
4
¿Por qué no agregar los códigos de los comentarios directamente en la Respuesta?
Angel Koh
@RobertSherman Hola, Robert, ¿podrías ayudarme a reescribir este pequeño fragmento para lo nuevo camera2? Estoy realmente confundido ... Solo necesito el enableAutofocusmétodo para abrir la cámara y establecer su enfoque: stackoverflow.com/questions/19076316/…
0

Ahora tenemos que usar android.hardware.camera2 ya que android.hardware.Camera está en desuso y 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;
                    }


            }
        });
    }
}
abhay rastogi Codeblended
fuente
0

Las respuestas proporcionadas aquí sobre qué api de cámara usar son incorrectas. O mejor dicho, son insuficientes.

Algunos teléfonos (por ejemplo, Samsung Galaxy S6) pueden estar por encima del nivel 21 de la API, pero es posible que aún no sean compatibles con la API 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 de hardware 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 puede crear una RuntimeException en la cámara o el teléfono podría devolver un valor no válido ID de cámara y etc.

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

Oguz Ozcan
fuente
0
 if ( getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {

          CameraManager cameraManager=(CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);


           try {
               String cameraId = cameraManager.getCameraIdList()[0];
               cameraManager.setTorchMode(cameraId,true);
           } catch (CameraAccessException e) {
               e.printStackTrace();
           }


 }
Rohith S
fuente