1de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher/*
2de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher * Copyright (C) 2014 The Android Open Source Project
3de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher *
4de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher * Licensed under the Apache License, Version 2.0 (the "License");
5de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher * you may not use this file except in compliance with the License.
6de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher * You may obtain a copy of the License at
7de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher *
8de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher *      http://www.apache.org/licenses/LICENSE-2.0
9de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher *
10de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher * Unless required by applicable law or agreed to in writing, software
11de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher * distributed under the License is distributed on an "AS IS" BASIS,
12de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher * See the License for the specific language governing permissions and
14de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher * limitations under the License.
15de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher */
16de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
177e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kongpackage com.android.ex.camera2.portability;
187e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong
19f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucherimport android.graphics.Matrix;
20f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucherimport android.graphics.RectF;
217e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong
22de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucherimport com.android.ex.camera2.portability.debug.Log;
23de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
247e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong/**
25b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher * The device info for all attached cameras.
267e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong */
277e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kongpublic interface CameraDeviceInfo {
287e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong
297e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong    static final int NO_DEVICE = -1;
307e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong
317e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong    /**
32b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher     * @param cameraId Which device to interrogate.
33b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher     * @return The static characteristics of the specified device, or {@code null} on error.
347e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong     */
35b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher    Characteristics getCharacteristics(int cameraId);
367e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong
377e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong    /**
387e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong     * @return The total number of the available camera devices.
397e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong     */
407e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong    int getNumberOfCameras();
417e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong
427e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong    /**
437e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong     * @return The first (lowest) ID of the back cameras or {@code NO_DEVICE}
447e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong     *         if not available.
457e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong     */
467e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong    int getFirstBackCameraId();
477e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong
487e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong    /**
497e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong     * @return The first (lowest) ID of the front cameras or {@code NO_DEVICE}
507e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong     *         if not available.
517e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong     */
527e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong    int getFirstFrontCameraId();
53b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher
54b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher    /**
55b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher     * Device characteristics for a single camera.
56b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher     */
57de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher    public abstract class Characteristics {
58de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        private static final Log.Tag TAG = new Log.Tag("CamDvcInfChar");
59de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
60b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher        /**
61b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher         * @return Whether the camera faces the back of the device.
62b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher         */
63de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        public abstract boolean isFacingBack();
64b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher
65b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher        /**
66b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher         * @return Whether the camera faces the device's screen.
67b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher         */
68de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        public abstract boolean isFacingFront();
69b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher
70b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher        /**
71f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         * @return The camera sensor orientation, or the counterclockwise angle
72f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          from its natural position that the device must be held at
73f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          for the sensor to be right side up (in degrees, always a
74f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          multiple of 90, and between 0 and 270, inclusive).
75de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         */
76de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        public abstract int getSensorOrientation();
77de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
78de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        /**
79de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         * @param currentDisplayOrientation
80f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          The current display orientation, measured counterclockwise
81f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          from to the device's natural orientation (in degrees, always
82f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          a multiple of 90, and between 0 and 270, inclusive).
83de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         * @return
84de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          The relative preview image orientation, or the clockwise
85de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          rotation angle that must be applied to display preview
86de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          frames in the matching orientation, accounting for implicit
87de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          mirroring, if applicable (in degrees, always a multiple of
88de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          90, and between 0 and 270, inclusive).
89b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher         */
90de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        public int getPreviewOrientation(int currentDisplayOrientation) {
91de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            // Drivers tend to mirror the image during front camera preview.
92de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            return getRelativeImageOrientation(currentDisplayOrientation, true);
93de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        }
94de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
95de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        /**
96de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         * @param currentDisplayOrientation
97f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          The current display orientation, measured counterclockwise
98f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          from to the device's natural orientation (in degrees, always
99f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          a multiple of 90, and between 0 and 270, inclusive).
100de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         * @return
101de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          The relative capture image orientation, or the clockwise
102de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          rotation angle that must be applied to display these frames
103de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          in the matching orientation (in degrees, always a multiple
104de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          of 90, and between 0 and 270, inclusive).
105de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         */
106de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        public int getJpegOrientation(int currentDisplayOrientation) {
107de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            // Don't mirror during capture!
108de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            return getRelativeImageOrientation(currentDisplayOrientation, false);
109de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        }
110de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
111de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        /**
112de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         * @param currentDisplayOrientaiton
113de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          {@link #getPreviewOrientation}, {@link #getJpegOrientation}
114de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         * @param compensateForMirroring
115de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          Whether to account for mirroring in the case of front-facing
116de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          cameras, which is necessary iff the OS/driver is
117de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          automatically reflecting the image.
118de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         * @return
119de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *          {@link #getPreviewOrientation}, {@link #getJpegOrientation}
120de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         *
121de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         * @see android.hardware.Camera.setDisplayOrientation
122de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher         */
123de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        protected int getRelativeImageOrientation(int currentDisplayOrientation,
124de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                                  boolean compensateForMirroring) {
125f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            if (!orientationIsValid(currentDisplayOrientation)) {
126f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                return 0;
127de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            }
128de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
129de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            int result = 0;
130de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            if (isFacingFront()) {
131de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                result = (getSensorOrientation() + currentDisplayOrientation) % 360;
132de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                if (compensateForMirroring) {
133de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    result = (360 - result) % 360;
134de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                }
135de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            } else if (isFacingBack()) {
136de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                result = (getSensorOrientation() - currentDisplayOrientation + 360) % 360;
137de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            } else {
138de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                Log.e(TAG, "Camera is facing unhandled direction");
139de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            }
140de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            return result;
141de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        }
142b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher
143b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher        /**
144f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         * @param currentDisplayOrientation
145f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          The current display orientation, measured counterclockwise
146f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          from to the device's natural orientation (in degrees, always
147f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          a multiple of 90, and between 0 and 270, inclusive).
148f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         * @param surfaceDimensions
149f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          The dimensions of the {@link android.view.Surface} on which
150f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          the preview image is being rendered. It usually only makes
151f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          sense for the upper-left corner to be at the origin.
152f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         * @return
153f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          The transform matrix that should be applied to the
154f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          {@link android.view.Surface} in order for the image to
155f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          display properly in the device's current orientation.
156f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         */
157f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher        public Matrix getPreviewTransform(int currentDisplayOrientation, RectF surfaceDimensions) {
158f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            return getPreviewTransform(currentDisplayOrientation, surfaceDimensions,
159f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                    new RectF(surfaceDimensions));
160f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher        }
161f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher
162f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher        /**
163f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         * @param currentDisplayOrientation
164f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          The current display orientation, measured counterclockwise
165f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          from to the device's natural orientation (in degrees, always
166f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          a multiple of 90, and between 0 and 270, inclusive).
167f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         * @param surfaceDimensions
168f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          The dimensions of the {@link android.view.Surface} on which
169f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          the preview image is being rendered. It usually only makes
170f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          sense for the upper-left corner to be at the origin.
171f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         * @param desiredBounds
172f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          The boundaries within the {@link android.view.Surface} where
173f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          the final image should appear. These can be used to
174f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          translate and scale the output, but note that the image will
175f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          be stretched to fit, possibly changing its aspect ratio.
176f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         * @return
177f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          The transform matrix that should be applied to the
178f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          {@link android.view.Surface} in order for the image to
179f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         *          display properly in the device's current orientation.
180f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher         */
181f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher        public Matrix getPreviewTransform(int currentDisplayOrientation, RectF surfaceDimensions,
182f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                                          RectF desiredBounds) {
183f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            if (!orientationIsValid(currentDisplayOrientation) ||
184f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                    surfaceDimensions.equals(desiredBounds)) {
185f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                return new Matrix();
186f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            }
187f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher
188f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            Matrix transform = new Matrix();
189f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            transform.setRectToRect(surfaceDimensions, desiredBounds, Matrix.ScaleToFit.FILL);
190f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            return transform;
191f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher        }
192f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher
193f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher        /**
194b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher         * @return Whether the shutter sound can be disabled.
195b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher         */
196de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        public abstract boolean canDisableShutterSound();
197f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher
198f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher        protected static boolean orientationIsValid(int angle) {
199f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            if (angle % 90 != 0) {
200f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                Log.e(TAG, "Provided display orientation is not divisible by 90");
201f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                return false;
202f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            }
203f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            if (angle < 0 || angle > 270) {
204f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                Log.e(TAG, "Provided display orientation is outside expected range");
205f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                return false;
206f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            }
207f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            return true;
208f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher        }
209b30d2c670f1262f0d60181e40dad33f2151fee4aSol Boucher    }
2107e6c76ef7faf26aa1060b4abc1c65934b4e45338Angus Kong}
211