Observação:esta página se refere ao pacote Camera2. A menos que seu app exija recursos específicos e de baixo nível do Camera2, recomendamos o uso do CameraX. CameraX e Camera2 oferecem suporte ao Android 5.0 (nível 21 da API) e versões mais recentes.
As câmeras e as visualizações de câmera nem sempre estão na mesma orientação no Android dispositivos.
Uma câmera está em uma posição fixa no dispositivo, mesmo que ele não esteja é um smartphone, tablet ou computador. Quando a orientação do dispositivo muda, o mudanças na orientação da câmera.
Como resultado, os apps de câmera geralmente presumem uma relação fixa entre a orientação do dispositivo e a proporção da visualização da câmera. Quando um smartphone está na orientação retrato, a visualização da câmera é considerada mais alta do que larga. Quando o smartphone (e a câmera) são girados para a orientação paisagem, a visualização da câmera deve ser mais larga do que alta.
Mas essas suposições são desafiadas por novos formatos, como dispositivos dobráveis dispositivos, e modos de exibição, como várias janelas e Várias telas. Os dispositivos dobráveis mudam o tamanho da tela e a proporção sem alterar a orientação. O modo de várias janelas restringe os apps da câmera a uma parte tela, dimensionando a visualização da câmera, independentemente da orientação do dispositivo. O modo de várias telas permite o uso de telas secundárias que talvez não precisa estar na mesma orientação da tela principal.
Orientação da câmera
O Definição de compatibilidade do Android especifica que um sensor de imagem de câmera "PRECISA estar orientado de forma que a distância a dimensão da câmera se alinha à dimensão longa da tela. Ou seja, quando o dispositivo é segurado na orientação paisagem, as câmeras precisam capturar imagens na orientação paisagem. Isso se aplica independentemente da orientação natural do dispositivo, ou seja, se aplica a dispositivos com orientação de paisagem e retrato."
A disposição entre a câmera e a tela maximiza a área de exibição em um app de câmera. Além disso, os sensores de imagem normalmente emitem dados proporções de paisagem, sendo 4:3 a mais comum.

A orientação natural do sensor da câmera é paisagem. Na Figura 1, o sensor da câmera frontal (a câmera apontando na mesma direção que o tela) é girado em 270 graus em relação ao telefone para obedecer à Definição de compatibilidade do Android.
Para expor a rotação do sensor a apps, o
A API camera2 inclui um
SENSOR_ORIENTATION
constante. Na maioria dos smartphones e tablets, o dispositivo informa uma orientação do sensor.
de 270 graus para câmeras frontais e 90 graus (ponto de vista da
parte traseira do dispositivo) para as câmeras traseiras, que alinham a borda longa do
com a borda longa do dispositivo. As câmeras de laptop geralmente informam uma
orientação do sensor de 0 ou 180 graus.
Como os sensores de imagem da câmera geram dados (um buffer de imagem)
orientação natural do sensor (paisagem), é necessário girar o buffer de imagem
número de graus especificado por SENSOR_ORIENTATION
para que a visualização da câmera seja
apareça na posição vertical na orientação natural do dispositivo. Para as câmeras frontais,
a rotação for no sentido anti-horário; para as câmeras traseiras, no sentido horário.
Por exemplo, para a câmera frontal da Figura 1, o buffer de imagem produzida pelo sensor da câmera tem esta aparência:

A imagem deve ser girada em 270 graus no sentido anti-horário para que o orientação corresponde à orientação do dispositivo:

