Appareil photo Android android.hardware.Camera obsolète

97

si android.hardware.Cameraest obsolète et que vous ne pouvez pas utiliser la variable Camera, quelle serait l'alternative à cela?

raja121
la source
1
J'ai eu ce problème avec une application et j'ai trouvé cela très utile. Si vous utilisez l'intention, vous êtes limité. Donc, ce tutoriel explique une alternative: developer.android.com/guide/topics/media/…
Ronaldo Bahia
1
Copie
lcnicolau

Réponses:

103

Documentation API

Selon le guide des développeurs Android pour android.hardware.Camera, ils déclarent:

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 aux appareils photo individuels connectés à un appareil Android. Il remplace la classe Camera obsolète.

Le problème

Lorsque vous consultez cette documentation, vous constaterez que l'implémentation de ces 2 API de caméra est très différente.

Par exemple, activer l'orientation de la caméra android.hardware.camera

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

Contre 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 de code capable de gérer les deux implémentations.

Notez que dans cet exemple de code unique, j'ai déjà dû contourner le fait que l'ancienne API de caméra fonctionne avec des intprimitives pour les ID de caméra tandis que la nouvelle fonctionne avecString objets. Pour cet exemple, j'ai rapidement corrigé cela en utilisant int comme index dans la nouvelle API. Si la caméra renvoyée n'est pas toujours dans le même ordre, cela entraînera déjà des problèmes. Une autre approche consiste à travailler avec des objets String et une représentation String des anciens ID caméra int, ce qui est probablement plus sûr.

Un loin autour

Maintenant, pour contourner cette énorme différence, vous pouvez d'abord implémenter une interface et référencer cette interface dans votre code.

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

Dans la section suivante, j'expliquerai rapidement comment charger l'un ou l'autre.

L'interface englobe 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'ancienne API matérielle 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 l'API appropriée

Maintenant, pour charger votre classe CameraOldou votre CameraNewclasse, vous devrez vérifier le niveau de l'API car il CameraNewn'est disponible qu'à partir du niveau 21 de l'API .

Si vous avez déjà configuré l'injection de dépendances, vous pouvez le faire dans votre module lors de la fourniture de l' CameraSupportimplémentation. 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 le bon. La partie importante est que le niveau d'API est vérifié.

Communauté
la source
25
Que faire si je dois prendre en charge le niveau d'API Android inférieur à 21?
niveuseverto
1
@Angelius peut-être que cette documentation serait utile à developer.android.com/guide/topics/media/camera.html - mais cela pourrait être une question distincte, ou rechercher des questions sur l'utilisation de variables obsolètes.
@Angelius voici quelques informations sur @SuppressWarningsdans ce QA stackoverflow.com/questions/7397996
5
Je ne pense pas seulement à utiliser des classes @deprecated, mais comment créer une application avec une compatibilité descendante? une aide officielle à ce sujet? J'ai une idée à ce sujet: l'interface ICamera, qui est sauvegardée avec l'objet Camera correspondant à la version actuelle du téléphone, mais c'est un peu simple et difficile à maintenir ...
niveuseverto
@Angelius ce que vous décrivez pourrait être une question distincte (vérifiez si elle a été posée auparavant).
5

Face au même problème , prendre en charge les appareils plus anciens via l'API de caméra obsolète et avoir besoin de la nouvelle API Camera2 pour les appareils actuels et pour l'avenir; J'ai rencontré les mêmes problèmes - et je n'ai pas trouvé de 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 de la POO .

Les 2 API sont nettement 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. J'ai de l'amour pour Google, mais ragnabbit! c'est frustrant.

J'ai donc créé une interface se concentrant uniquement sur la fonctionnalité de la caméra dont mon application a besoin et créé un wrapper simple pour les deux API qui implémente cette interface. De cette façon, mon activité de caméra n'a pas à se soucier de la plate-forme sur laquelle elle s'exécute ...

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

La même interface est utilisée par les deux classes de wrapper , donc peu importe si l'application s'exécute sur Jellybean ou Marshmallow - tant que l'interface fournit à mon application ce dont elle a besoin de l'une ou l'autre API Camera, 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 plus récentes et plus anciennes d'Android.

Le Singleton peut également faire certaines choses liées non liées aux API - comme détecter qu'il y a effectivement une caméra sur l'appareil et enregistrer dans la bibliothèque multimédia.

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

Robert Sherman
la source
Par exemple: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(); } }Puis une méthode pour le retourner ...
Robert Sherman
apparemment aucun saut de ligne n'est autorisé dans les commentaires ;-) mais ça marche vraiment.
Robert Sherman
4
pourquoi ne pas ajouter les codes dans les commentaires directement dans la réponse?
Angel Koh
@RobertSherman Salut Robert, pouvez-vous s'il vous plaît m'aider à réécrire ce tout petit extrait pour le nouveau camera2? Je suis vraiment confus ... J'ai juste besoin de la enableAutofocusméthode pour ouvrir la caméra et définir son objectif: stackoverflow.com/questions/19076316/…
0

Maintenant, nous devons utiliser android.hardware.camera2 car android.hardware.Camera est obsolète et ne fonctionnera que sur 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
la source
0

Les réponses fournies ici selon lesquelles l'API d'appareil photo à utiliser sont incorrectes. Ou mieux dire qu'ils sont insuffisants.

Certains téléphones (par exemple le Samsung Galaxy S6) peuvent être au-dessus du niveau 21 de l'API mais peuvent ne pas 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 de Camera2Api a une méthode pour lire les caractéristiques de la caméra. Vous devez vérifier si le périphérique matériel prend en charge Camera2 Api ou non.

Mais il y a plus de problèmes à gérer si vous voulez vraiment le faire fonctionner pour une application sérieuse: comme, l'option de 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 ou le téléphone peut renvoyer un invalide 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 et si cela échoue également, vous pouvez appeler Android pour ouvrir la caméra par défaut pour vous.

Oguz Ozcan
la source
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
la source