Câmera Android android.hardware.Camera obsoleta

97

se android.hardware.Camerafor obsoleto e você não puder usar a variável Camera, qual seria a alternativa para isso?

raja121
fonte
1
Eu tive esse problema com um aplicativo e achei isso muito útil. Se você usar a intenção, estará limitado. Portanto, este tutorial explica uma alternativa: developer.android.com/guide/topics/media/…
Ronaldo Bahia

Respostas:

102

Documentação API

De acordo com o guia do desenvolvedor Android para android.hardware.Camera, eles afirmam:

Recomendamos o uso da nova API android.hardware.camera2 para novos aplicativos.

Na página de informações sobre android.hardware.camera2, ( link acima), é indicado:

O pacote android.hardware.camera2 fornece uma interface para dispositivos de câmera individuais conectados a um dispositivo Android. Ele substitui a classe obsoleta Camera.

O problema

Ao verificar essa documentação, você descobrirá que a implementação dessas 2 APIs de câmera são muito diferentes.

Por exemplo, obter orientação da câmera em 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;
    }
}

Isso torna difícil mudar de um para outro e escrever código que possa lidar com ambas as implementações.

Observe que neste único exemplo de código eu já tive que contornar o fato de que a API de câmera olde funciona com intprimitivas para IDs de câmera enquanto a nova funciona com Stringobjetos. Para este exemplo, resolvi rapidamente isso usando o int como um índice na nova API. Se as câmeras devolvidas não estiverem sempre na mesma ordem, isso já causará problemas. Uma abordagem alternativa é trabalhar com objetos String e representação String dos antigos cameraIDs int, o que provavelmente é mais seguro.

Um por perto

Agora, para contornar essa enorme diferença, você pode implementar uma interface primeiro e fazer referência a essa interface em seu código.

Aqui vou listar alguns códigos para essa interface e as 2 implementações. Você pode limitar a implementação ao que você realmente usa da API da câmera para limitar a quantidade de trabalho.

Na próxima seção, explicarei rapidamente como carregar um ou outro.

A interface envolve tudo que você precisa, para limitar este exemplo, tenho apenas 2 métodos aqui.

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

Agora tem uma aula para a API de hardware de câmera antiga:

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

E outro para a nova 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;
        }
    }
}

Carregando a API adequada

Agora, para carregar sua classe CameraOldou, CameraNewvocê terá que verificar o nível da API, pois CameraNewestá disponível apenas a partir do nível 21 da API.

Se você já tiver a injeção de dependência configurada, poderá fazê-lo em seu módulo ao fornecer a CameraSupportimplementação. Exemplo:

@Module public class CameraModule {

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

Se você não usa DI, pode apenas fazer um utilitário ou usar o padrão de fábrica para criar o apropriado. Parte importante é que o nível da API é verificado.

Comunidade
fonte
25
E se eu precisar de suporte para nível de API do Android inferior a 21?
niveuseverto
1
@Angelius talvez esta documentação seja de ajuda para developer.android.com/guide/topics/media/camera.html - mas isso poderia ser uma questão separada, ou procure por questões sobre ter que usar variáveis ​​obsoletas.
@Angelius aqui estão algumas informações sobre @SuppressWarningsneste controle de qualidade stackoverflow.com/questions/7397996/…
5
Estou pensando não apenas em usar classes @deprecated, mas em como fazer um aplicativo com compatibilidade retroativa? alguma ajuda oficial sobre isso? Eu tenho uma ideia sobre isso: interface ICamera, que é apoiada com o objeto Camera correspondente na versão atual do telefone, mas isso é um pouco direto e difícil de manter ...
niveuseverto
@Angelius, o que você está descrevendo pode ser uma pergunta separada (verifique primeiro se já foi feita).
5

Enfrentando o mesmo problema , suportando dispositivos mais antigos por meio da API de câmera obsoleta e precisando da nova API Camera2 para os dispositivos atuais e para o futuro; Eu tive os mesmos problemas - e não encontrei uma biblioteca de terceiros que faça a ponte entre as 2 APIs, provavelmente porque elas são muito diferentes, mudei para os princípios OOP básicos .

As 2 APIs são marcadamente diferentes, tornando seu intercâmbio problemático para objetos clientes que esperam as interfaces apresentadas na API antiga. A nova API possui objetos diferentes com métodos diferentes, construídos usando uma arquitetura diferente. Adorei o Google, mas ragnabbit! isso é frustrante.

Então, criei uma interface focando apenas na funcionalidade de câmera de que meu aplicativo precisa e criei um wrapper simples para ambas as APIs que implementam essa interface. Dessa forma, minha atividade de câmera não precisa se preocupar com a plataforma em que está sendo executada ...

Também configurei um Singleton para gerenciar a (s) API (s); instanciar o wrapper da API mais antiga com minha interface para dispositivos Android OS mais antigos e a classe de wrapper da nova API para dispositivos mais novos que usam a nova API. O singleton tem um código típico para obter o nível de API e, em seguida, instancia o objeto correto.

A mesma interface é usada por ambas as classes de wrapper , portanto, não importa se o aplicativo é executado em Jellybean ou Marshmallow - contanto que a interface forneça ao meu aplicativo o que ele precisa de qualquer API de câmera, usando as mesmas assinaturas de método; a câmera funciona no aplicativo da mesma maneira para as versões mais recentes e mais antigas do Android.

O Singleton também pode fazer algumas coisas relacionadas não vinculadas às APIs - como detectar se realmente há uma câmera no dispositivo e salvar na biblioteca de mídia.

Espero que a ideia ajude você.

Robert Sherman
fonte
Por exemplo: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(); } }Em seguida, um método para devolvê-lo ...
Robert Sherman
aparentemente nenhuma quebra de linha é permitida nos comentários ;-) mas realmente funciona.
Robert Sherman
4
por que não anexar os códigos aos comentários diretamente na resposta?
Angel Koh de
@RobertSherman Oi Robert, Você pode me ajudar a reescrever este pequeno trecho para o novo camera2? Estou muito confuso ... Eu só preciso do enableAutofocusmétodo para abrir a câmera e definir seu foco: stackoverflow.com/questions/19076316/…
0

Agora temos que usar android.hardware.camera2, pois android.hardware.Camera está obsoleto, o que só funcionará na 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
fonte
0

As respostas fornecidas aqui como qual câmera api usar estão erradas. Ou melhor, são insuficientes.

Alguns telefones (por exemplo, Samsung Galaxy S6) podem estar acima do nível 21 da API, mas ainda podem não oferecer suporte à 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;
}

A classe CameraManager em Camera2Api tem um método para ler as características da câmera. Você deve verificar se o dispositivo inteligente de hardware é compatível com Camera2 Api ou não.

Mas há mais problemas a serem resolvidos se você realmente quiser fazer funcionar para um aplicativo sério: Por exemplo, a opção de flash automático pode não funcionar para alguns dispositivos ou o nível da bateria do telefone pode criar um RuntimeException na câmera ou no telefone pode retornar um inválido id da câmera e etc.

Portanto, a melhor abordagem é ter um mecanismo de fallback, pois por algum motivo o Camera2 falha ao iniciar, você pode tentar o Camera1 e, se isso também falhar, você pode fazer uma chamada para o Android para abrir a câmera padrão para você.

Oguz Ozcan
fonte
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
fonte