1a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling/*
2a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling * Copyright (C) 2014 The Android Open Source Project
3a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling *
4a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling * Licensed under the Apache License, Version 2.0 (the "License");
5a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling * you may not use this file except in compliance with the License.
6a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling * You may obtain a copy of the License at
7a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling *
8a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling *      http://www.apache.org/licenses/LICENSE-2.0
9a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling *
10a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling * Unless required by applicable law or agreed to in writing, software
11a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling * distributed under the License is distributed on an "AS IS" BASIS,
12a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling * See the License for the specific language governing permissions and
14a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling * limitations under the License.
15a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling */
16a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
17a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberlingpackage com.android.camera;
18a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
19a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberlingimport android.content.Context;
20a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberlingimport android.content.res.Configuration;
21a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberlingimport android.view.Surface;
22a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
23a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberlingimport com.android.camera.debug.Log;
24a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberlingimport com.android.camera.debug.Log.Tag;
25a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberlingimport com.android.camera.util.CameraUtil;
26e3dfd5a433e39d76578b379fe1539864cf924ceeSascha Haeberlingimport com.android.camera.util.Size;
27a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
28a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberlingimport java.util.ArrayList;
29a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
30a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling/**
31a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling * Common utility methods used in capture modules.
32a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling */
33a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberlingpublic class CaptureModuleUtil {
34a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling    private static final Tag TAG = new Tag("CaptureModuleUtil");
35a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
36a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling    public static int getDeviceNaturalOrientation(Context context) {
37a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        Configuration config = context.getResources().getConfiguration();
388be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde        int rotation = CameraUtil.getDisplayRotation();
39a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
40a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        if (((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) &&
41a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling                config.orientation == Configuration.ORIENTATION_LANDSCAPE) ||
42a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling                ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) &&
43a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling                config.orientation == Configuration.ORIENTATION_PORTRAIT)) {
44a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            return Configuration.ORIENTATION_LANDSCAPE;
45a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        } else {
46a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            return Configuration.ORIENTATION_PORTRAIT;
47a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        }
48a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling    }
49a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
50a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling    /**
51a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling     * Equivalent to the
526ba8eeea4758e29318c615e978c63599c30438b4Paul Rohde     * {@link CameraUtil#getOptimalPreviewSize(java.util.List, double)}
53a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling     * method for the camera1 api.
54a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling     */
556ba8eeea4758e29318c615e978c63599c30438b4Paul Rohde    public static Size getOptimalPreviewSize(Size[] sizes,double targetRatio) {
566ba8eeea4758e29318c615e978c63599c30438b4Paul Rohde        return getOptimalPreviewSize(sizes, targetRatio, null);
57c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling    }
58c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling
59c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling    /**
60c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling     * Returns the best preview size based on the current display resolution,
61c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling     * the available preview sizes, the target aspect ratio (typically the
62c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling     * aspect ratio of the picture to be taken) as well as a maximum allowed
63c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling     * tolerance. If tolerance is 'null', a default tolerance will be used.
64c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling     */
656ba8eeea4758e29318c615e978c63599c30438b4Paul Rohde    public static Size getOptimalPreviewSize(Size[] sizes,
66c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling            double targetRatio, Double aspectRatioTolerance) {
67a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        // TODO(andyhuibers): Don't hardcode this but use device's measurements.
68a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        final int MAX_ASPECT_HEIGHT = 1080;
69a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
70a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        // Count sizes with height <= 1080p to mimic camera1 api behavior.
71a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        int count = 0;
72a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        for (Size s : sizes) {
73a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            if (s.getHeight() <= MAX_ASPECT_HEIGHT) {
74a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling                count++;
75a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            }
76a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        }
77f2627903d11faf47c5052884bc2b23e27b8d5f94Sascha Haeberling        ArrayList<Size> camera1Sizes = new ArrayList<Size>(count);
78a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
79a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        // Set array of all sizes with height <= 1080p
80a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        for (Size s : sizes) {
81a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            if (s.getHeight() <= MAX_ASPECT_HEIGHT) {
82f2627903d11faf47c5052884bc2b23e27b8d5f94Sascha Haeberling                camera1Sizes.add(new Size(s.getWidth(), s.getHeight()));
83a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            }
84a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        }
85a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
86a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        int optimalIndex = CameraUtil
876ba8eeea4758e29318c615e978c63599c30438b4Paul Rohde                .getOptimalPreviewSizeIndex(camera1Sizes, targetRatio,
88c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling                        aspectRatioTolerance);
89a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
90a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        if (optimalIndex == -1) {
91a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            return null;
92a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        }
93a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
94f2627903d11faf47c5052884bc2b23e27b8d5f94Sascha Haeberling        Size optimal = camera1Sizes.get(optimalIndex);
95a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        for (Size s : sizes) {
96f2627903d11faf47c5052884bc2b23e27b8d5f94Sascha Haeberling            if (s.getWidth() == optimal.getWidth() && s.getHeight() == optimal.getHeight()) {
97a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling                return s;
98a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            }
99a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        }
100a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        return null;
101a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling    }
102a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
103a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling    /**
104a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling     * Selects the preview buffer dimensions that are closest in size to the
105a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling     * size of the view containing the preview.
106a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling     */
107a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling    public static Size pickBufferDimensions(Size[] supportedPreviewSizes,
108a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            double bestPreviewAspectRatio,
109a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            Context context) {
110a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        // Swap dimensions if the device is not in its natural orientation.
1118be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde        boolean swapDimens = (CameraUtil.getDisplayRotation() % 180) == 90;
112a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        // Swap dimensions if the device's natural orientation doesn't match
113a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        // the sensor orientation.
114a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        if (CaptureModuleUtil.getDeviceNaturalOrientation(context)
115a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling                == Configuration.ORIENTATION_PORTRAIT) {
116a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            swapDimens = !swapDimens;
117a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        }
118a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        double bestAspect = bestPreviewAspectRatio;
119a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        if (swapDimens) {
120a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling            bestAspect = 1 / bestAspect;
121a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        }
122a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling
1236ba8eeea4758e29318c615e978c63599c30438b4Paul Rohde        Size pick = CaptureModuleUtil.getOptimalPreviewSize(supportedPreviewSizes,
124c6da1a12fe8b78e2fbebe1af5efee514bc8e25eeSascha Haeberling                bestPreviewAspectRatio, null);
125a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        Log.d(TAG, "Picked buffer size: " + pick.toString());
126a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling        return pick;
127a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling    }
128a5c41b83304218f05a6454bf40fc6d236c218338Sascha Haeberling}
129