1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera.captureintent;
18
19import com.android.camera.app.OrientationManager;
20import com.android.camera.debug.Log;
21import com.android.camera.util.Size;
22
23import android.graphics.Matrix;
24import android.graphics.PointF;
25import android.graphics.RectF;
26
27public class PreviewTransformCalculator {
28    private static final Log.Tag TAG = new Log.Tag("PviewTransfmCal");
29
30    private final OrientationManager mOrientationManager;
31
32    public PreviewTransformCalculator(OrientationManager orientationManager) {
33        mOrientationManager = orientationManager;
34    }
35
36    /**
37     * Build a matrix which can be used when calling setTransform() on a
38     * TextureView.
39     * TODO: write unit test when roboletric is available.
40     *
41     * @param previewViewSize The TextureView current layout size.
42     * @param previewStreamSize The selected preview video stream size.
43     * @return The matrix to transform TextureView.
44     */
45    public Matrix toTransformMatrix(Size previewViewSize, Size previewStreamSize) {
46        RectF previewViewRect =
47                new RectF(0.0f, 0.0f, previewViewSize.width(), previewViewSize.height());
48        PointF previewViewCenter = new PointF(previewViewRect.centerX(), previewViewRect.centerY());
49
50        // If natural orientation is portrait, rotate the buffer dimensions.
51        Size previewBufferSize = previewStreamSize;
52
53        if (mOrientationManager.getDeviceNaturalOrientation() == OrientationManager.DeviceNaturalOrientation.PORTRAIT) {
54            previewBufferSize = new Size(previewStreamSize.height(), previewStreamSize.width());
55        }
56
57        Matrix transformMatrix = new Matrix();
58
59        // Adjust the effective preview rect to the center of the texture view.
60        final RectF PreviewBufferRect =
61                new RectF(0.0f, 0.0f, previewBufferSize.width(), previewBufferSize.height());
62        final PointF previewBufferCenter =
63                new PointF(PreviewBufferRect.centerX(), PreviewBufferRect.centerY());
64
65        final RectF centeredEffectivePreviewRect = new RectF(PreviewBufferRect);
66        centeredEffectivePreviewRect.offset(
67                previewViewCenter.x - previewBufferCenter.x,
68                previewViewCenter.y - previewBufferCenter.y);
69
70        // Undo ScaleToFit.FILL done by the surface
71        transformMatrix.setRectToRect(
72                previewViewRect, centeredEffectivePreviewRect, Matrix.ScaleToFit.FILL);
73
74        // Rotate buffer contents to proper orientation
75        int rotateDegree = mOrientationManager.getDisplayRotation().getDegrees();
76        transformMatrix.postRotate(
77                rotateDegree,
78                previewViewCenter.x, previewViewCenter.y);
79
80        /**
81         * Scale to fit view, cropping the longest dimension.
82         *
83         * surfaceTextureSize is changed with the device orientation. Since
84         * previewStreamSize is always in landscape. To calculate the scale
85         * factor, previewStreamSize needs to be rotated if in portrait.
86         */
87        Size rotatedPreviewSize = previewStreamSize;
88        if (mOrientationManager.isInPortrait()) {
89            rotatedPreviewSize = new Size(previewStreamSize.height(), previewStreamSize.width());
90        }
91        float scale = Math.min(
92                (float) previewViewSize.width() / (float) rotatedPreviewSize.width(),
93                (float) previewViewSize.height() / (float) rotatedPreviewSize.height());
94        transformMatrix.postScale(scale, scale, previewViewCenter.x, previewViewCenter.y);
95
96        RectF scaledPreviewStreamRect = new RectF(
97                0.0f, 0.0f, previewStreamSize.width() * scale, previewStreamSize.height() * scale);
98        PointF scaledPreviewStreamCenter =
99                new PointF(scaledPreviewStreamRect.centerX(), scaledPreviewStreamRect.centerY());
100        transformMatrix.postTranslate(
101                scaledPreviewStreamCenter.x - previewViewCenter.x,
102                scaledPreviewStreamCenter.y - previewViewCenter.y);
103
104        return transformMatrix;
105    }
106}
107