Uma câmera traseira produziria um buffer de imagem com a mesma orientação
do buffer acima, mas SENSOR_ORIENTATION
é de 90 graus. Como resultado, o
buffer é girado 90 graus no sentido horário.
Rotação do dispositivo
A rotação do dispositivo é o número de graus em que um dispositivo é girado em relação à orientação. Por exemplo, um smartphone na orientação paisagem tem um dispositivo rotação de 90 ou 270 graus, dependendo da direção da rotação.
Um buffer de imagem do sensor da câmera precisa ser girado no mesmo número de graus que o rotação do dispositivo (além dos graus de orientação do sensor) para o a visualização da câmera apareça na posição vertical.
Cálculo da orientação
A orientação adequada da visualização da câmera considera o sensor orientação e rotação do dispositivo.
A rotação geral do buffer de imagem do sensor pode ser calculada usando a seguinte fórmula:
rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360
em que sign
é 1
para câmeras frontais e -1
para câmeras traseiras.
Para câmeras frontais, o buffer de imagem é girado no sentido anti-horário (a partir da orientação natural do sensor). Para câmeras traseiras, o buffer de imagem do sensor é girado no sentido horário.
A expressão deviceOrientationDegrees * sign + 360
converte a rotação do dispositivo
de anti-horário para horário para câmeras traseiras (por exemplo,
convertendo 270 graus anti-horário para 90 graus no sentido horário). A operação de módulo
dimensiona o resultado para menos de 360 graus (por exemplo, dimensionar 540
graus de rotação para 180).
Diferentes APIs informam a rotação do dispositivo de maneira diferente:
Display#getRotation()
fornece a rotação no sentido anti-horário do dispositivo (do ponto de vista do usuário). Esse valor é inserido na fórmula acima como está.OrientationEventListener#onOrientationChanged()
retorna a rotação no sentido horário do dispositivo (do ponto de vista do usuário). Negue o valor a ser usado na fórmula acima.
Câmeras frontais

Este é o buffer de imagem produzido pelo sensor da câmera na figura 2:

O buffer precisa ser girado 270 graus no sentido anti-horário para ajustar a orientação do sensor (consulte Orientação da câmera acima):

Em seguida, o buffer é girado mais 90 graus no sentido anti-horário para considerar a rotação do dispositivo, resultando na orientação correta do visualização da câmera na Figura 2:

Aqui está a câmera virada para a direita na orientação paisagem:

Confira o buffer de imagem:

O buffer precisa ser girado em 270 graus no sentido anti-horário para ajustar o sensor orientação:

Depois, o buffer é girado mais 270 graus no sentido anti-horário para considerar a rotação do dispositivo:

Câmeras traseiras
As câmeras traseiras geralmente têm uma orientação do sensor de 90 graus (como vistas na parte de trás do dispositivo). Ao orientar a visualização da câmera, o buffer de imagem do sensor é girado no sentido horário de acordo com a quantidade de rotação (em vez de sentido anti-horário, como as câmeras frontais), e a imagem é girado no sentido anti-horário de acordo com a quantidade de rotação do dispositivo.

Este é o buffer de imagem do sensor da câmera na Figura 4:

O buffer precisa ser girado 90 graus no sentido horário para ajustar o sensor orientação:

Em seguida, o buffer é girado em 270 graus no sentido anti-horário para considerar rotação

Proporção
A proporção da tela muda quando a orientação do dispositivo muda, mas também quando dispositivos dobráveis são dobrados e desdobrados, quando as janelas são redimensionadas em ambientes de várias janelas e quando os apps são abertos em telas secundárias.
O buffer de imagem do sensor da câmera precisa ser orientado e dimensionado para corresponder à orientação e proporção do elemento da interface do visor, já que a interface muda de orientação dinamicamente, com ou sem a mudança de orientação do dispositivo.
Em novos formatos ou em ambientes de várias janelas ou telas, se o app presumir que a visualização da câmera tem a mesma orientação que o dispositivo (retrato ou paisagem), a visualização poderá estar orientada incorretamente, dimensionada incorretamente ou ambas.

Na Figura 5, o aplicativo presumiu por engano que o dispositivo foi girado 90 graus no sentido anti-horário. Por isso, o app girou a visualização na mesma quantidade.

Na Figura 6, o app não ajustou a proporção do buffer de imagem para permitir que ele fosse dimensionado corretamente para caber nas novas dimensões do elemento da interface da visualização da câmera.
Os apps de câmera de orientação fixa geralmente apresentam problemas em dispositivos dobráveis e em outros dispositivos de tela grande, como laptops:

