web-dev-qa-db-fra.com

Android caméra Android.hardware.Camera obsolète

si Android.hardware.Camera est obsolète et que vous ne pouvez pas utiliser la variable Camera, quelle serait alors la solution de rechange?

89
raja121

Documentation API

Selon le Guide du développeur Android pour Android.hardware.Camera, ils indiquent:

Nous vous recommandons d'utiliser la nouvelle API Android.hardware.camera2 pour les nouvelles applications.

Sur la page d'informations sur Android.hardware.camera2, (lien ci-dessus), il est indiqué:

Le package Android.hardware.camera2 fournit une interface à chaque appareil photo connecté à un appareil Android. Il remplace la classe Camera obsolète.

Le problème

Lorsque vous consultez cette documentation, vous constaterez que la mise en œuvre de ces 2 API de caméra est très différente.

Par exemple, obtenir l'orientation de la caméra sur 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;
    }
}

Cela rend difficile le passage de l'un à l'autre et l'écriture d'un code capable de gérer les deux implémentations.

Notez que dans cet exemple de code unique, je devais déjà contourner le fait que l'ancienne API de caméra fonctionnait avec les primitives int pour les identificateurs de caméra, tandis que la nouvelle fonctionnait avec les objets String . Pour cet exemple, j'ai rapidement résolu le problème en utilisant int comme index dans la nouvelle API. Si les appareils photo renvoyés ne sont pas toujours dans le même ordre, cela causera déjà des problèmes. Une autre approche consiste à travailler avec des objets String et une représentation String de l’ancien ID cameraID, ce qui est probablement plus sûr.

Un loin autour

Maintenant, pour contourner cette énorme différence, vous pouvez d’abord mettre en place une interface et référencer cette interface dans votre code.

Ici, je vais lister du code pour cette interface et les 2 implémentations. Vous pouvez limiter l'implémentation à ce que vous utilisez réellement de l'API de caméra pour limiter la quantité de travail.

Dans la section suivante, je vais expliquer rapidement comment charger l'un ou l'autre.

L'interface englobant tout ce dont vous avez besoin, pour limiter cet exemple, je n'ai que 2 méthodes ici.

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

Maintenant, ayez une classe pour l'ancien api matériel de la caméra:

@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;
    }
}

Et un autre pour la nouvelle api matérielle:

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;
        }
    }
}

Chargement de la bonne API

Maintenant, pour charger votre classe CameraOld ou CameraNew, vous devrez vérifier le niveau de l’API car CameraNew n’est disponible qu’à partir du niveau 21 de l’API.

Si vous avez déjà configuré l'injection de dépendance, vous pouvez le faire dans votre module en fournissant l'implémentation CameraSupport. Exemple:

@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 vous n'utilisez pas DI, vous pouvez simplement créer un utilitaire ou utiliser le modèle Factory pour créer celui qui convient. Une partie importante est que le niveau de l'API est vérifié.

95
user4469467

confronté au même problème, prenant en charge des appareils plus anciens via l’API de caméra obsolète et nécessitant la nouvelle API Camera2 pour les deux appareils actuels et évoluant vers l’avenir; J'ai rencontré les mêmes problèmes - et n'ai pas trouvé une bibliothèque tierce qui relie les 2 API, probablement parce qu'elles sont très différentes Je me suis tourné vers les principes de base OOP .

Les 2 API sont très différentes, ce qui rend leur échange problématique pour les objets clients qui attendent les interfaces présentées dans l'ancienne API. La nouvelle API a différents objets avec différentes méthodes, construits en utilisant une architecture différente. Vous avez l'amour pour Google, mais ragnabbit! c'est frustrant.

J'ai donc créé une interface centrée uniquement sur les fonctionnalités de la caméra dont mon application a besoin et créé un simple wrapper pour les deux API qui implémentent cette interface. De cette façon, mon activité caméra ne doit pas se soucier de la plate-forme sur laquelle elle tourne ...

J'ai également mis en place un Singleton pour gérer les API; instancier l'ancien wrapper de l'API avec mon interface pour les anciens appareils Android OS, et la classe d'emballage de la nouvelle API pour les nouveaux périphériques utilisant la nouvelle API. Le singleton a un code typique pour obtenir le niveau de l'API, puis instance le bon objet.

La même interface est utilisée par les deux classes de wrapper , de sorte que l'application ne fonctionne pas sur Jellybean ou Marshmallow - tant que l'interface fournit mon application avec ce dont elle a besoin de l'une ou l'autre des API de caméra, en utilisant les mêmes signatures de méthode; la caméra fonctionne dans l'application de la même manière pour les versions les plus récentes et les plus anciennes d'Android.

Singleton peut également effectuer certaines tâches connexes non liées aux API - par exemple, détecter un appareil photo sur le périphérique et les enregistrer dans la bibliothèque multimédia.

J'espère que l'idée vous aide.

6
Robert Sherman

Nous devons maintenant utiliser Android.hardware.camera2 car Android.hardware.Camera est obsolète et ne fonctionnera que sur les 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;
                    }


            }
        });
    }
}

Les réponses fournies ici en tant qu'API de caméra à utiliser sont incorrectes. Ou mieux dire qu'ils sont insuffisants.

Certains téléphones (par exemple, le Samsung Galaxy S6) peuvent dépasser le niveau 21 de l’API, mais ne pas toujours prendre en charge l’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 classe CameraManager dans Camera2Api a une méthode pour lire les caractéristiques de la caméra. Vous devez vérifier si le périphérique informatique prend en charge Camera2 Api ou non.

Toutefois, si vous voulez vraiment que cela fonctionne avec une application sérieuse, vous devez gérer plus de problèmes: l'option Flash automatique peut ne pas fonctionner pour certains appareils ou le niveau de la batterie du téléphone peut créer une exception RuntimeException sur l'appareil photo. identifiant de la caméra et etc.

La meilleure approche est donc d’avoir un mécanisme de secours, car pour une raison quelconque, Camera2 ne démarre pas, vous pouvez essayer Camera1. Si cela échoue, vous pouvez également appeler Android pour ouvrir l’appareil photo par défaut.

0
Oguz Ozcan