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

Commit 570f4bde authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

Merge changes from topic "am-539574293c0c44efb365f30984f997d2"

* changes:
  Merge changes from topic "bug73953366_bug74605221" into pi-dev am: 7ed5fb3e am: a87c6da0
  Camera: Camera shouldn't throw 'RejectedExecutionException' am: b9a5194e am: ca5ffee3
  Revert "Revert "Camera: SessionConfiguration should use Executors"" am: 77ca866b am: f18ec573
parents 4e2de4d2 6dfdd8cc
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -16435,8 +16435,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