Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 52d60076 authored by Eino-Ville Talvala's avatar Eino-Ville Talvala Committed by Android (Google) Code Review
Browse files

Merge "Camera: Updates in preparation for HIDL"

parents 01c41ed8 283ae234
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.hardware;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Status information about a camera.
 *
 * Contains the name of the camera device, and its current status, one of the
 * ICameraServiceListener.STATUS_ values.
 *
 * @hide
 */
public class CameraStatus implements Parcelable {
    public String cameraId;
    public int status;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeString(cameraId);
        out.writeInt(status);
    }

    public void readFromParcel(Parcel in) {
        cameraId = in.readString();
        status = in.readInt();
    }

    public static final Parcelable.Creator<CameraStatus> CREATOR =
            new Parcelable.Creator<CameraStatus>() {
        @Override
        public CameraStatus createFromParcel(Parcel in) {
            CameraStatus status = new CameraStatus();
            status.readFromParcel(in);

            return status;
        }

        @Override
        public CameraStatus[] newArray(int size) {
            return new CameraStatus[size];
        }
    };
};
+51 −92
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.Context;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
import android.hardware.CameraInfo;
import android.hardware.CameraStatus;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.legacy.CameraDeviceUserShim;
import android.hardware.camera2.legacy.LegacyMetadataMapper;
@@ -92,11 +93,7 @@ public final class CameraManager {
     */
    @NonNull
    public String[] getCameraIdList() throws CameraAccessException {
        synchronized (mLock) {
            // ID list creation handles various known failures in device enumeration, so only
            // exceptions it'll throw are unexpected, and should be propagated upward.
            return getOrCreateDeviceIdListLocked().toArray(new String[0]);
        }
        return CameraManagerGlobal.get().getCameraIdList();
    }

    /**
@@ -218,18 +215,10 @@ public final class CameraManager {
        CameraCharacteristics characteristics = null;

        synchronized (mLock) {
            if (!getOrCreateDeviceIdListLocked().contains(cameraId)) {
                throw new IllegalArgumentException(String.format("Camera id %s does not match any" +
                        " currently connected camera device", cameraId));
            }

            int id = Integer.parseInt(cameraId);

            /*
             * Get the camera characteristics from the camera service directly if it supports it,
             * otherwise get them from the legacy shim instead.
             */

            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
            if (cameraService == null) {
                throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
@@ -239,6 +228,8 @@ public final class CameraManager {
                if (!supportsCamera2ApiLocked(cameraId)) {
                    // Legacy backwards compatibility path; build static info from the camera
                    // parameters
                    int id = Integer.parseInt(cameraId);

                    String parameters = cameraService.getLegacyParameters(id);

                    CameraInfo info = cameraService.getCameraInfo(id);
@@ -246,7 +237,7 @@ public final class CameraManager {
                    characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info);
                } else {
                    // Normal path: Get the camera characteristics directly from the camera service
                    CameraMetadataNative info = cameraService.getCameraCharacteristics(id);
                    CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId);

                    characteristics = new CameraCharacteristics(info);
                }
@@ -303,14 +294,6 @@ public final class CameraManager {

            ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();

            int id;
            try {
                id = Integer.parseInt(cameraId);
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
                        + cameraId);
            }

            try {
                if (supportsCamera2ApiLocked(cameraId)) {
                    // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
@@ -320,10 +303,18 @@ public final class CameraManager {
                            ICameraService.ERROR_DISCONNECTED,
                            "Camera service is currently unavailable");
                    }
                    cameraUser = cameraService.connectDevice(callbacks, id,
                    cameraUser = cameraService.connectDevice(callbacks, cameraId,
                            mContext.getOpPackageName(), uid);
                } else {
                    // Use legacy camera implementation for HAL1 devices
                    int id;
                    try {
                        id = Integer.parseInt(cameraId);
                    } catch (NumberFormatException e) {
                        throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
                                + cameraId);
                    }

                    Log.i(TAG, "Using legacy camera HAL.");
                    cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
                }
@@ -671,69 +662,6 @@ public final class CameraManager {
        }
    }

    /**
     * Return or create the list of currently connected camera devices.
     *
     * <p>In case of errors connecting to the camera service, will return an empty list.</p>
     */
    private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
        if (mDeviceIdList == null) {
            int numCameras = 0;
            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
            ArrayList<String> deviceIdList = new ArrayList<>();

            // If no camera service, then no devices
            if (cameraService == null) {
                return deviceIdList;
            }

            try {
                numCameras = cameraService.getNumberOfCameras(CAMERA_TYPE_ALL);
            } catch(ServiceSpecificException e) {
                throwAsPublicException(e);
            } catch (RemoteException e) {
                // camera service just died - if no camera service, then no devices
                return deviceIdList;
            }

            for (int i = 0; i < numCameras; ++i) {
                // Non-removable cameras use integers starting at 0 for their
                // identifiers
                boolean isDeviceSupported = false;
                try {
                    CameraMetadataNative info = cameraService.getCameraCharacteristics(i);
                    if (!info.isEmpty()) {
                        isDeviceSupported = true;
                    } else {
                        throw new AssertionError("Expected to get non-empty characteristics");
                    }
                } catch(ServiceSpecificException e) {
                    // DISCONNECTED means that the HAL reported an low-level error getting the
                    // device info; ILLEGAL_ARGUMENT means that this devices is not supported.
                    // Skip listing the device.  Other errors,
                    // propagate exception onward
                    if (e.errorCode != ICameraService.ERROR_DISCONNECTED ||
                            e.errorCode != ICameraService.ERROR_ILLEGAL_ARGUMENT) {
                        throwAsPublicException(e);
                    }
                } catch(RemoteException e) {
                    // Camera service died - no devices to list
                    deviceIdList.clear();
                    return deviceIdList;
                }

                if (isDeviceSupported) {
                    deviceIdList.add(String.valueOf(i));
                } else {
                    Log.w(TAG, "Error querying camera device " + i + " for listing.");
                }

            }
            mDeviceIdList = deviceIdList;
        }
        return mDeviceIdList;
    }

    /**
     * Queries the camera service if it supports the camera2 api directly, or needs a shim.
     *
@@ -752,8 +680,6 @@ public final class CameraManager {
     * @return {@code true} if connecting will work for that device version.
     */
    private boolean supportsCameraApiLocked(String cameraId, int apiVersion) {
        int id = Integer.parseInt(cameraId);

        /*
         * Possible return values:
         * - NO_ERROR => CameraX API is supported
@@ -767,7 +693,7 @@ public final class CameraManager {
            // If no camera service, no support
            if (cameraService == null) return false;

            return cameraService.supportsCameraApi(id, apiVersion);
            return cameraService.supportsCameraApi(cameraId, apiVersion);
        } catch (RemoteException e) {
            // Camera service is now down, no support for any API level
        }
@@ -880,7 +806,10 @@ public final class CameraManager {
            }

            try {
                cameraService.addListener(this);
                CameraStatus[] cameraStatuses = cameraService.addListener(this);
                for (CameraStatus c : cameraStatuses) {
                    onStatusChangedLocked(c.status, c.cameraId);
                }
                mCameraService = cameraService;
            } catch(ServiceSpecificException e) {
                // Unexpected failure
@@ -890,6 +819,36 @@ public final class CameraManager {
            }
        }

        /**
         * Get a list of all camera IDs that are at least PRESENT; ignore devices that are
         * NOT_PRESENT or ENUMERATING, since they cannot be used by anyone.
         */
        public String[] getCameraIdList() {
            String[] cameraIds = null;
            synchronized(mLock) {
                // Try to make sure we have an up-to-date list of camera devices.
                connectCameraServiceLocked();

                int idCount = 0;
                for (int i = 0; i < mDeviceStatus.size(); i++) {
                    int status = mDeviceStatus.valueAt(i);
                    if (status == ICameraServiceListener.STATUS_NOT_PRESENT ||
                            status == ICameraServiceListener.STATUS_ENUMERATING) continue;
                    idCount++;
                }
                cameraIds = new String[idCount];
                idCount = 0;
                for (int i = 0; i < mDeviceStatus.size(); i++) {
                    int status = mDeviceStatus.valueAt(i);
                    if (status == ICameraServiceListener.STATUS_NOT_PRESENT ||
                            status == ICameraServiceListener.STATUS_ENUMERATING) continue;
                    cameraIds[idCount] = mDeviceStatus.keyAt(i);
                    idCount++;
                }
            }
            return cameraIds;
        }

        public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException {
            synchronized(mLock) {

@@ -1173,9 +1132,9 @@ public final class CameraManager {
         * Callback from camera service notifying the process about camera availability changes
         */
        @Override
        public void onStatusChanged(int status, int cameraId) throws RemoteException {
        public void onStatusChanged(int status, String cameraId) throws RemoteException {
            synchronized(mLock) {
                onStatusChangedLocked(status, String.valueOf(cameraId));
                onStatusChangedLocked(status, cameraId);
            }
        }

+2 −2
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ public class MediaFrameworkIntegrationTestRunner extends InstrumentationTestRunn

    private static final String TAG = "MediaFrameworkIntegrationTestRunner";

    public static int mCameraId = 0;
    public static String mCameraId = "0";

    @Override
    public TestSuite getAllTests() {
@@ -62,7 +62,7 @@ public class MediaFrameworkIntegrationTestRunner extends InstrumentationTestRunn
            try {
                Log.v(TAG,
                        String.format("Reading camera_id from icicle: '%s'", cameraId));
                mCameraId = Integer.parseInt(cameraId);
                mCameraId = cameraId;
            }
            catch (NumberFormatException e) {
                Log.e(TAG, String.format("Failed to convert camera_id to integer"));
+7 −6
Original line number Diff line number Diff line
@@ -116,8 +116,8 @@ public class CameraBinderTest extends AndroidTestCase {
    @SmallTest
    public void testSupportsCamera2Api() throws Exception {
        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {

            boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
            boolean supports = mUtils.getCameraService().supportsCameraApi(
                String.valueOf(cameraId), API_VERSION_2);

            Log.v(TAG, "Camera " + cameraId + " supports api2: " + supports);
        }
@@ -128,7 +128,8 @@ public class CameraBinderTest extends AndroidTestCase {
    public void testSupportsCamera1Api() throws Exception {
        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {

            boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
            boolean supports = mUtils.getCameraService().supportsCameraApi(
                String.valueOf(cameraId), API_VERSION_1);
            assertTrue(
                    "Camera service returned false when queried if it supports camera1 api " +
                    " for camera ID " + cameraId, supports);
@@ -285,7 +286,7 @@ public class CameraBinderTest extends AndroidTestCase {

            ICameraDeviceUser cameraUser =
                    mUtils.getCameraService().connectDevice(
                        dummyCallbacks, cameraId,
                        dummyCallbacks, String.valueOf(cameraId),
                        clientPackageName,
                        ICameraService.USE_CALLING_UID);
            assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
@@ -298,9 +299,9 @@ public class CameraBinderTest extends AndroidTestCase {

    static class DummyCameraServiceListener extends ICameraServiceListener.Stub {
        @Override
        public void onStatusChanged(int status, int cameraId)
        public void onStatusChanged(int status, String cameraId)
                throws RemoteException {
            Log.v(TAG, String.format("Camera %d has status changed to 0x%x", cameraId, status));
            Log.v(TAG, String.format("Camera %s has status changed to 0x%x", cameraId, status));
        }
        public void onTorchStatusChanged(int status, String cameraId)
                throws RemoteException {
+1 −1
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
    private static final int DEFAULT_IMAGE_HEIGHT = 480;
    private static final int MAX_NUM_IMAGES = 5;

    private int mCameraId;
    private String mCameraId;
    private ICameraDeviceUser mCameraUser;
    private CameraBinderTestUtils mUtils;
    private ICameraDeviceCallbacks.Stub mMockCb;