Ну, похоже, я ответила на свой вопрос. Первоначально я начал с ответа из Android предварительного просмотра Camera2, иногда поворачиваемого на 90 градусов . В этом коде есть ошибка. Конкретно масштабирование. С этим и несколькими другими изменениями я смог заставить его работать. В связанном ответе сказано поставить звонок прямо перед тем, как открыть камеру, что я и сделал изначально. Итак, что произойдет, когда система изменит ориентацию с портретной на ландшафтную (или наоборот), система перезапустит действие. Однако, если вы быстро перевернули устройство, чтобы оно по-прежнему находилось в альбомной ориентации, но перевернулось, то изображение, по-видимому, будет повернуто на 180 °, поскольку окончательное вращение все еще в альбомной ориентации, и система не перезапускает действие. Таким образом, размещение кода внутри подпрограммы обратного вызова с измененной поверхностью гарантирует, что код будет вызываться при каждом изменении ориентации, независимо от того, перезапущена ли активность.
Вот пересмотренный код:
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
int rotation = getWindowManager().getDefaultDisplay().getRotation();
if (rotation != prevRotation) {
prevRotation = rotation;
RectF cameraRectF = new RectF(0, 0, imageDimensions.getWidth(), imageDimensions.getHeight());
RectF textureRectF = new RectF(0, 0, textureView.getHeight(), textureView.getWidth());
float centerX = cameraRectF.centerX();
float centerY = cameraRectF.centerY();
if (rotation != Surface.ROTATION_0) {
textureRectF.offset(centerX - textureRectF.centerX(), centerY - textureRectF.centerY());
transformMatrix.setRectToRect(cameraRectF, textureRectF, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) textureRectF.right / cameraRectF.right,
(float) textureRectF.bottom / cameraRectF.bottom);
transformMatrix.postScale(scale, scale, centerX, centerY);
if (rotation != Surface.ROTATION_180) {
int angle = (ORIENTATIONS_REAL.get(rotation) + sensorOrientation +
ORIENTATIONS_SENSOR.get(sensorOrientation)) % 360;
transformMatrix.postRotate(angle, centerX, centerY);
} else {
transformMatrix.postRotate(180, centerX, centerY);
}
} else {
transformMatrix.reset();
}
}
textureView.setTransform(transformMatrix);
}
Мой код также учитывает ориентацию датчика, поэтому он должен работать на любом устройстве. У меня есть три разных устройства, два из которых сообщают, что ориентация датчика составляет 90 °. Третье устройство сообщает, что ориентация датчика равна 0 °. Поэтому, немного поэкспериментировав, я придумал таблицу, которая будет добавлять константу к конечному углу поворота, основываясь на том, что представляет собой угол поворота датчика. Ниже приведены определения для ориентации. ORIENTATIONS_SENSOR является вышеупомянутой таблицей.
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private static final SparseIntArray ORIENTATIONS_REAL = new SparseIntArray();
static {
ORIENTATIONS_REAL.append(Surface.ROTATION_0, 0);
ORIENTATIONS_REAL.append(Surface.ROTATION_90, 90);
ORIENTATIONS_REAL.append(Surface.ROTATION_180, 180);
ORIENTATIONS_REAL.append(Surface.ROTATION_270, 270);
}
private static final SparseIntArray ORIENTATIONS_SENSOR = new SparseIntArray();
static {
ORIENTATIONS_SENSOR.append(0, 180);
ORIENTATIONS_SENSOR.append(90, 90);
ORIENTATIONS_SENSOR.append(180, 0);
ORIENTATIONS_SENSOR.append(270, -90);
}
Хотя я смог проверить только 0 ° и 90 ° от таблицы, я приглашаю других, у кого есть устройства с указанными датчиками ориентации датчика 180 ° и 270 °, проверить что мои расчеты верны.