124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu/*
224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Copyright (C) 2015 The Android Open Source Project
324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu *
424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Licensed under the Apache License, Version 2.0 (the "License");
524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * you may not use this file except in compliance with the License.
624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * You may obtain a copy of the License at
724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu *
824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu *      http://www.apache.org/licenses/LICENSE-2.0
924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu *
1024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Unless required by applicable law or agreed to in writing, software
1124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * distributed under the License is distributed on an "AS IS" BASIS,
1224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * See the License for the specific language governing permissions and
1424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * limitations under the License.
1524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu */
1624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
1724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hupackage com.android.camera.captureintent;
1824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
1924be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport com.android.camera.app.OrientationManager;
2024be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport com.android.camera.debug.Log;
2124be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport com.android.camera.util.Size;
2224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
2324be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport android.graphics.Matrix;
2424be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport android.graphics.PointF;
2524be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport android.graphics.RectF;
2624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
2724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hupublic class PreviewTransformCalculator {
28de4e5225ea92d681f9f4c005e6285f739635d271Senpo Hu    private static final Log.Tag TAG = new Log.Tag("PviewTransfmCal");
2924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
3024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu    private final OrientationManager mOrientationManager;
3124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
3224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu    public PreviewTransformCalculator(OrientationManager orientationManager) {
3324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        mOrientationManager = orientationManager;
3424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu    }
3524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
3624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu    /**
3724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu     * Build a matrix which can be used when calling setTransform() on a
3824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu     * TextureView.
3924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu     * TODO: write unit test when roboletric is available.
4024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu     *
4124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu     * @param previewViewSize The TextureView current layout size.
4224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu     * @param previewStreamSize The selected preview video stream size.
4324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu     * @return The matrix to transform TextureView.
4424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu     */
4524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu    public Matrix toTransformMatrix(Size previewViewSize, Size previewStreamSize) {
4624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        RectF previewViewRect =
4724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                new RectF(0.0f, 0.0f, previewViewSize.width(), previewViewSize.height());
4824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        PointF previewViewCenter = new PointF(previewViewRect.centerX(), previewViewRect.centerY());
4924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
5024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        // If natural orientation is portrait, rotate the buffer dimensions.
5124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        Size previewBufferSize = previewStreamSize;
5224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
5324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        if (mOrientationManager.getDeviceNaturalOrientation() == OrientationManager.DeviceNaturalOrientation.PORTRAIT) {
5424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu            previewBufferSize = new Size(previewStreamSize.height(), previewStreamSize.width());
5524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        }
5624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
5724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        Matrix transformMatrix = new Matrix();
5824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
5924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        // Adjust the effective preview rect to the center of the texture view.
6024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        final RectF PreviewBufferRect =
6124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                new RectF(0.0f, 0.0f, previewBufferSize.width(), previewBufferSize.height());
6224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        final PointF previewBufferCenter =
6324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                new PointF(PreviewBufferRect.centerX(), PreviewBufferRect.centerY());
6424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
6524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        final RectF centeredEffectivePreviewRect = new RectF(PreviewBufferRect);
6624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        centeredEffectivePreviewRect.offset(
6724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                previewViewCenter.x - previewBufferCenter.x,
6824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                previewViewCenter.y - previewBufferCenter.y);
6924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
7024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        // Undo ScaleToFit.FILL done by the surface
7124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        transformMatrix.setRectToRect(
7224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                previewViewRect, centeredEffectivePreviewRect, Matrix.ScaleToFit.FILL);
7324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
7424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        // Rotate buffer contents to proper orientation
7524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        int rotateDegree = mOrientationManager.getDisplayRotation().getDegrees();
7624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        transformMatrix.postRotate(
7724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                rotateDegree,
7824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                previewViewCenter.x, previewViewCenter.y);
7924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
8024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        /**
8124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu         * Scale to fit view, cropping the longest dimension.
8224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu         *
8324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu         * surfaceTextureSize is changed with the device orientation. Since
8424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu         * previewStreamSize is always in landscape. To calculate the scale
8524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu         * factor, previewStreamSize needs to be rotated if in portrait.
8624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu         */
8724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        Size rotatedPreviewSize = previewStreamSize;
8824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        if (mOrientationManager.isInPortrait()) {
8924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu            rotatedPreviewSize = new Size(previewStreamSize.height(), previewStreamSize.width());
9024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        }
9124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        float scale = Math.min(
9224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                (float) previewViewSize.width() / (float) rotatedPreviewSize.width(),
9324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                (float) previewViewSize.height() / (float) rotatedPreviewSize.height());
9424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        transformMatrix.postScale(scale, scale, previewViewCenter.x, previewViewCenter.y);
9524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
9624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        RectF scaledPreviewStreamRect = new RectF(
9724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                0.0f, 0.0f, previewStreamSize.width() * scale, previewStreamSize.height() * scale);
9824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        PointF scaledPreviewStreamCenter =
9924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                new PointF(scaledPreviewStreamRect.centerX(), scaledPreviewStreamRect.centerY());
10024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        transformMatrix.postTranslate(
10124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                scaledPreviewStreamCenter.x - previewViewCenter.x,
10224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu                scaledPreviewStreamCenter.y - previewViewCenter.y);
10324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu
10424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu        return transformMatrix;
10524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu    }
10624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu}
107