Na Figura 7, a interface do app da câmera está lateralmente porque a orientação do app está restrito ao modo retrato. A imagem do visor está orientada corretamente em relação ao sensor da câmera.
Ajustar modo retrato
Apps de câmera que não são compatíveis com o modo de várias janelas
(resizeableActivity="false"
)
e restringem a orientação
(screenOrientation="portrait"
)
ou screenOrientation="landscape"
)
pode ser colocado no modo retrato embutido em dispositivos de tela grande para orientar corretamente
a visualização da câmera.
Inserir o modo retrato com efeito letterbox (insets) em apps somente retrato na orientação retrato, mesmo que a proporção de exibição seja paisagem. Apps somente paisagem têm efeito letterbox na orientação paisagem, mesmo que a proporção da tela é retrato. A imagem da câmera é girada para se alinhar à interface do app, cortada para corresponder à proporção da visualização da câmera e dimensionada para preencher a visualização.
O modo retrato embutido é acionado quando a proporção do sensor de imagem da câmera e a proporção da atividade principal do aplicativo não correspondem.

Na Figura 8, o app de câmera somente para retrato foi girado para exibir a interface. na tela do laptop. O app tem efeito letterbox devido à diferença na proporção entre o app em modo retrato e a tela no modo paisagem. A câmera imagem de visualização mudou para compensar a rotação da interface do app (devido a o modo retrato inserido), e a imagem foi cortada e dimensionada para se ajustar ao orientação de retrato, reduzindo o campo de visão.
Girar, cortar, dimensionar
O modo retrato inserido é invocado para um app de câmera somente retrato em uma tela com proporção de paisagem:

O app recebe efeito letterbox na orientação retrato:

A imagem da câmera é girada em 90 graus para ajustar a reorientação do app:

A imagem é cortada para a proporção da visualização da câmera e dimensionada para preencher a visualização (o campo de visão é reduzido):

Em dispositivos dobráveis, a orientação do sensor da câmera pode ser retrato enquanto a proporção da tela é paisagem:

Como a visualização da câmera é girada para se ajustar à orientação do sensor, a imagem está devidamente orientada no visor, mas o aplicativo apenas de retrato fica de lado.
O encarte do modo retrato só precisa colocar o app com efeito letterbox na orientação retrato para orientar corretamente o app e a visualização da câmera:

