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.net.Uri;
  import android.os.Bundle;
  import android.os.Parcel;
  import android.os.ParcelFileDescriptor;
  import android.os.Parcelable;
  
  /**
   * Simple data container encapsulating a request to some entity to
   * create a new {@link Connection}.
   */
  public final class ConnectionRequest implements Parcelable {
  
      /**
       * Builder class for {@link ConnectionRequest}
       * @hide
       */
      public static final class Builder {
          private PhoneAccountHandle mAccountHandle;
          private Uri mAddress;
          private Bundle mExtras;
          private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
          private String mTelecomCallId;
          private boolean mShouldShowIncomingCallUi = false;
          private ParcelFileDescriptor mRttPipeToInCall;
          private ParcelFileDescriptor mRttPipeFromInCall;
  
          public Builder() { }
  
          /**
           * Sets the phone account handle for the resulting {@link ConnectionRequest}
           * @param accountHandle The accountHandle which should be used to place the call.
           */
          public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
              this.mAccountHandle = accountHandle;
              return this;
          }
  
          /**
           * Sets the address for the resulting {@link ConnectionRequest}
           * @param address The address(e.g., phone number) to which the {@link Connection} is to
           *                connect.
           */
          public Builder setAddress(Uri address) {
              this.mAddress = address;
              return this;
          }
  
          /**
           * Sets the extras bundle for the resulting {@link ConnectionRequest}
           * @param extras Application-specific extra data.
           */
          public Builder setExtras(Bundle extras) {
              this.mExtras = extras;
              return this;
          }
  
          /**
           * Sets the video state for the resulting {@link ConnectionRequest}
           * @param videoState Determines the video state for the connection.
           */
          public Builder setVideoState(int videoState) {
              this.mVideoState = videoState;
              return this;
          }
  
          /**
           * Sets the Telecom call ID for the resulting {@link ConnectionRequest}
           * @param telecomCallId The telecom call ID.
           */
          public Builder setTelecomCallId(String telecomCallId) {
              this.mTelecomCallId = telecomCallId;
              return this;
          }
  
          /**
           * Sets shouldShowIncomingUi for the resulting {@link ConnectionRequest}
           * @param shouldShowIncomingCallUi For a self-managed {@link ConnectionService}, will be
           *                                 {@code true} if the {@link ConnectionService} should show
           *                                 its own incoming call UI for an incoming call.  When
           *                                 {@code false}, Telecom shows the incoming call UI.
           */
          public Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
              this.mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
              return this;
          }
  
          /**
           * Sets the RTT pipe for transferring text into the {@link ConnectionService} for the
           * resulting {@link ConnectionRequest}
           * @param rttPipeFromInCall The data pipe to read from.
           */
          public Builder setRttPipeFromInCall(ParcelFileDescriptor rttPipeFromInCall) {
              this.mRttPipeFromInCall = rttPipeFromInCall;
              return this;
          }
  
          /**
           * Sets the RTT pipe for transferring text out of {@link ConnectionService} for the
           * resulting {@link ConnectionRequest}
           * @param rttPipeToInCall The data pipe to write to.
           */
          public Builder setRttPipeToInCall(ParcelFileDescriptor rttPipeToInCall) {
              this.mRttPipeToInCall = rttPipeToInCall;
              return this;
          }
  
          public ConnectionRequest build() {
              return new ConnectionRequest(
                      mAccountHandle,
                      mAddress,
                      mExtras,
                      mVideoState,
                      mTelecomCallId,
                      mShouldShowIncomingCallUi,
                      mRttPipeFromInCall,
                      mRttPipeToInCall);
          }
      }
  
      private final PhoneAccountHandle mAccountHandle;
      private final Uri mAddress;
      private final Bundle mExtras;
      private final int mVideoState;
      private final String mTelecomCallId;
      private final boolean mShouldShowIncomingCallUi;
      private final ParcelFileDescriptor mRttPipeToInCall;
      private final ParcelFileDescriptor mRttPipeFromInCall;
      // Cached return value of getRttTextStream -- we don't want to wrap it more than once.
      private Connection.RttTextStream mRttTextStream;
  
      /**
       * @param accountHandle The accountHandle which should be used to place the call.
       * @param handle The handle (e.g., phone number) to which the {@link Connection} is to connect.
       * @param extras Application-specific extra data.
       */
      public ConnectionRequest(
              PhoneAccountHandle accountHandle,
              Uri handle,
              Bundle extras) {
          this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false, null, null);
      }
  
      /**
       * @param accountHandle The accountHandle which should be used to place the call.
       * @param handle The handle (e.g., phone number) to which the {@link Connection} is to connect.
       * @param extras Application-specific extra data.
       * @param videoState Determines the video state for the connection.
       */
      public ConnectionRequest(
              PhoneAccountHandle accountHandle,
              Uri handle,
              Bundle extras,
              int videoState) {
          this(accountHandle, handle, extras, videoState, null, false, null, null);
      }
  
      /**
       * @param accountHandle The accountHandle which should be used to place the call.
       * @param handle The handle (e.g., phone number) to which the {@link Connection} is to connect.
       * @param extras Application-specific extra data.
       * @param videoState Determines the video state for the connection.
       * @param telecomCallId The telecom call ID.
       * @param shouldShowIncomingCallUi For a self-managed {@link ConnectionService}, will be
       *                                 {@code true} if the {@link ConnectionService} should show its
       *                                 own incoming call UI for an incoming call.  When
       *                                 {@code false}, Telecom shows the incoming call UI.
       * @hide
       */
      public ConnectionRequest(
              PhoneAccountHandle accountHandle,
              Uri handle,
              Bundle extras,
              int videoState,
              String telecomCallId,
              boolean shouldShowIncomingCallUi) {
          this(accountHandle, handle, extras, videoState, telecomCallId,
                  shouldShowIncomingCallUi, null, null);
      }
  
      private ConnectionRequest(
              PhoneAccountHandle accountHandle,
              Uri handle,
              Bundle extras,
              int videoState,
              String telecomCallId,
              boolean shouldShowIncomingCallUi,
              ParcelFileDescriptor rttPipeFromInCall,
              ParcelFileDescriptor rttPipeToInCall) {
          mAccountHandle = accountHandle;
          mAddress = handle;
          mExtras = extras;
          mVideoState = videoState;
          mTelecomCallId = telecomCallId;
          mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
          mRttPipeFromInCall = rttPipeFromInCall;
          mRttPipeToInCall = rttPipeToInCall;
      }
  
      private ConnectionRequest(Parcel in) {
          mAccountHandle = in.readParcelable(getClass().getClassLoader());
          mAddress = in.readParcelable(getClass().getClassLoader());
          mExtras = in.readParcelable(getClass().getClassLoader());
          mVideoState = in.readInt();
          mTelecomCallId = in.readString();
          mShouldShowIncomingCallUi = in.readInt() == 1;
          mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader());
          mRttPipeToInCall = in.readParcelable(getClass().getClassLoader());
      }
  
      /**
       * The account which should be used to place the call.
       */
      public PhoneAccountHandle getAccountHandle() { return mAccountHandle; }
  
      /**
       * The handle (e.g., phone number) to which the {@link Connection} is to connect.
       */
      public Uri getAddress() { return mAddress; }
  
      /**
       * Application-specific extra data. Used for passing back information from an incoming
       * call {@code Intent}, and for any proprietary extensions arranged between a client
       * and servant {@code ConnectionService} which agree on a vocabulary for such data.
       */
      public Bundle getExtras() { return mExtras; }
  
      /**
       * Describes the video states supported by the client requesting the connection.
       * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
       * {@link VideoProfile#STATE_BIDIRECTIONAL},
       * {@link VideoProfile#STATE_TX_ENABLED},
       * {@link VideoProfile#STATE_RX_ENABLED}.
       *
       * @return The video state for the connection.
       */
      public int getVideoState() {
          return mVideoState;
      }
  
      /**
       * Returns the internal Telecom ID associated with the connection request.
       *
       * @return The Telecom ID.
       * @hide
       */
      public String getTelecomCallId() {
          return mTelecomCallId;
      }
  
      /**
       * For a self-managed {@link ConnectionService}, indicates for an incoming call whether the
       * {@link ConnectionService} should show its own incoming call UI for an incoming call.
       *
       * @return {@code true} if the {@link ConnectionService} should show its own incoming call UI.
       * When {@code false}, Telecom shows the incoming call UI for the call.
       * @hide
       */
      public boolean shouldShowIncomingCallUi() {
          return mShouldShowIncomingCallUi;
      }
  
      /**
       * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the connection
       * service to the in-call UI. In order to obtain an
       * {@link java.io.InputStream} from this {@link ParcelFileDescriptor}, use
       * {@link android.os.ParcelFileDescriptor.AutoCloseInputStream}.
       * Only text data encoded using UTF-8 should be written into this {@link ParcelFileDescriptor}.
       * @return The {@link ParcelFileDescriptor} that should be used for communication.
       * Do not un-hide -- only for use by Telephony
       * @hide
       */
      public ParcelFileDescriptor getRttPipeToInCall() {
          return mRttPipeToInCall;
      }
  
      /**
       * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the in-call UI to
       * the connection service. In order to obtain an
       * {@link java.io.OutputStream} from this {@link ParcelFileDescriptor}, use
       * {@link android.os.ParcelFileDescriptor.AutoCloseOutputStream}.
       * The contents of this {@link ParcelFileDescriptor} will consist solely of text encoded in
       * UTF-8.
       * @return The {@link ParcelFileDescriptor} that should be used for communication
       * Do not un-hide -- only for use by Telephony
       * @hide
       */
      public ParcelFileDescriptor getRttPipeFromInCall() {
          return mRttPipeFromInCall;
      }
  
      /**
       * Gets the {@link android.telecom.Connection.RttTextStream} object that should be used to
       * send and receive RTT text to/from the in-call app.
       * @return An instance of {@link android.telecom.Connection.RttTextStream}, or {@code null}
       * if this connection request is not requesting an RTT session upon connection establishment.
       */
      public Connection.RttTextStream getRttTextStream() {
          if (isRequestingRtt()) {
              if (mRttTextStream == null) {
                  mRttTextStream = new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
              }
              return mRttTextStream;
          } else {
              return null;
          }
      }
  
      /**
       * Convenience method for determining whether the ConnectionRequest is requesting an RTT session
       * @return {@code true} if RTT is requested, {@code false} otherwise.
       */
      public boolean isRequestingRtt() {
          return mRttPipeFromInCall != null && mRttPipeToInCall != null;
      }
  
      @Override
      public String toString() {
          return String.format("ConnectionRequest %s %s",
                  mAddress == null
                          ? Uri.EMPTY
                          : Connection.toLogSafePhoneNumber(mAddress.toString()),
                  bundleToString(mExtras));
      }
  
      private static String bundleToString(Bundle extras){
          if (extras == null) {
              return "";
          }
          StringBuilder sb = new StringBuilder();
          sb.append("Bundle[");
          for (String key : extras.keySet()) {
              sb.append(key);
              sb.append("=");
              switch (key) {
                  case TelecomManager.EXTRA_INCOMING_CALL_ADDRESS:
                  case TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE:
                      sb.append(Log.pii(extras.get(key)));
                      break;
                  default:
                      sb.append(extras.get(key));
                      break;
              }
              sb.append(", ");
          }
          sb.append("]");
          return sb.toString();
      }
  
      public static final @android.annotation.NonNull Creator<ConnectionRequest> CREATOR = new Creator<ConnectionRequest> () {
          @Override
          public ConnectionRequest createFromParcel(Parcel source) {
              return new ConnectionRequest(source);
          }
  
          @Override
          public ConnectionRequest[] newArray(int size) {
              return new ConnectionRequest[size];
          }
      };
  
      /**
       * {@inheritDoc}
       */
      @Override
      public int describeContents() {
          return 0;
      }
  
      @Override
      public void writeToParcel(Parcel destination, int flags) {
          destination.writeParcelable(mAccountHandle, 0);
          destination.writeParcelable(mAddress, 0);
          destination.writeParcelable(mExtras, 0);
          destination.writeInt(mVideoState);
          destination.writeString(mTelecomCallId);
          destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0);
          destination.writeParcelable(mRttPipeFromInCall, 0);
          destination.writeParcelable(mRttPipeToInCall, 0);
      }
  }
  