content: /*
   * 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.telecom;
  
  import android.annotation.FloatRange;
  import android.annotation.IntDef;
  import android.annotation.IntRange;
  import android.annotation.UnsupportedAppUsage;
  import android.os.Parcel;
  import android.os.Parcelable;
  
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  
  /**
   * Represents attributes of video calls.
   */
  public class VideoProfile implements Parcelable {
  
      /** @hide */
      @Retention(RetentionPolicy.SOURCE)
      @IntDef({QUALITY_UNKNOWN, QUALITY_HIGH, QUALITY_MEDIUM, QUALITY_LOW, QUALITY_DEFAULT})
      public @interface VideoQuality {}
  
      /**
       * "Unknown" video quality.
       * @hide
       */
      public static final int QUALITY_UNKNOWN = 0;
      /**
       * "High" video quality.
       */
      public static final int QUALITY_HIGH = 1;
  
      /**
       * "Medium" video quality.
       */
      public static final int QUALITY_MEDIUM = 2;
  
      /**
       * "Low" video quality.
       */
      public static final int QUALITY_LOW = 3;
  
      /**
       * Use default video quality.
       */
      public static final int QUALITY_DEFAULT = 4;
  
      /** @hide */
      @Retention(RetentionPolicy.SOURCE)
      @IntDef(
              flag = true,
              prefix = { "STATE_" },
              value = {STATE_AUDIO_ONLY, STATE_TX_ENABLED, STATE_RX_ENABLED, STATE_BIDIRECTIONAL,
                      STATE_PAUSED})
      public @interface VideoState {}
  
      /**
       * Used when answering or dialing a call to indicate that the call does not have a video
       * component.
       * <p>
       * Should <b>not</b> be used in comparison checks to determine if a video state represents an
       * audio-only call.
       * <p>
       * The following, for example, is not the correct way to check if a call is audio-only:
       * <pre>
       * {@code
       * // This is the incorrect way to check for an audio-only call.
       * if (videoState == VideoProfile.STATE_AUDIO_ONLY) {
       *      // Handle audio-only call.
       * }
       * }
       * </pre>
       * <p>
       * Instead, use the {@link VideoProfile#isAudioOnly(int)} helper function to check if a
       * video state represents an audio-only call:
       * <pre>
       * {@code
       * // This is the correct way to check for an audio-only call.
       * if (VideoProfile.isAudioOnly(videoState)) {
       *      // Handle audio-only call.
       * }
       * }
       * </pre>
       */
      public static final int STATE_AUDIO_ONLY = 0x0;
  
      /**
       * Video transmission is enabled.
       */
      public static final int STATE_TX_ENABLED = 0x1;
  
      /**
       * Video reception is enabled.
       */
      public static final int STATE_RX_ENABLED = 0x2;
  
      /**
       * Video signal is bi-directional.
       */
      public static final int STATE_BIDIRECTIONAL = STATE_TX_ENABLED | STATE_RX_ENABLED;
  
      /**
       * Video is paused.
       */
      public static final int STATE_PAUSED = 0x4;
  
      private final int mVideoState;
  
      private final int mQuality;
  
      /**
       * Creates an instance of the VideoProfile
       *
       * @param videoState The video state.
       */
      public VideoProfile(@VideoState int videoState) {
          this(videoState, QUALITY_DEFAULT);
      }
  
      /**
       * Creates an instance of the VideoProfile
       *
       * @param videoState The video state.
       * @param quality The video quality.
       */
      public VideoProfile(@VideoState int videoState, @VideoQuality int quality) {
          mVideoState = videoState;
          mQuality = quality;
      }
  
      /**
       * The video state of the call.
       * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
       * {@link VideoProfile#STATE_BIDIRECTIONAL},
       * {@link VideoProfile#STATE_TX_ENABLED},
       * {@link VideoProfile#STATE_RX_ENABLED},
       * {@link VideoProfile#STATE_PAUSED}.
       */
      @VideoState
      public int getVideoState() {
          return mVideoState;
      }
  
      /**
       * The desired video quality for the call.
       * Valid values: {@link VideoProfile#QUALITY_HIGH}, {@link VideoProfile#QUALITY_MEDIUM},
       * {@link VideoProfile#QUALITY_LOW}, {@link VideoProfile#QUALITY_DEFAULT}.
       */
      @VideoQuality
      public int getQuality() {
          return mQuality;
      }
  
      /**
       * Responsible for creating VideoProfile objects from deserialized Parcels.
       **/
      public static final @android.annotation.NonNull Parcelable.Creator<VideoProfile> CREATOR =
              new Parcelable.Creator<VideoProfile> () {
                  /**
                   * Creates a MediaProfile instances from a parcel.
                   *
                   * @param source The parcel.
                   * @return The MediaProfile.
                   */
                  @Override
                  public VideoProfile createFromParcel(Parcel source) {
                      int state = source.readInt();
                      int quality = source.readInt();
  
                      ClassLoader classLoader = VideoProfile.class.getClassLoader();
                      return new VideoProfile(state, quality);
                  }
  
                  @Override
                  public VideoProfile[] newArray(int size) {
                      return new VideoProfile[size];
                  }
              };
  
      /**
       * Describe the kinds of special objects contained in this Parcelable's
       * marshalled representation.
       *
       * @return a bitmask indicating the set of special object types marshalled
       * by the Parcelable.
       */
      @Override
      public int describeContents() {
          return 0;
      }
  
      /**
       * Flatten this object in to a Parcel.
       *
       * @param dest  The Parcel in which the object should be written.
       * @param flags Additional flags about how the object should be written.
       *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
       */
      @Override
      public void writeToParcel(Parcel dest, int flags) {
          dest.writeInt(mVideoState);
          dest.writeInt(mQuality);
      }
  
      @Override
      public String toString() {
          StringBuilder sb = new StringBuilder();
          sb.append("[VideoProfile videoState = ");
          sb.append(videoStateToString(mVideoState));
          sb.append(" videoQuality = ");
          sb.append(mQuality);
          sb.append("]");
          return sb.toString();
      }
  
      /**
       * Generates a string representation of a video state.
       *
       * @param videoState The video state.
       * @return String representation of the video state.
       */
      public static String videoStateToString(@VideoState int videoState) {
          StringBuilder sb = new StringBuilder();
          sb.append("Audio");
  
          if (videoState == STATE_AUDIO_ONLY) {
              sb.append(" Only");
          } else {
              if (isTransmissionEnabled(videoState)) {
                  sb.append(" Tx");
              }
  
              if (isReceptionEnabled(videoState)) {
                  sb.append(" Rx");
              }
  
              if (isPaused(videoState)) {
                  sb.append(" Pause");
              }
          }
  
          return sb.toString();
      }
  
      /**
       * Indicates whether the video state is audio only.
       * <p>
       * Note: Considers only whether either both the {@link #STATE_RX_ENABLED} or
       * {@link #STATE_TX_ENABLED} bits are off, but not {@link #STATE_PAUSED}.
       *
       * @param videoState The video state.
       * @return {@code True} if the video state is audio only, {@code false} otherwise.
       */
      public static boolean isAudioOnly(@VideoState int videoState) {
          return !hasState(videoState, VideoProfile.STATE_TX_ENABLED)
                  && !hasState(videoState, VideoProfile.STATE_RX_ENABLED);
      }
  
      /**
       * Indicates whether video transmission or reception is enabled for a video state.
       *
       * @param videoState The video state.
       * @return {@code True} if video transmission or reception is enabled, {@code false} otherwise.
       */
      public static boolean isVideo(@VideoState int videoState) {
          return hasState(videoState, VideoProfile.STATE_TX_ENABLED)
                  || hasState(videoState, VideoProfile.STATE_RX_ENABLED)
                  || hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
      }
  
      /**
       * Indicates whether the video state has video transmission enabled.
       *
       * @param videoState The video state.
       * @return {@code True} if video transmission is enabled, {@code false} otherwise.
       */
      public static boolean isTransmissionEnabled(@VideoState int videoState) {
          return hasState(videoState, VideoProfile.STATE_TX_ENABLED);
      }
  
      /**
       * Indicates whether the video state has video reception enabled.
       *
       * @param videoState The video state.
       * @return {@code True} if video reception is enabled, {@code false} otherwise.
       */
      public static boolean isReceptionEnabled(@VideoState int videoState) {
          return hasState(videoState, VideoProfile.STATE_RX_ENABLED);
      }
  
      /**
       * Indicates whether the video state is bi-directional.
       *
       * @param videoState The video state.
       * @return {@code True} if the video is bi-directional, {@code false} otherwise.
       */
      public static boolean isBidirectional(@VideoState int videoState) {
          return hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
      }
  
      /**
       * Indicates whether the video state is paused.
       *
       * @param videoState The video state.
       * @return {@code True} if the video is paused, {@code false} otherwise.
       */
      public static boolean isPaused(@VideoState int videoState) {
          return hasState(videoState, VideoProfile.STATE_PAUSED);
      }
  
      /**
       * Indicates if a specified state is set in a videoState bit-mask.
       *
       * @param videoState The video state bit-mask.
       * @param state The state to check.
       * @return {@code True} if the state is set.
       */
      private static boolean hasState(@VideoState int videoState, @VideoState int state) {
          return (videoState & state) == state;
      }
  
      /**
       * Represents the camera capabilities important to a Video Telephony provider.
       */
      public static final class CameraCapabilities implements Parcelable {
  
          /**
           * The width of the camera video in pixels.
           */
          private final int mWidth;
  
          /**
           * The height of the camera video in pixels.
           */
          private final int mHeight;
  
          /**
           * Whether the camera supports zoom.
           */
          private final boolean mZoomSupported;
  
          /**
           * The maximum zoom supported by the camera.
           */
          private final float mMaxZoom;
  
          /**
           * Create a call camera capabilities instance.
           *
           * @param width The width of the camera video (in pixels).
           * @param height The height of the camera video (in pixels).
           */
          public CameraCapabilities(@IntRange(from = 0) int width, @IntRange(from = 0) int height) {
              this(width, height, false, 1.0f);
          }
  
          /**
           * Create a call camera capabilities instance that optionally supports zoom.
           *
           * @param width The width of the camera video (in pixels).
           * @param height The height of the camera video (in pixels).
           * @param zoomSupported True when camera supports zoom.
           * @param maxZoom Maximum zoom supported by camera.
           */
          public CameraCapabilities(@IntRange(from = 0) int width,  @IntRange(from = 0) int height,
                                     boolean zoomSupported,  @FloatRange(from = 1.0f) float maxZoom) {
              mWidth = width;
              mHeight = height;
              mZoomSupported = zoomSupported;
              mMaxZoom = maxZoom;
          }
  
          /**
           * Responsible for creating CallCameraCapabilities objects from deserialized Parcels.
           **/
          public static final @android.annotation.NonNull Parcelable.Creator<CameraCapabilities> CREATOR =
                  new Parcelable.Creator<CameraCapabilities> () {
                      /**
                       * Creates a CallCameraCapabilities instances from a parcel.
                       *
                       * @param source The parcel.
                       * @return The CallCameraCapabilities.
                       */
                      @Override
                      public CameraCapabilities createFromParcel(Parcel source) {
                          int width = source.readInt();
                          int height = source.readInt();
                          boolean supportsZoom = source.readByte() != 0;
                          float maxZoom = source.readFloat();
  
                          return new CameraCapabilities(width, height, supportsZoom, maxZoom);
                      }
  
                      @Override
                      public CameraCapabilities[] newArray(int size) {
                          return new CameraCapabilities[size];
                      }
                  };
  
          /**
           * Describe the kinds of special objects contained in this Parcelable's
           * marshalled representation.
           *
           * @return a bitmask indicating the set of special object types marshalled
           * by the Parcelable.
           */
          @Override
          public int describeContents() {
              return 0;
          }
  
          /**
           * Flatten this object in to a Parcel.
           *
           * @param dest  The Parcel in which the object should be written.
           * @param flags Additional flags about how the object should be written.
           *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
           */
          @Override
          public void writeToParcel(Parcel dest, int flags) {
              dest.writeInt(getWidth());
              dest.writeInt(getHeight());
              dest.writeByte((byte) (isZoomSupported() ? 1 : 0));
              dest.writeFloat(getMaxZoom());
          }
  
          /**
           * The width of the camera video in pixels.
           */
          public int getWidth() {
              return mWidth;
          }
  
          /**
           * The height of the camera video in pixels.
           */
          public int getHeight() {
              return mHeight;
          }
  
          /**
           * Returns {@code true} is zoom is supported, {@code false} otherwise.
           */
          public boolean isZoomSupported() {
              return mZoomSupported;
          }
  
          /**
           * Returns the maximum zoom supported by the camera.
           */
          public float getMaxZoom() {
              return mMaxZoom;
          }
      }
  
  }
  