API
A partir do Android 12 (nível 31 da API), os apps também podem controlar explicitamente o encarte de retrato
usando o
SCALER_ROTATE_AND_CROP
do elemento CaptureRequest
.
O valor padrão é
SCALER_ROTATE_AND_CROP_AUTO
,
que permite que o sistema invoque o modo retrato embutido.
SCALER_ROTATE_AND_CROP_90
é o comportamento do modo retrato inserido, conforme descrito acima.
Nem todos os dispositivos oferecem suporte a todos os valores de SCALER_ROTATE_AND_CROP
. Para obter uma lista
de valores suportados, consulte
CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES
CameraX
A biblioteca Jetpack CameraX facilita a criação de um visor da câmera que acomoda a orientação do sensor e a rotação do dispositivo.
O elemento de layout PreviewView
cria uma visualização da câmera, ajustando automaticamente a orientação do sensor,
a rotação do dispositivo e o dimensionamento. O PreviewView
mantém a proporção da
imagem da câmera aplicando o tipo de escala
FILL_CENTER
,
que centraliza a imagem, mas pode cortá-la para corresponder às dimensões
do PreviewView
. Para aplicar a imagem da câmera, defina o tipo de escala como
FIT_CENTER
.
Para saber os princípios básicos da criação de uma visualização da câmera com PreviewView
, consulte
Implementar uma visualização.
Para um exemplo completo de implementação, consulte a
CameraXBasic
no GitHub.
Visor da câmera
Semelhante ao caso de uso da visualização, a biblioteca CameraViewfinder oferece um conjunto de ferramentas para simplificar a criação de uma visualização da câmera. Ele não depende do CameraX Core, então você pode integrá-lo perfeitamente à base de código da Camera2.
Em vez de usar o
Surface
diretamente, use o widget
CameraViewfinder
para mostrar o feed da câmera para a Camera2.
O CameraViewfinder
usa internamente um TextureView
ou SurfaceView
para mostrar o feed da câmera e aplica as transformações necessárias a eles para
mostrar corretamente o visor.
Isso envolve corrigir a proporção, a escala e a rotação.
Para solicitar a superfície do objeto CameraViewfinder
, é necessário
criar uma ViewfinderSurfaceRequest
.
Essa solicitação contém requisitos para a resolução da superfície e as informações do dispositivo da câmera
de CameraCharacteristics
.
Chamar requestSurfaceAsync()
envia a solicitação ao provedor de superfície, que é um TextureView
ou
SurfaceView
e recebe um ListenableFuture
de Surface
.
Ligando para markSurfaceSafeToRelease()
notifica o provedor de superfície de que ela não é necessária e está relacionada
recursos podem ser liberados.
fun startCamera(){ val previewResolution = Size(width, height) val viewfinderSurfaceRequest = ViewfinderSurfaceRequest(previewResolution, characteristics) val surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest) Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> { override fun onSuccess(surface: Surface) { /* create a CaptureSession using this surface as usual */ } override fun onFailure(t: Throwable) { /* something went wrong */} }, ContextCompat.getMainExecutor(context)) }
void startCamera(){ Size previewResolution = new Size(width, height); ViewfinderSurfaceRequest viewfinderSurfaceRequest = new ViewfinderSurfaceRequest(previewResolution, characteristics); ListenableFuture<Surface> surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest); Futures.addCallback(surfaceListenableFuture, new FutureCallback<Surface>() { @Override public void onSuccess(Surface result) { /* create a CaptureSession using this surface as usual */ } @Override public void onFailure(Throwable t) { /* something went wrong */} }, ContextCompat.getMainExecutor(context)); }
SurfaceView
SurfaceView
é uma
abordagem simples para criar uma visualização da câmera se ela não
exigir processamento e não for animada.
SurfaceView
gira automaticamente o buffer de imagem do sensor da câmera para corresponder
a orientação da tela, considerando a orientação do sensor e do dispositivo
a rotação de chaves. No entanto, o buffer de imagem é dimensionado para se ajustar ao SurfaceView
dimensões sem considerar a proporção.
É necessário garantir que a proporção do buffer de imagem corresponda à proporção
do SurfaceView
, o que pode ser feito dimensionando o conteúdo
do SurfaceView
no método
onMeasure()
do componente:
O código-fonte computeRelativeRotation()
está em
Rotação relativa abaixo.)
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val width = MeasureSpec.getSize(widthMeasureSpec) val height = MeasureSpec.getSize(heightMeasureSpec) val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees) if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ val scaleX = if (relativeRotation % 180 == 0) { width.toFloat() / previewWidth } else { width.toFloat() / previewHeight } /* Scale factor required to scale the preview to its original size on the y-axis. */ val scaleY = if (relativeRotation % 180 == 0) { height.toFloat() / previewHeight } else { height.toFloat() / previewWidth } /* Scale factor required to fit the preview to the SurfaceView size. */ val finalScale = min(scaleX, scaleY) setScaleX(1 / scaleX * finalScale) setScaleY(1 / scaleY * finalScale) } setMeasuredDimension(width, height) }
@Override void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees); if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ float scaleX = (relativeRotation % 180 == 0) ? (float) width / previewWidth : (float) width / previewHeight; /* Scale factor required to scale the preview to its original size on the y-axis. */ float scaleY = (relativeRotation % 180 == 0) ? (float) height / previewHeight : (float) height / previewWidth; /* Scale factor required to fit the preview to the SurfaceView size. */ float finalScale = Math.min(scaleX, scaleY); setScaleX(1 / scaleX * finalScale); setScaleY(1 / scaleY * finalScale); } setMeasuredDimension(width, height); }
Para mais detalhes sobre como implementar SurfaceView
como uma visualização da câmera, consulte
Orientação da câmera.
TextureView
TextureView
tem menos desempenho que
SurfaceView
, e mais trabalho, mas TextureView
oferece o máximo
de controle da visualização da câmera.
TextureView
gira o buffer de imagem do sensor com base na orientação do sensor, mas
não processa a rotação do dispositivo ou a redução de visualização.
O dimensionamento e a rotação podem ser codificados
Matrix (link em inglês). Para saber como
dimensionar e girar corretamente um TextureView
, consulte
Suporte a superfícies redimensionáveis no seu app de câmera.
Rotação relativa
A rotação relativa do sensor da câmera é a quantidade de rotação necessária para alinhe a saída do sensor da câmera à orientação do dispositivo.
A rotação relativa é usada por componentes como SurfaceView
e TextureView
para determinar os fatores de escala x e y da imagem de pré-visualização. Ele também é usado para
especificar a rotação do buffer de imagem do sensor.
O
CameraCharacteristics
e
As classes Surface
permitem o cálculo da
rotação relativa do sensor da câmera:
/** * Computes rotation required to transform the camera sensor output orientation to the * device's current orientation in degrees. * * @param characteristics The CameraCharacteristics to query for the sensor orientation. * @param surfaceRotationDegrees The current device orientation as a Surface constant. * @return Relative rotation of the camera sensor output. */ public fun computeRelativeRotation( characteristics: CameraCharacteristics, surfaceRotationDegrees: Int ): Int { val sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!! // Reverse device orientation for back-facing cameras. val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ) 1 else -1 // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360 }
/** * Computes rotation required to transform the camera sensor output orientation to the * device's current orientation in degrees. * * @param characteristics The CameraCharacteristics to query for the sensor orientation. * @param surfaceRotationDegrees The current device orientation as a Surface constant. * @return Relative rotation of the camera sensor output. */ public int computeRelativeRotation( CameraCharacteristics characteristics, int surfaceRotationDegrees ){ Integer sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); // Reverse device orientation for back-facing cameras. int sign = characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ? 1 : -1; // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360; }
Métricas de janela
O tamanho da tela não deve ser usado para determinar as dimensões do visor da câmera. O app da câmera pode estar sendo executado em uma parte da tela, no modo de várias janelas em dispositivos móveis ou no modo livre no ChromeOS.
WindowManager#getCurrentWindowMetrics()
(adicionado no nível 30 da API) retorna o tamanho da janela do aplicativo em vez de
o tamanho da tela. Os métodos da biblioteca WindowManager do Jetpack
WindowMetricsCalculator#computeCurrentWindowMetrics()
e
WindowInfoTracker#currentWindowMetrics()
oferecem suporte semelhante com compatibilidade com versões anteriores até o nível 14 da API.
Rotação de 180 graus
Uma rotação de 180 graus de um dispositivo (por exemplo, de orientação natural para
orientação natural de cabeça para baixo) não aciona o
onConfigurationChanged()
o retorno de chamada. Como resultado, a visualização da câmera pode ficar de cabeça para baixo.
Para detectar uma rotação de 180 graus, implemente um
DisplayListener
e verifique a rotação do dispositivo com uma chamada para
Display#getRotation()
no
callback
onDisplayChanged()
.
Recursos exclusivos
Antes do Android 10, apenas a atividade mais visível em um ambiente de várias
janelas estava no estado RESUMED
. Isso era confuso para os usuários porque
o sistema não forneceu nenhuma indicação de qual atividade foi retomada.
O Android 10 (nível 29 da API) introduziu a retomada múltipla, em que todas as atividades visíveis
estão no estado RESUMED
. Atividades visíveis ainda podem entrar no estado PAUSED
se, por exemplo, uma atividade transparente estiver sobre a atividade ou
a atividade não for focalizável, como no modo picture-in-picture. Consulte
Suporte ao picture-in-picture.
Um aplicativo que usa a câmera, o microfone ou qualquer recurso exclusivo ou
único no nível 29 da API ou mais recente precisa oferecer suporte à retomada múltipla. Por
exemplo, se três atividades retomadas quiserem usar a câmera, apenas uma poderá
acessar esse recurso exclusivo. Cada atividade precisa implementar um callback
onDisconnected()
para ficar ciente do acesso preventivo à câmera por uma atividade
de prioridade mais alta.
Para mais informações, consulte Multi-resume.
Outros recursos
- Para conferir um exemplo de Camera2, consulte o app Camera2Basic no GitHub.
- Para saber mais sobre o caso de uso de visualização do CameraX, consulte Implementar uma visualização.
- Para conferir uma implementação de amostra de visualização da câmera do CameraX, consulte o repositório CameraXBasic no GitHub.
- Para saber mais sobre a visualização da câmera no ChromeOS, consulte Orientações da câmera.
- Para informações sobre o desenvolvimento para dispositivos dobráveis, consulte Saiba mais sobre dispositivos dobráveis.