content: /*
   * Copyright (C) 2017 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.params;
  
  import android.annotation.CallbackExecutor;
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.annotation.IntDef;
  import android.hardware.camera2.CameraCaptureSession;
  import android.hardware.camera2.CameraCharacteristics;
  import android.hardware.camera2.CameraDevice;
  import android.hardware.camera2.CaptureRequest;
  import android.hardware.camera2.params.InputConfiguration;
  import android.hardware.camera2.params.OutputConfiguration;
  import android.hardware.camera2.utils.HashCodeHelpers;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.util.Log;
  
  import java.util.Collections;
  import java.util.List;
  import java.util.ArrayList;
  import java.util.concurrent.Executor;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  
  import static com.android.internal.util.Preconditions.*;
  
  /**
   * A helper class that aggregates all supported arguments for capture session initialization.
   */
  public final class SessionConfiguration implements Parcelable {
      private static final String TAG = "SessionConfiguration";
  
      /**
       * A regular session type containing instances of {@link OutputConfiguration} running
       * at regular non high speed FPS ranges and optionally {@link InputConfiguration} for
       * reprocessable sessions.
       *
       * @see CameraDevice#createCaptureSession
       * @see CameraDevice#createReprocessableCaptureSession
       */
      public static final int SESSION_REGULAR = CameraDevice.SESSION_OPERATION_MODE_NORMAL;
  
      /**
       * A high speed session type that can only contain instances of {@link OutputConfiguration}.
       * The outputs can run using high speed FPS ranges. Calls to {@link #setInputConfiguration}
       * are not supported.
       *
       * @see CameraDevice#createConstrainedHighSpeedCaptureSession
       */
      public static final int SESSION_HIGH_SPEED =
          CameraDevice.SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED;
  
      /**
       * First vendor-specific session mode
       * @hide
       */
      public static final int SESSION_VENDOR_START =
          CameraDevice.SESSION_OPERATION_MODE_VENDOR_START;
  
       /** @hide */
      @Retention(RetentionPolicy.SOURCE)
      @IntDef(prefix = {"SESSION_"}, value =
              {SESSION_REGULAR,
               SESSION_HIGH_SPEED })
      public @interface SessionMode {};
  
      // Camera capture session related parameters.
      private List<OutputConfiguration> mOutputConfigurations;
      private CameraCaptureSession.StateCallback mStateCallback;
      private int mSessionType;
      private Executor mExecutor = null;
      private InputConfiguration mInputConfig = null;
      private CaptureRequest mSessionParameters = null;
  
      /**
       * Create a new {@link SessionConfiguration}.
       *
       * @param sessionType The session type.
       * @param outputs A list of output configurations for the capture session.
       * @param executor The executor which should be used to invoke the callback. In general it is
       *                 recommended that camera operations are not done on the main (UI) thread.
       * @param cb A state callback interface implementation.
       *
       * @see #SESSION_REGULAR
       * @see #SESSION_HIGH_SPEED
       * @see CameraDevice#createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)
       * @see CameraDevice#createCaptureSessionByOutputConfigurations
       * @see CameraDevice#createReprocessableCaptureSession
       * @see CameraDevice#createConstrainedHighSpeedCaptureSession
       */
      public SessionConfiguration(@SessionMode int sessionType,
              @NonNull List<OutputConfiguration> outputs,
              @NonNull @CallbackExecutor Executor executor,
              @NonNull CameraCaptureSession.StateCallback cb) {
          mSessionType = sessionType;
          mOutputConfigurations = Collections.unmodifiableList(new ArrayList<>(outputs));
          mStateCallback = cb;
          mExecutor = executor;
      }
  
      /**
       * Create a SessionConfiguration from Parcel.
       * No support for parcelable 'mStateCallback', 'mExecutor' and 'mSessionParameters' yet.
       */
      private SessionConfiguration(@NonNull Parcel source) {
          int sessionType = source.readInt();
          int inputWidth = source.readInt();
          int inputHeight = source.readInt();
          int inputFormat = source.readInt();
          ArrayList<OutputConfiguration> outConfigs = new ArrayList<OutputConfiguration>();
          source.readTypedList(outConfigs, OutputConfiguration.CREATOR);
  
          if ((inputWidth > 0) && (inputHeight > 0) && (inputFormat != -1)) {
              mInputConfig = new InputConfiguration(inputWidth, inputHeight, inputFormat);
          }
          mSessionType = sessionType;
          mOutputConfigurations = outConfigs;
      }
  
      public static final @android.annotation.NonNull Parcelable.Creator<SessionConfiguration> CREATOR =
              new Parcelable.Creator<SessionConfiguration> () {
          @Override
          public SessionConfiguration createFromParcel(Parcel source) {
              try {
                  SessionConfiguration sessionConfiguration = new SessionConfiguration(source);
                  return sessionConfiguration;
              } catch (Exception e) {
                  Log.e(TAG, "Exception creating SessionConfiguration from parcel", e);
                  return null;
              }
          }
  
          @Override
          public SessionConfiguration[] newArray(int size) {
              return new SessionConfiguration[size];
          }
      };
  
      @Override
      public void writeToParcel(Parcel dest, int flags) {
          if (dest == null) {
              throw new IllegalArgumentException("dest must not be null");
          }
          dest.writeInt(mSessionType);
          if (mInputConfig != null) {
              dest.writeInt(mInputConfig.getWidth());
              dest.writeInt(mInputConfig.getHeight());
              dest.writeInt(mInputConfig.getFormat());
          } else {
              dest.writeInt(/*inputWidth*/ 0);
              dest.writeInt(/*inputHeight*/ 0);
              dest.writeInt(/*inputFormat*/ -1);
          }
          dest.writeTypedList(mOutputConfigurations);
      }
  
      @Override
      public int describeContents() {
          return 0;
      }
  
      /**
       * Check if this {@link SessionConfiguration} is equal to another {@link SessionConfiguration}.
       *
       * <p>Two output session configurations are only equal if and only if the underlying input
       * configuration, output configurations, and session type are equal. </p>
       *
       * @return {@code true} if the objects were equal, {@code false} otherwise
       */
      @Override
      public boolean equals(Object obj) {
          if (obj == null) {
              return false;
          } else if (this == obj) {
              return true;
          } else if (obj instanceof SessionConfiguration) {
              final SessionConfiguration other = (SessionConfiguration) obj;
              if (mInputConfig != other.mInputConfig || mSessionType != other.mSessionType ||
                      mOutputConfigurations.size() != other.mOutputConfigurations.size()) {
                  return false;
              }
  
              for (int i = 0;  i < mOutputConfigurations.size(); i++) {
                  if (!mOutputConfigurations.get(i).equals(other.mOutputConfigurations.get(i)))
                      return false;
              }
  
              return true;
          }
  
          return false;
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      public int hashCode() {
          return HashCodeHelpers.hashCode(mOutputConfigurations.hashCode(), mInputConfig.hashCode(),
                  mSessionType);
      }
  
      /**
       * Retrieve the type of the capture session.
       *
       * @return The capture session type.
       */
      public @SessionMode int getSessionType() {
          return mSessionType;
      }
  
      /**
       * Retrieve the {@link OutputConfiguration} list for the capture session.
       *
       * @return A list of output configurations for the capture session.
       */
      public List<OutputConfiguration> getOutputConfigurations() {
          return mOutputConfigurations;
      }
  
      /**
       * Retrieve the {@link CameraCaptureSession.StateCallback} for the capture session.
       *
       * @return A state callback interface implementation.
       */
      public CameraCaptureSession.StateCallback getStateCallback() {
          return mStateCallback;
      }
  
      /**
       * Retrieve the {@link java.util.concurrent.Executor} for the capture session.
       *
       * @return The Executor on which the callback will be invoked.
       */
      public Executor getExecutor() {
          return mExecutor;
      }
  
      /**
       * Sets the {@link InputConfiguration} for a reprocessable session. Input configuration are not
       * supported for {@link #SESSION_HIGH_SPEED}.
       *
       * @param input Input configuration.
       * @throws UnsupportedOperationException In case it is called for {@link #SESSION_HIGH_SPEED}
       *                                       type session configuration.
       */
      public void setInputConfiguration(@NonNull InputConfiguration input) {
          if (mSessionType != SESSION_HIGH_SPEED) {
              mInputConfig = input;
          } else {
              throw new UnsupportedOperationException("Method not supported for high speed session" +
                      " types");
          }
      }
  
      /**
       * Retrieve the {@link InputConfiguration}.
       *
       * @return The capture session input configuration.
       */
      public InputConfiguration getInputConfiguration() {
          return mInputConfig;
      }
  
      /**
       * Sets the session wide camera parameters (see {@link CaptureRequest}). This argument can
       * be set for every supported session type and will be passed to the camera device as part
       * of the capture session initialization. Session parameters are a subset of the available
       * capture request parameters (see {@link CameraCharacteristics#getAvailableSessionKeys})
       * and their application can introduce internal camera delays. To improve camera performance
       * it is suggested to change them sparingly within the lifetime of the capture session and
       * to pass their initial values as part of this method.
       *
       * @param params A capture request that includes the initial values for any available
       *               session wide capture keys. Tags (see {@link CaptureRequest.Builder#setTag}) and
       *               output targets (see {@link CaptureRequest.Builder#addTarget}) are ignored if
       *               set. Parameter values not part of
       *               {@link CameraCharacteristics#getAvailableSessionKeys} will also be ignored. It
       *               is recommended to build the session parameters using the same template type as
       *               the initial capture request, so that the session and initial request parameters
       *               match as much as possible.
       */
      public void setSessionParameters(CaptureRequest params) {
          mSessionParameters = params;
      }
  
      /**
       * Retrieve the session wide camera parameters (see {@link CaptureRequest}).
       *
       * @return A capture request that includes the initial values for any available
       *         session wide capture keys.
       */
      public CaptureRequest getSessionParameters() {
          return mSessionParameters;
      }
  }
  