1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.telecom; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SuppressLint; 22 import android.annotation.SystemApi; 23 import android.annotation.TestApi; 24 import android.net.Uri; 25 import android.os.Bundle; 26 import android.os.Parcel; 27 import android.os.ParcelFileDescriptor; 28 import android.os.Parcelable; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 33 /** 34 * Simple data container encapsulating a request to some entity to 35 * create a new {@link Connection}. 36 */ 37 public final class ConnectionRequest implements Parcelable { 38 39 /** 40 * Builder class for {@link ConnectionRequest} 41 * @hide 42 */ 43 @TestApi // For convenience in CTS tests 44 public static final class Builder { 45 private PhoneAccountHandle mAccountHandle; 46 private Uri mAddress; 47 private Bundle mExtras; 48 private int mVideoState = VideoProfile.STATE_AUDIO_ONLY; 49 private String mTelecomCallId; 50 private boolean mShouldShowIncomingCallUi = false; 51 private ParcelFileDescriptor mRttPipeToInCall; 52 private ParcelFileDescriptor mRttPipeFromInCall; 53 private List<Uri> mParticipants; 54 private boolean mIsAdhocConference = false; 55 Builder()56 public Builder() { } 57 58 /** 59 * Sets the phone account handle for the resulting {@link ConnectionRequest} 60 * @param accountHandle The accountHandle which should be used to place the call. 61 */ setAccountHandle(@onNull PhoneAccountHandle accountHandle)62 public @NonNull Builder setAccountHandle(@NonNull PhoneAccountHandle accountHandle) { 63 this.mAccountHandle = accountHandle; 64 return this; 65 } 66 67 /** 68 * Sets the participants for the resulting {@link ConnectionRequest} 69 * @param participants The participants to which the {@link Connection} is to connect. 70 */ setParticipants( @uppressLint"NullableCollection") @ullable List<Uri> participants)71 public @NonNull Builder setParticipants( 72 @SuppressLint("NullableCollection") @Nullable List<Uri> participants) { 73 this.mParticipants = participants; 74 return this; 75 } 76 77 /** 78 * Sets the address for the resulting {@link ConnectionRequest} 79 * @param address The address(e.g., phone number) to which the {@link Connection} is to 80 * connect. 81 */ setAddress(@onNull Uri address)82 public @NonNull Builder setAddress(@NonNull Uri address) { 83 this.mAddress = address; 84 return this; 85 } 86 87 /** 88 * Sets the extras bundle for the resulting {@link ConnectionRequest} 89 * @param extras Application-specific extra data. 90 */ setExtras(@onNull Bundle extras)91 public @NonNull Builder setExtras(@NonNull Bundle extras) { 92 this.mExtras = extras; 93 return this; 94 } 95 96 /** 97 * Sets the video state for the resulting {@link ConnectionRequest} 98 * @param videoState Determines the video state for the connection. 99 */ setVideoState(int videoState)100 public @NonNull Builder setVideoState(int videoState) { 101 this.mVideoState = videoState; 102 return this; 103 } 104 105 /** 106 * Sets the Telecom call ID for the resulting {@link ConnectionRequest} 107 * @param telecomCallId The telecom call ID. 108 */ setTelecomCallId(@onNull String telecomCallId)109 public @NonNull Builder setTelecomCallId(@NonNull String telecomCallId) { 110 this.mTelecomCallId = telecomCallId; 111 return this; 112 } 113 114 /** 115 * Sets shouldShowIncomingUi for the resulting {@link ConnectionRequest} 116 * @param shouldShowIncomingCallUi For a self-managed {@link ConnectionService}, will be 117 * {@code true} if the {@link ConnectionService} should show 118 * its own incoming call UI for an incoming call. When 119 * {@code false}, Telecom shows the incoming call UI. 120 */ setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi)121 public @NonNull Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) { 122 this.mShouldShowIncomingCallUi = shouldShowIncomingCallUi; 123 return this; 124 } 125 126 /** 127 * Sets isAdhocConference for the resulting {@link ConnectionRequest} 128 * @param isAdhocConference {@code true} if it is a adhoc conference call 129 * {@code false}, if not a adhoc conference call 130 */ setIsAdhocConferenceCall(boolean isAdhocConference)131 public @NonNull Builder setIsAdhocConferenceCall(boolean isAdhocConference) { 132 this.mIsAdhocConference = isAdhocConference; 133 return this; 134 } 135 136 /** 137 * Sets the RTT pipe for transferring text into the {@link ConnectionService} for the 138 * resulting {@link ConnectionRequest} 139 * @param rttPipeFromInCall The data pipe to read from. 140 */ setRttPipeFromInCall( @onNull ParcelFileDescriptor rttPipeFromInCall)141 public @NonNull Builder setRttPipeFromInCall( 142 @NonNull ParcelFileDescriptor rttPipeFromInCall) { 143 this.mRttPipeFromInCall = rttPipeFromInCall; 144 return this; 145 } 146 147 /** 148 * Sets the RTT pipe for transferring text out of {@link ConnectionService} for the 149 * resulting {@link ConnectionRequest} 150 * @param rttPipeToInCall The data pipe to write to. 151 */ setRttPipeToInCall(@onNull ParcelFileDescriptor rttPipeToInCall)152 public @NonNull Builder setRttPipeToInCall(@NonNull ParcelFileDescriptor rttPipeToInCall) { 153 this.mRttPipeToInCall = rttPipeToInCall; 154 return this; 155 } 156 157 /** 158 * Build the {@link ConnectionRequest} 159 * @return Result of the builder 160 */ build()161 public @NonNull ConnectionRequest build() { 162 return new ConnectionRequest( 163 mAccountHandle, 164 mAddress, 165 mExtras, 166 mVideoState, 167 mTelecomCallId, 168 mShouldShowIncomingCallUi, 169 mRttPipeFromInCall, 170 mRttPipeToInCall, 171 mParticipants, 172 mIsAdhocConference); 173 } 174 } 175 176 private final PhoneAccountHandle mAccountHandle; 177 private final Uri mAddress; 178 private final Bundle mExtras; 179 private final int mVideoState; 180 private final String mTelecomCallId; 181 private final boolean mShouldShowIncomingCallUi; 182 private final ParcelFileDescriptor mRttPipeToInCall; 183 private final ParcelFileDescriptor mRttPipeFromInCall; 184 // Cached return value of getRttTextStream -- we don't want to wrap it more than once. 185 private Connection.RttTextStream mRttTextStream; 186 private List<Uri> mParticipants; 187 private final boolean mIsAdhocConference; 188 189 /** 190 * @param accountHandle The accountHandle which should be used to place the call. 191 * @param handle The handle (e.g., phone number) to which the {@link Connection} is to connect. 192 * @param extras Application-specific extra data. 193 */ ConnectionRequest( PhoneAccountHandle accountHandle, Uri handle, Bundle extras)194 public ConnectionRequest( 195 PhoneAccountHandle accountHandle, 196 Uri handle, 197 Bundle extras) { 198 this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false, null, null); 199 } 200 201 /** 202 * @param accountHandle The accountHandle which should be used to place the call. 203 * @param handle The handle (e.g., phone number) to which the {@link Connection} is to connect. 204 * @param extras Application-specific extra data. 205 * @param videoState Determines the video state for the connection. 206 */ ConnectionRequest( PhoneAccountHandle accountHandle, Uri handle, Bundle extras, int videoState)207 public ConnectionRequest( 208 PhoneAccountHandle accountHandle, 209 Uri handle, 210 Bundle extras, 211 int videoState) { 212 this(accountHandle, handle, extras, videoState, null, false, null, null); 213 } 214 215 /** 216 * @param accountHandle The accountHandle which should be used to place the call. 217 * @param handle The handle (e.g., phone number) to which the {@link Connection} is to connect. 218 * @param extras Application-specific extra data. 219 * @param videoState Determines the video state for the connection. 220 * @param telecomCallId The telecom call ID. 221 * @param shouldShowIncomingCallUi For a self-managed {@link ConnectionService}, will be 222 * {@code true} if the {@link ConnectionService} should show its 223 * own incoming call UI for an incoming call. When 224 * {@code false}, Telecom shows the incoming call UI. 225 * @hide 226 */ ConnectionRequest( PhoneAccountHandle accountHandle, Uri handle, Bundle extras, int videoState, String telecomCallId, boolean shouldShowIncomingCallUi)227 public ConnectionRequest( 228 PhoneAccountHandle accountHandle, 229 Uri handle, 230 Bundle extras, 231 int videoState, 232 String telecomCallId, 233 boolean shouldShowIncomingCallUi) { 234 this(accountHandle, handle, extras, videoState, telecomCallId, 235 shouldShowIncomingCallUi, null, null); 236 } 237 ConnectionRequest( PhoneAccountHandle accountHandle, Uri handle, Bundle extras, int videoState, String telecomCallId, boolean shouldShowIncomingCallUi, ParcelFileDescriptor rttPipeFromInCall, ParcelFileDescriptor rttPipeToInCall)238 private ConnectionRequest( 239 PhoneAccountHandle accountHandle, 240 Uri handle, 241 Bundle extras, 242 int videoState, 243 String telecomCallId, 244 boolean shouldShowIncomingCallUi, 245 ParcelFileDescriptor rttPipeFromInCall, 246 ParcelFileDescriptor rttPipeToInCall) { 247 this(accountHandle, handle, extras, videoState, telecomCallId, 248 shouldShowIncomingCallUi, rttPipeFromInCall, rttPipeToInCall, null, false); 249 } 250 ConnectionRequest( PhoneAccountHandle accountHandle, Uri handle, Bundle extras, int videoState, String telecomCallId, boolean shouldShowIncomingCallUi, ParcelFileDescriptor rttPipeFromInCall, ParcelFileDescriptor rttPipeToInCall, List<Uri> participants, boolean isAdhocConference)251 private ConnectionRequest( 252 PhoneAccountHandle accountHandle, 253 Uri handle, 254 Bundle extras, 255 int videoState, 256 String telecomCallId, 257 boolean shouldShowIncomingCallUi, 258 ParcelFileDescriptor rttPipeFromInCall, 259 ParcelFileDescriptor rttPipeToInCall, 260 List<Uri> participants, 261 boolean isAdhocConference) { 262 mAccountHandle = accountHandle; 263 mAddress = handle; 264 mExtras = extras; 265 mVideoState = videoState; 266 mTelecomCallId = telecomCallId; 267 mShouldShowIncomingCallUi = shouldShowIncomingCallUi; 268 mRttPipeFromInCall = rttPipeFromInCall; 269 mRttPipeToInCall = rttPipeToInCall; 270 mParticipants = participants; 271 mIsAdhocConference = isAdhocConference; 272 } 273 ConnectionRequest(Parcel in)274 private ConnectionRequest(Parcel in) { 275 mAccountHandle = in.readParcelable(getClass().getClassLoader(), android.telecom.PhoneAccountHandle.class); 276 mAddress = in.readParcelable(getClass().getClassLoader(), android.net.Uri.class); 277 mExtras = in.readParcelable(getClass().getClassLoader(), android.os.Bundle.class); 278 mVideoState = in.readInt(); 279 mTelecomCallId = in.readString(); 280 mShouldShowIncomingCallUi = in.readInt() == 1; 281 mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader(), android.os.ParcelFileDescriptor.class); 282 mRttPipeToInCall = in.readParcelable(getClass().getClassLoader(), android.os.ParcelFileDescriptor.class); 283 284 mParticipants = new ArrayList<Uri>(); 285 in.readList(mParticipants, getClass().getClassLoader(), android.net.Uri.class); 286 287 mIsAdhocConference = in.readInt() == 1; 288 } 289 290 /** 291 * The account which should be used to place the call. 292 */ getAccountHandle()293 public PhoneAccountHandle getAccountHandle() { return mAccountHandle; } 294 295 /** 296 * The handle (e.g., phone number) to which the {@link Connection} is to connect. 297 */ getAddress()298 public Uri getAddress() { return mAddress; } 299 300 /** 301 * The participants to which the {@link Connection} is to connect. 302 */ getParticipants()303 public @Nullable List<Uri> getParticipants() { return mParticipants; } 304 305 /** 306 * Application-specific extra data. Used for passing back information from an incoming 307 * call {@code Intent}, and for any proprietary extensions arranged between a client 308 * and servant {@code ConnectionService} which agree on a vocabulary for such data. 309 */ getExtras()310 public Bundle getExtras() { return mExtras; } 311 312 /** 313 * Describes the video states supported by the client requesting the connection. 314 * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY}, 315 * {@link VideoProfile#STATE_BIDIRECTIONAL}, 316 * {@link VideoProfile#STATE_TX_ENABLED}, 317 * {@link VideoProfile#STATE_RX_ENABLED}. 318 * 319 * @return The video state for the connection. 320 */ getVideoState()321 public int getVideoState() { 322 return mVideoState; 323 } 324 325 /** 326 * Returns the internal Telecom ID associated with the connection request. 327 * 328 * @return The Telecom ID. 329 * @hide 330 */ 331 @SystemApi getTelecomCallId()332 public @Nullable String getTelecomCallId() { 333 return mTelecomCallId; 334 } 335 336 /** 337 * For a self-managed {@link ConnectionService}, indicates for an incoming call whether the 338 * {@link ConnectionService} should show its own incoming call UI for an incoming call. 339 * 340 * @return {@code true} if the {@link ConnectionService} should show its own incoming call UI. 341 * When {@code false}, Telecom shows the incoming call UI for the call. 342 * @hide 343 */ shouldShowIncomingCallUi()344 public boolean shouldShowIncomingCallUi() { 345 return mShouldShowIncomingCallUi; 346 } 347 348 /** 349 * @return {@code true} if the call is a adhoc conference call else @return {@code false} 350 */ isAdhocConferenceCall()351 public boolean isAdhocConferenceCall() { 352 return mIsAdhocConference; 353 } 354 355 /** 356 * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the connection 357 * service to the in-call UI. In order to obtain an 358 * {@link java.io.InputStream} from this {@link ParcelFileDescriptor}, use 359 * {@link android.os.ParcelFileDescriptor.AutoCloseInputStream}. 360 * Only text data encoded using UTF-8 should be written into this {@link ParcelFileDescriptor}. 361 * @return The {@link ParcelFileDescriptor} that should be used for communication. 362 * Do not un-hide -- only for use by Telephony 363 * @hide 364 */ getRttPipeToInCall()365 public ParcelFileDescriptor getRttPipeToInCall() { 366 return mRttPipeToInCall; 367 } 368 369 /** 370 * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the in-call UI to 371 * the connection service. In order to obtain an 372 * {@link java.io.OutputStream} from this {@link ParcelFileDescriptor}, use 373 * {@link android.os.ParcelFileDescriptor.AutoCloseOutputStream}. 374 * The contents of this {@link ParcelFileDescriptor} will consist solely of text encoded in 375 * UTF-8. 376 * @return The {@link ParcelFileDescriptor} that should be used for communication 377 * Do not un-hide -- only for use by Telephony 378 * @hide 379 */ getRttPipeFromInCall()380 public ParcelFileDescriptor getRttPipeFromInCall() { 381 return mRttPipeFromInCall; 382 } 383 384 /** 385 * Gets the {@link android.telecom.Connection.RttTextStream} object that should be used to 386 * send and receive RTT text to/from the in-call app. 387 * @return An instance of {@link android.telecom.Connection.RttTextStream}, or {@code null} 388 * if this connection request is not requesting an RTT session upon connection establishment. 389 */ getRttTextStream()390 public Connection.RttTextStream getRttTextStream() { 391 if (isRequestingRtt()) { 392 if (mRttTextStream == null) { 393 mRttTextStream = new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall); 394 } 395 return mRttTextStream; 396 } else { 397 return null; 398 } 399 } 400 401 /** 402 * Convenience method for determining whether the ConnectionRequest is requesting an RTT session 403 * @return {@code true} if RTT is requested, {@code false} otherwise. 404 */ isRequestingRtt()405 public boolean isRequestingRtt() { 406 return mRttPipeFromInCall != null && mRttPipeToInCall != null; 407 } 408 409 @Override toString()410 public String toString() { 411 return String.format("ConnectionRequest %s %s isAdhocConf: %s", 412 mAddress == null 413 ? Uri.EMPTY 414 : Connection.toLogSafePhoneNumber(mAddress.toString()), 415 bundleToString(mExtras), 416 isAdhocConferenceCall() ? "Y" : "N"); 417 } 418 bundleToString(Bundle extras)419 private static String bundleToString(Bundle extras){ 420 if (extras == null) { 421 return ""; 422 } 423 StringBuilder sb = new StringBuilder(); 424 sb.append("Bundle["); 425 for (String key : extras.keySet()) { 426 sb.append(key); 427 sb.append("="); 428 switch (key) { 429 case TelecomManager.EXTRA_INCOMING_CALL_ADDRESS: 430 case TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE: 431 sb.append(Log.pii(extras.get(key))); 432 break; 433 default: 434 sb.append(extras.get(key)); 435 break; 436 } 437 sb.append(", "); 438 } 439 sb.append("]"); 440 return sb.toString(); 441 } 442 443 public static final @android.annotation.NonNull Creator<ConnectionRequest> CREATOR = new Creator<ConnectionRequest> () { 444 @Override 445 public ConnectionRequest createFromParcel(Parcel source) { 446 return new ConnectionRequest(source); 447 } 448 449 @Override 450 public ConnectionRequest[] newArray(int size) { 451 return new ConnectionRequest[size]; 452 } 453 }; 454 455 /** 456 * {@inheritDoc} 457 */ 458 @Override describeContents()459 public int describeContents() { 460 return 0; 461 } 462 463 @Override writeToParcel(Parcel destination, int flags)464 public void writeToParcel(Parcel destination, int flags) { 465 destination.writeParcelable(mAccountHandle, 0); 466 destination.writeParcelable(mAddress, 0); 467 destination.writeParcelable(mExtras, 0); 468 destination.writeInt(mVideoState); 469 destination.writeString(mTelecomCallId); 470 destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0); 471 destination.writeParcelable(mRttPipeFromInCall, 0); 472 destination.writeParcelable(mRttPipeToInCall, 0); 473 destination.writeList(mParticipants); 474 destination.writeInt(mIsAdhocConference ? 1 : 0); 475 } 476 } 477