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

Commit 7ed5fb3e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "bug73953366_bug74605221" into pi-dev

* changes:
  Camera: Complete transition from handlers to executors
  Camera: Camera shouldn't throw 'RejectedExecutionException'
  Revert "Revert "Camera: SessionConfiguration should use Executors""
parents 13269764 9a0ec8c4
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -16449,8 +16449,8 @@ package android.hardware.camera2.params {
  }
  public final class SessionConfiguration {
    ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler);
    method public android.os.Handler getHandler();
    ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.StateCallback);
    method public java.util.concurrent.Executor getExecutor();
    method public android.hardware.camera2.params.InputConfiguration getInputConfiguration();
    method public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
    method public android.hardware.camera2.CaptureRequest getSessionParameters();
+2 −1
Original line number Diff line number Diff line
@@ -819,7 +819,8 @@ public abstract class CameraDevice implements AutoCloseable {
     * @param config A session configuration (see {@link SessionConfiguration}).
     *
     * @throws IllegalArgumentException In case the session configuration is invalid; or the output
     *                                  configurations are empty.
     *                                  configurations are empty; or the session configuration
     *                                  executor is invalid.
     * @throws CameraAccessException In case the camera device is no longer connected or has
     *                               encountered a fatal error.
     * @see #createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)
+93 −94
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.hardware.CameraInfo;
import android.hardware.CameraStatus;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
import android.hardware.camera2.impl.CameraDeviceImpl;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.legacy.CameraDeviceUserShim;
import android.hardware.camera2.legacy.LegacyMetadataMapper;
@@ -41,6 +42,11 @@ import android.util.ArrayMap;
import android.util.Log;

import java.util.ArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * <p>A system service manager for detecting, characterizing, and connecting to
@@ -123,16 +129,8 @@ public final class CameraManager {
     */
    public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback,
            @Nullable Handler handler) {
        if (handler == null) {
            Looper looper = Looper.myLooper();
            if (looper == null) {
                throw new IllegalArgumentException(
                        "No handler given, and current thread has no looper!");
            }
            handler = new Handler(looper);
        }

        CameraManagerGlobal.get().registerAvailabilityCallback(callback, handler);
        CameraManagerGlobal.get().registerAvailabilityCallback(callback,
                CameraDeviceImpl.checkAndWrapHandler(handler));
    }

    /**
@@ -170,15 +168,8 @@ public final class CameraManager {
     *             no looper.
     */
    public void registerTorchCallback(@NonNull TorchCallback callback, @Nullable Handler handler) {
        if (handler == null) {
            Looper looper = Looper.myLooper();
            if (looper == null) {
                throw new IllegalArgumentException(
                        "No handler given, and current thread has no looper!");
            }
            handler = new Handler(looper);
        }
        CameraManagerGlobal.get().registerTorchCallback(callback, handler);
        CameraManagerGlobal.get().registerTorchCallback(callback,
                CameraDeviceImpl.checkAndWrapHandler(handler));
    }

    /**
@@ -728,12 +719,13 @@ public final class CameraManager {
         */
        private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";

        private final ScheduledExecutorService mScheduler = Executors.newScheduledThreadPool(1);
        // Camera ID -> Status map
        private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();

        // Registered availablility callbacks and their handlers
        private final ArrayMap<AvailabilityCallback, Handler> mCallbackMap =
            new ArrayMap<AvailabilityCallback, Handler>();
        // Registered availablility callbacks and their executors
        private final ArrayMap<AvailabilityCallback, Executor> mCallbackMap =
            new ArrayMap<AvailabilityCallback, Executor>();

        // torch client binder to set the torch mode with.
        private Binder mTorchClientBinder = new Binder();
@@ -741,9 +733,9 @@ public final class CameraManager {
        // Camera ID -> Torch status map
        private final ArrayMap<String, Integer> mTorchStatus = new ArrayMap<String, Integer>();

        // Registered torch callbacks and their handlers
        private final ArrayMap<TorchCallback, Handler> mTorchCallbackMap =
                new ArrayMap<TorchCallback, Handler>();
        // Registered torch callbacks and their executors
        private final ArrayMap<TorchCallback, Executor> mTorchCallbackMap =
                new ArrayMap<TorchCallback, Executor>();

        private final Object mLock = new Object();

@@ -925,49 +917,63 @@ public final class CameraManager {
            }
        }

        private void postSingleUpdate(final AvailabilityCallback callback, final Handler handler,
        private void postSingleUpdate(final AvailabilityCallback callback, final Executor executor,
                final String id, final int status) {
            if (isAvailable(status)) {
                handler.post(
                final long ident = Binder.clearCallingIdentity();
                try {
                    executor.execute(
                        new Runnable() {
                            @Override
                            public void run() {
                                callback.onCameraAvailable(id);
                            }
                        });
                } finally {
                    Binder.restoreCallingIdentity(ident);
                }
            } else {
                handler.post(
                final long ident = Binder.clearCallingIdentity();
                try {
                    executor.execute(
                        new Runnable() {
                            @Override
                            public void run() {
                                callback.onCameraUnavailable(id);
                            }
                        });
                } finally {
                    Binder.restoreCallingIdentity(ident);
                }
            }
        }

        private void postSingleTorchUpdate(final TorchCallback callback, final Handler handler,
        private void postSingleTorchUpdate(final TorchCallback callback, final Executor executor,
                final String id, final int status) {
            switch(status) {
                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF:
                    handler.post(
                            new Runnable() {
                                @Override
                                public void run() {
                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF: {
                        final long ident = Binder.clearCallingIdentity();
                        try {
                            executor.execute(() -> {
                                callback.onTorchModeChanged(id, status ==
                                        ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON);
                                }
                            });
                        } finally {
                            Binder.restoreCallingIdentity(ident);
                        }
                    }
                    break;
                default:
                    handler.post(
                            new Runnable() {
                                @Override
                                public void run() {
                default: {
                        final long ident = Binder.clearCallingIdentity();
                        try {
                            executor.execute(() -> {
                                callback.onTorchModeUnavailable(id);
                                }
                            });
                        } finally {
                            Binder.restoreCallingIdentity(ident);
                        }
                    }
                    break;
            }
        }
@@ -976,11 +982,11 @@ public final class CameraManager {
         * Send the state of all known cameras to the provided listener, to initialize
         * the listener's knowledge of camera state.
         */
        private void updateCallbackLocked(AvailabilityCallback callback, Handler handler) {
        private void updateCallbackLocked(AvailabilityCallback callback, Executor executor) {
            for (int i = 0; i < mDeviceStatus.size(); i++) {
                String id = mDeviceStatus.keyAt(i);
                Integer status = mDeviceStatus.valueAt(i);
                postSingleUpdate(callback, handler, id, status);
                postSingleUpdate(callback, executor, id, status);
            }
        }

@@ -1039,18 +1045,18 @@ public final class CameraManager {

            final int callbackCount = mCallbackMap.size();
            for (int i = 0; i < callbackCount; i++) {
                Handler handler = mCallbackMap.valueAt(i);
                Executor executor = mCallbackMap.valueAt(i);
                final AvailabilityCallback callback = mCallbackMap.keyAt(i);

                postSingleUpdate(callback, handler, id, status);
                postSingleUpdate(callback, executor, id, status);
            }
        } // onStatusChangedLocked

        private void updateTorchCallbackLocked(TorchCallback callback, Handler handler) {
        private void updateTorchCallbackLocked(TorchCallback callback, Executor executor) {
            for (int i = 0; i < mTorchStatus.size(); i++) {
                String id = mTorchStatus.keyAt(i);
                Integer status = mTorchStatus.valueAt(i);
                postSingleTorchUpdate(callback, handler, id, status);
                postSingleTorchUpdate(callback, executor, id, status);
            }
        }

@@ -1078,9 +1084,9 @@ public final class CameraManager {

            final int callbackCount = mTorchCallbackMap.size();
            for (int i = 0; i < callbackCount; i++) {
                final Handler handler = mTorchCallbackMap.valueAt(i);
                final Executor executor = mTorchCallbackMap.valueAt(i);
                final TorchCallback callback = mTorchCallbackMap.keyAt(i);
                postSingleTorchUpdate(callback, handler, id, status);
                postSingleTorchUpdate(callback, executor, id, status);
            }
        } // onTorchStatusChangedLocked

@@ -1089,16 +1095,16 @@ public final class CameraManager {
         * global listener singleton.
         *
         * @param callback the new callback to send camera availability notices to
         * @param handler The handler on which the callback should be invoked. May not be null.
         * @param executor The executor which should invoke the callback. May not be null.
         */
        public void registerAvailabilityCallback(AvailabilityCallback callback, Handler handler) {
        public void registerAvailabilityCallback(AvailabilityCallback callback, Executor executor) {
            synchronized (mLock) {
                connectCameraServiceLocked();

                Handler oldHandler = mCallbackMap.put(callback, handler);
                Executor oldExecutor = mCallbackMap.put(callback, executor);
                // For new callbacks, provide initial availability information
                if (oldHandler == null) {
                    updateCallbackLocked(callback, handler);
                if (oldExecutor == null) {
                    updateCallbackLocked(callback, executor);
                }

                // If not connected to camera service, schedule a reconnect to camera service.
@@ -1120,14 +1126,14 @@ public final class CameraManager {
            }
        }

        public void registerTorchCallback(TorchCallback callback, Handler handler) {
        public void registerTorchCallback(TorchCallback callback, Executor executor) {
            synchronized(mLock) {
                connectCameraServiceLocked();

                Handler oldHandler = mTorchCallbackMap.put(callback, handler);
                Executor oldExecutor = mTorchCallbackMap.put(callback, executor);
                // For new callbacks, provide initial torch information
                if (oldHandler == null) {
                    updateTorchCallbackLocked(callback, handler);
                if (oldExecutor == null) {
                    updateTorchCallbackLocked(callback, executor);
                }

                // If not connected to camera service, schedule a reconnect to camera service.
@@ -1165,13 +1171,7 @@ public final class CameraManager {
         * availability callback or torch status callback.
         */
        private void scheduleCameraServiceReconnectionLocked() {
            final Handler handler;

            if (mCallbackMap.size() > 0) {
                handler = mCallbackMap.valueAt(0);
            } else if (mTorchCallbackMap.size() > 0) {
                handler = mTorchCallbackMap.valueAt(0);
            } else {
            if (mCallbackMap.isEmpty() && mTorchCallbackMap.isEmpty()) {
                // Not necessary to reconnect camera service if no client registers a callback.
                return;
            }
@@ -1181,10 +1181,8 @@ public final class CameraManager {
                        " ms");
            }

            handler.postDelayed(
                    new Runnable() {
                        @Override
                        public void run() {
            try {
                mScheduler.schedule(() -> {
                    ICameraService cameraService = getCameraService();
                    if (cameraService == null) {
                        synchronized(mLock) {
@@ -1194,9 +1192,10 @@ public final class CameraManager {
                            scheduleCameraServiceReconnectionLocked();
                        }
                    }
                }, CAMERA_SERVICE_RECONNECT_DELAY_MS, TimeUnit.MILLISECONDS);
            } catch (RejectedExecutionException e) {
                Log.e(TAG, "Failed to schedule camera service re-connect: " + e);
            }
                    },
                    CAMERA_SERVICE_RECONNECT_DELAY_MS);
        }

        /**
+0 −85
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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.camera2.dispatch;

import java.lang.reflect.Method;

import static com.android.internal.util.Preconditions.*;

/**
 * A dispatcher that replaces one argument with another; replaces any argument at an index
 * with another argument.
 *
 * <p>For example, we can override an {@code void onSomething(int x)} calls to have {@code x} always
 * equal to 1. Or, if using this with a duck typing dispatcher, we could even overwrite {@code x} to
 * be something
 * that's not an {@code int}.</p>
 *
 * @param <T>
 *          source dispatch type, whose methods with {@link #dispatch} will be called
 * @param <TArg>
 *          argument replacement type, args in {@link #dispatch} matching {@code argumentIndex}
 *          will be overriden to objects of this type
 */
public class ArgumentReplacingDispatcher<T, TArg> implements Dispatchable<T> {

    private final Dispatchable<T> mTarget;
    private final int mArgumentIndex;
    private final TArg mReplaceWith;

    /**
     * Create a new argument replacing dispatcher; dispatches are forwarded to {@code target}
     * after the argument is replaced.
     *
     * <p>For example, if a method {@code onAction(T1 a, Integer b, T2 c)} is invoked, and we wanted
     * to replace all occurrences of {@code b} with {@code 0xDEADBEEF}, we would set
     * {@code argumentIndex = 1} and {@code replaceWith = 0xDEADBEEF}.</p>
     *
     * <p>If a method dispatched has less arguments than {@code argumentIndex}, it is
     * passed through with the arguments unchanged.</p>
     *
     * @param target destination dispatch type, methods will be redirected to this dispatcher
     * @param argumentIndex the numeric index of the argument {@code >= 0}
     * @param replaceWith arguments matching {@code argumentIndex} will be replaced with this object
     */
    public ArgumentReplacingDispatcher(Dispatchable<T> target, int argumentIndex,
            TArg replaceWith) {
        mTarget = checkNotNull(target, "target must not be null");
        mArgumentIndex = checkArgumentNonnegative(argumentIndex,
                "argumentIndex must not be negative");
        mReplaceWith = checkNotNull(replaceWith, "replaceWith must not be null");
    }

    @Override
    public Object dispatch(Method method, Object[] args) throws Throwable {

        if (args.length > mArgumentIndex) {
            args = arrayCopy(args); // don't change in-place since it can affect upstream dispatches
            args[mArgumentIndex] = mReplaceWith;
        }

        return mTarget.dispatch(method, args);
    }

    private static Object[] arrayCopy(Object[] array) {
        int length = array.length;
        Object[] newArray = new Object[length];
        for (int i = 0; i < length; ++i) {
            newArray[i] = array[i];
        }
        return newArray;
    }
}
+0 −64
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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.camera2.dispatch;


import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

import static com.android.internal.util.Preconditions.*;

/**
 * Broadcast a single dispatch into multiple other dispatchables.
 *
 * <p>Every time {@link #dispatch} is invoked, all the broadcast targets will
 * see the same dispatch as well. The first target's return value is returned.</p>
 *
 * <p>This enables a single listener to be converted into a multi-listener.</p>
 */
public class BroadcastDispatcher<T> implements Dispatchable<T> {

    private final List<Dispatchable<T>> mDispatchTargets;

    /**
     * Create a broadcast dispatcher from the supplied dispatch targets.
     *
     * @param dispatchTargets one or more targets to dispatch to
     */
    @SafeVarargs
    public BroadcastDispatcher(Dispatchable<T>... dispatchTargets) {
        mDispatchTargets = Arrays.asList(
                checkNotNull(dispatchTargets, "dispatchTargets must not be null"));
    }

    @Override
    public Object dispatch(Method method, Object[] args) throws Throwable {
        Object result = null;
        boolean gotResult = false;

        for (Dispatchable<T> dispatchTarget : mDispatchTargets) {
            Object localResult = dispatchTarget.dispatch(method, args);

            if (!gotResult) {
                gotResult = true;
                result = localResult;
            }
        }

        return result;
    }
}
Loading