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

Commit 4c018e40 authored by Igor Murashkin's avatar Igor Murashkin Committed by Android (Google) Code Review
Browse files

Merge "Revert "Partial CameraManager implementation""

parents 0c5e010e a858308e
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -10653,7 +10653,7 @@ package android.hardware.location {
package android.hardware.photography {
  public class CameraAccessException extends android.util.AndroidException {
  public class CameraAccessException extends java.lang.Exception {
    ctor public CameraAccessException(int);
    ctor public CameraAccessException(int, java.lang.String);
    ctor public CameraAccessException(int, java.lang.String, java.lang.Throwable);
@@ -10666,6 +10666,7 @@ package android.hardware.photography {
  }
  public final class CameraDevice implements java.lang.AutoCloseable {
    ctor public CameraDevice();
    method public void capture(android.hardware.photography.CaptureRequest, android.hardware.photography.CameraDevice.CaptureListener) throws android.hardware.photography.CameraAccessException;
    method public void captureBurst(java.util.List<android.hardware.photography.CaptureRequest>, android.hardware.photography.CameraDevice.CaptureListener) throws android.hardware.photography.CameraAccessException;
    method public void close();
+3 −3
Original line number Diff line number Diff line
@@ -549,9 +549,9 @@ class ContextImpl extends Context {
                return new AppOpsManager(ctx, service);
            }});

        registerService(CAMERA_SERVICE, new ServiceFetcher() {
            public Object createService(ContextImpl ctx) {
                return new CameraManager(ctx);
        registerService(CAMERA_SERVICE, new StaticServiceFetcher() {
            public Object createStaticService() {
                return new CameraManager();
            }
        });

+3 −27
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package android.hardware.photography;

import android.util.AndroidException;

/**
 * <p><code>CameraAccessException</code> is thrown if a camera device could not
 * be queried or opened by the {@link CameraManager}, or if the connection to an
@@ -26,7 +24,7 @@ import android.util.AndroidException;
 * @see CameraManager
 * @see CameraDevice
 */
public class CameraAccessException extends AndroidException {
public class CameraAccessException extends Exception {
    /**
     * The camera device is in use already
     */
@@ -53,10 +51,7 @@ public class CameraAccessException extends AndroidException {
     */
    public static final int CAMERA_DISCONNECTED = 4;

    // Make the eclipse warning about serializable exceptions go away
    private static final long serialVersionUID = 5630338637471475675L; // randomly generated

    private final int mReason;
    private int mReason;

    /**
     * The reason for the failure to access the camera.
@@ -71,7 +66,6 @@ public class CameraAccessException extends AndroidException {
    }

    public CameraAccessException(int problem) {
        super(getDefaultMessage(problem));
        mReason = problem;
    }

@@ -86,25 +80,7 @@ public class CameraAccessException extends AndroidException {
    }

    public CameraAccessException(int problem, Throwable cause) {
        super(getDefaultMessage(problem), cause);
        super(cause);
        mReason = problem;
    }

    private static String getDefaultMessage(int problem) {
        switch (problem) {
            case CAMERA_IN_USE:
                return "The camera device is in use already";
            case MAX_CAMERAS_IN_USE:
                return "The system-wide limit for number of open cameras has been reached, " +
                       "and more camera devices cannot be opened until previous instances " +
                       "are closed.";
            case CAMERA_DISABLED:
                return "The camera is disabled due to a device policy, and cannot be opened.";
            case CAMERA_DISCONNECTED:
                return "The camera device is removable and has been disconnected from the Android" +
                       " device, or the camera service has shut down the connection due to a " +
                       "higher-priority access request for the camera device.";
        }
        return null;
    }
}
+0 −12
Original line number Diff line number Diff line
@@ -17,10 +17,8 @@
package android.hardware.photography;

import android.graphics.ImageFormat;
import android.os.IBinder;
import android.renderscript.Allocation;
import android.renderscript.RenderScript;
import android.util.Log;
import android.view.Surface;

import java.lang.AutoCloseable;
@@ -103,8 +101,6 @@ public final class CameraDevice implements AutoCloseable {
     */
    public static final int TEMPLATE_MANUAL = 5;

    private static final String TAG = "CameraDevice";

    /**
     * Get the static properties for this camera. These are identical to the
     * properties returned by {@link CameraManager#getCameraProperties}.
@@ -455,7 +451,6 @@ public final class CameraDevice implements AutoCloseable {
     * the camera device interface will throw a {@link IllegalStateException},
     * except for calls to close().
     */
    @Override
    public void close() {
    }

@@ -557,11 +552,4 @@ public final class CameraDevice implements AutoCloseable {
        public void onCameraDeviceError(CameraDevice camera, int error);
    }

    /**
     * @hide
     */
    public CameraDevice(IBinder binder) {
        Log.e(TAG, "CameraDevice constructor not implemented yet");
    }

}
+7 −234
Original line number Diff line number Diff line
@@ -16,22 +16,6 @@

package android.hardware.photography;

import android.content.Context;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
import android.hardware.IProCameraUser;
import android.hardware.photography.utils.CameraBinderDecorator;
import android.hardware.photography.utils.CameraRuntimeException;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

/**
 * <p>An interface for iterating, listing, and connecting to
 * {@link CameraDevice CameraDevices}.</p>
@@ -47,41 +31,10 @@ import java.util.HashSet;
 */
public final class CameraManager {

    /**
     * This should match the ICameraService definition
     */
    private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
    private static final int USE_CALLING_UID = -1;

    private final ICameraService mCameraService;
    private ArrayList<String> mDeviceIdList;
    private HashSet<CameraListener> mListenerSet;
    private final Context mContext;
    private final Object mLock = new Object();

    /**
     * @hide
     */
    public CameraManager(Context context) {
        mContext = context;

        IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);
        ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);

        /**
         * Wrap the camera service in a decorator which automatically translates return codes
         * into exceptions, and RemoteExceptions into other exceptions.
         */
        mCameraService = CameraBinderDecorator.newInstance(cameraServiceRaw);

        try {
            mCameraService.addListener(new CameraServiceListener());
        } catch(CameraRuntimeException e) {
            throw new IllegalStateException("Failed to register a camera service listener",
                    e.asChecked());
        } catch (RemoteException e) {
            // impossible
        }
    public CameraManager() {
    }

    /**
@@ -92,37 +45,25 @@ public final class CameraManager {
     *
     * @return The list of currently connected camera devices.
     */
    public String[] getDeviceIdList() throws CameraAccessException {
        synchronized (mLock) {
            return (String[]) getOrCreateDeviceIdListLocked().toArray();
        }
    public String[] getDeviceIdList() {
        return null;
    }

    /**
     * Register a listener to be notified about camera device availability.
     *
     * Registering a listener more than once has no effect.
     *
     * @param listener the new listener to send camera availability notices to.
     * @param listener the new listener to send camera availablity notices to.
     */
    public void registerCameraListener(CameraListener listener) {
        synchronized (mLock) {
            mListenerSet.add(listener);
        }
    }

    /**
     * Remove a previously-added listener; the listener will no longer receive
     * connection and disconnection callbacks.
     *
     * Removing a listener that isn't registered has no effect.
     *
     * @param listener the listener to remove from the notification list
     */
    public void unregisterCameraListener(CameraListener listener) {
        synchronized (mLock) {
            mListenerSet.remove(listener);
        }
    }

    /**
@@ -143,18 +84,7 @@ public final class CameraManager {
     */
    public CameraProperties getCameraProperties(String cameraId)
            throws CameraAccessException {

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

        // TODO: implement and call a service function to get the capabilities on C++ side

        // TODO: get properties from service
        return new CameraProperties();
        throw new IllegalArgumentException();
    }

    /**
@@ -177,33 +107,7 @@ public final class CameraManager {
     * @see android.app.admin.DevicePolicyManager#setCameraDisabled
     */
    public CameraDevice openCamera(String cameraId) throws CameraAccessException {

        try {
            IProCameraUser cameraUser;

            synchronized (mLock) {
                // TODO: Use ICameraDevice or some such instead of this...
                cameraUser = mCameraService.connectPro(null,
                        Integer.parseInt(cameraId),
                        mContext.getPackageName(), USE_CALLING_UID);

            }

            return new CameraDevice(cameraUser.asBinder());
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
                    + cameraId);
        } catch (CameraRuntimeException e) {
            if (e.getReason() == CameraAccessException.CAMERA_DISCONNECTED) {
                throw new IllegalArgumentException("Invalid camera ID specified -- " +
                        "perhaps the camera was physically disconnected", e);
            } else {
                throw e.asChecked();
            }
        } catch (RemoteException e) {
            // impossible
            return null;
        }
        throw new IllegalArgumentException();
    }

    /**
@@ -231,135 +135,4 @@ public final class CameraManager {
         */
        public void onCameraUnavailable(String cameraId);
    }

    private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
        if (mDeviceIdList == null) {
            int numCameras = 0;

            try {
                numCameras = mCameraService.getNumberOfCameras();
            } catch(CameraRuntimeException e) {
                throw e.asChecked();
            } catch (RemoteException e) {
                // impossible
                return null;
            }

            mDeviceIdList = new ArrayList<String>();
            for (int i = 0; i < numCameras; ++i) {
                // Non-removable cameras use integers starting at 0 for their
                // identifiers
                mDeviceIdList.add(String.valueOf(i));
            }

        }
        return mDeviceIdList;
    }

    // TODO: this class needs unit tests
    // TODO: extract class into top level
    private class CameraServiceListener extends Binder implements ICameraServiceListener  {

        // Keep up-to-date with ICameraServiceListener.h

        // Device physically unplugged
        public static final int STATUS_NOT_PRESENT = 0;
        // Device physically has been plugged in
        // and the camera can be used exclusively
        public static final int STATUS_PRESENT = 1;
        // Device physically has been plugged in
        // but it will not be connect-able until enumeration is complete
        public static final int STATUS_ENUMERATING = 2;
        // Camera is in use by another app and cannot be used exclusively
        public static final int STATUS_NOT_AVAILABLE = 0x80000000;

        // Camera ID -> Status map
        private final HashMap<String, Integer> mDeviceStatus = new HashMap<String, Integer>();

        private static final String TAG = "CameraServiceListener";

        @Override
        public IBinder asBinder() {
            return this;
        }

        private boolean isAvailable(int status) {
            switch (status) {
                case STATUS_PRESENT:
                    return true;
                default:
                    return false;
            }
        }

        private boolean validStatus(int status) {
            switch (status) {
                case STATUS_NOT_PRESENT:
                case STATUS_PRESENT:
                case STATUS_ENUMERATING:
                case STATUS_NOT_AVAILABLE:
                    return true;
                default:
                    return false;
            }
        }

        @Override
        public void onStatusChanged(int status, int cameraId) throws RemoteException {
            synchronized(CameraManager.this) {

                Log.v(TAG,
                        String.format("Camera id %d has status changed to 0x%x", cameraId, status));

                String id = String.valueOf(cameraId);

                if (!validStatus(status)) {
                    Log.e(TAG, String.format("Ignoring invalid device %d status 0x%x", cameraId,
                            status));
                    return;
                }

                Integer oldStatus = mDeviceStatus.put(id, status);

                if (oldStatus == status) {
                    Log.v(TAG, String.format(
                            "Device status changed to 0x%x, which is what it already was",
                            status));
                    return;
                }

                // TODO: consider abstracting out this state minimization + transition
                // into a separate
                // more easily testable class
                // i.e. (new State()).addState(STATE_AVAILABLE)
                //                   .addState(STATE_NOT_AVAILABLE)
                //                   .addTransition(STATUS_PRESENT, STATE_AVAILABLE),
                //                   .addTransition(STATUS_NOT_PRESENT, STATE_NOT_AVAILABLE)
                //                   .addTransition(STATUS_ENUMERATING, STATE_NOT_AVAILABLE);
                //                   .addTransition(STATUS_NOT_AVAILABLE, STATE_NOT_AVAILABLE);

                // Translate all the statuses to either 'available' or 'not available'
                //  available -> available         => no new update
                //  not available -> not available => no new update
                if (oldStatus != null && isAvailable(status) == isAvailable(oldStatus)) {

                    Log.v(TAG,
                            String.format(
                                    "Device status was previously available (%d), " +
                                            " and is now again available (%d)" +
                                            "so no new client visible update will be sent",
                                    isAvailable(status), isAvailable(status)));
                    return;
                }

                for (CameraListener listener : mListenerSet) {
                    if (isAvailable(status)) {
                        listener.onCameraAvailable(id);
                    } else {
                        listener.onCameraUnavailable(id);
}
                } // for
            } // synchronized
        } // onStatusChanged
    } // CameraServiceListener
} // CameraManager
Loading