1 /* 2 * Copyright (C) 2018 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.telephony.ims; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.net.Uri; 24 import android.os.Build; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.HashSet; 33 import java.util.List; 34 import java.util.Set; 35 36 /** 37 * Contains the User Capability Exchange capabilities corresponding to a contact's URI. 38 * @hide 39 */ 40 @SystemApi 41 public final class RcsContactUceCapability implements Parcelable { 42 43 /** Contains presence information associated with the contact */ 44 public static final int CAPABILITY_MECHANISM_PRESENCE = 1; 45 46 /** Contains OPTIONS information associated with the contact */ 47 public static final int CAPABILITY_MECHANISM_OPTIONS = 2; 48 49 /** @hide */ 50 @Retention(RetentionPolicy.SOURCE) 51 @IntDef(prefix = "CAPABILITY_MECHANISM_", value = { 52 CAPABILITY_MECHANISM_PRESENCE, 53 CAPABILITY_MECHANISM_OPTIONS 54 }) 55 public @interface CapabilityMechanism {} 56 57 /** 58 * The capabilities of this contact were requested recently enough to still be considered in 59 * the availability window. 60 */ 61 public static final int SOURCE_TYPE_NETWORK = 0; 62 63 /** 64 * The capabilities of this contact were retrieved from the cached information in the Enhanced 65 * Address Book. 66 */ 67 public static final int SOURCE_TYPE_CACHED = 1; 68 69 /** @hide */ 70 @Retention(RetentionPolicy.SOURCE) 71 @IntDef(prefix = "SOURCE_TYPE_", value = { 72 SOURCE_TYPE_NETWORK, 73 SOURCE_TYPE_CACHED 74 }) 75 public @interface SourceType {} 76 77 /** 78 * Capability information for the requested contact has expired and can not be refreshed due to 79 * a temporary network error. This is a temporary error and the capabilities of the contact 80 * should be queried again at a later time. 81 */ 82 public static final int REQUEST_RESULT_UNKNOWN = 0; 83 84 /** 85 * The requested contact was found to be offline when queried. This is only applicable to 86 * contact capabilities that were queried via OPTIONS requests and the network returned a 87 * 408/480 response. 88 */ 89 public static final int REQUEST_RESULT_NOT_ONLINE = 1; 90 91 /** 92 * Capability information for the requested contact was not found. The contact should not be 93 * considered an RCS user. 94 */ 95 public static final int REQUEST_RESULT_NOT_FOUND = 2; 96 97 /** 98 * Capability information for the requested contact was found successfully. 99 */ 100 public static final int REQUEST_RESULT_FOUND = 3; 101 102 /** @hide */ 103 @Retention(RetentionPolicy.SOURCE) 104 @IntDef(prefix = "REQUEST_RESULT_", value = { 105 REQUEST_RESULT_UNKNOWN, 106 REQUEST_RESULT_NOT_ONLINE, 107 REQUEST_RESULT_NOT_FOUND, 108 REQUEST_RESULT_FOUND 109 }) 110 public @interface RequestResult {} 111 112 /** 113 * Builder to help construct {@link RcsContactUceCapability} instances when capabilities were 114 * queried through SIP OPTIONS. 115 */ 116 public static final class OptionsBuilder { 117 118 private final RcsContactUceCapability mCapabilities; 119 120 /** 121 * Create the Builder, which can be used to set UCE capabilities as well as custom 122 * capability extensions. 123 * @param contact The contact URI that the capabilities are attached to. 124 */ OptionsBuilder(@onNull Uri contact)125 public OptionsBuilder(@NonNull Uri contact) { 126 mCapabilities = new RcsContactUceCapability(contact, CAPABILITY_MECHANISM_OPTIONS, 127 SOURCE_TYPE_NETWORK); 128 } 129 130 /** 131 * Create the Builder, which can be used to set UCE capabilities as well as custom 132 * capability extensions. 133 * @param contact The contact URI that the capabilities are attached to. 134 * @param sourceType The type where the capabilities of this contact were retrieved from. 135 * @hide 136 */ OptionsBuilder(@onNull Uri contact, @SourceType int sourceType)137 public OptionsBuilder(@NonNull Uri contact, @SourceType int sourceType) { 138 mCapabilities = new RcsContactUceCapability(contact, CAPABILITY_MECHANISM_OPTIONS, 139 sourceType); 140 } 141 142 /** 143 * Set the result of the capabilities request. 144 * @param requestResult the request result 145 * @return this OptionBuilder 146 */ setRequestResult(@equestResult int requestResult)147 public @NonNull OptionsBuilder setRequestResult(@RequestResult int requestResult) { 148 mCapabilities.mRequestResult = requestResult; 149 return this; 150 } 151 152 /** 153 * Add the feature tag into the capabilities instance. 154 * @param tag the supported feature tag 155 * @return this OptionBuilder 156 */ addFeatureTag(@onNull String tag)157 public @NonNull OptionsBuilder addFeatureTag(@NonNull String tag) { 158 mCapabilities.mFeatureTags.add(tag); 159 return this; 160 } 161 162 /** 163 * Add the list of feature tag into the capabilities instance. 164 * @param tags the list of the supported feature tags 165 * @return this OptionBuilder 166 */ addFeatureTags(@onNull Set<String> tags)167 public @NonNull OptionsBuilder addFeatureTags(@NonNull Set<String> tags) { 168 mCapabilities.mFeatureTags.addAll(tags); 169 return this; 170 } 171 172 /** 173 * @return the constructed instance. 174 */ build()175 public @NonNull RcsContactUceCapability build() { 176 return mCapabilities; 177 } 178 } 179 180 /** 181 * Builder to help construct {@link RcsContactUceCapability} instances when capabilities were 182 * queried through a presence server. 183 */ 184 public static final class PresenceBuilder { 185 186 private final RcsContactUceCapability mCapabilities; 187 188 /** 189 * Create the builder, which can be used to set UCE capabilities as well as custom 190 * capability extensions. 191 * @param contact The contact URI that the capabilities are attached to. 192 * @param sourceType The type where the capabilities of this contact were retrieved from. 193 * @param requestResult the request result 194 */ PresenceBuilder(@onNull Uri contact, @SourceType int sourceType, @RequestResult int requestResult)195 public PresenceBuilder(@NonNull Uri contact, @SourceType int sourceType, 196 @RequestResult int requestResult) { 197 mCapabilities = new RcsContactUceCapability(contact, CAPABILITY_MECHANISM_PRESENCE, 198 sourceType); 199 mCapabilities.mRequestResult = requestResult; 200 } 201 202 /** 203 * Add the {@link RcsContactPresenceTuple} into the capabilities instance. 204 * @param tuple The {@link RcsContactPresenceTuple} to be added into. 205 * @return this PresenceBuilder 206 */ addCapabilityTuple(@onNull RcsContactPresenceTuple tuple)207 public @NonNull PresenceBuilder addCapabilityTuple(@NonNull RcsContactPresenceTuple tuple) { 208 mCapabilities.mPresenceTuples.add(tuple); 209 return this; 210 } 211 212 /** 213 * Add the list of {@link RcsContactPresenceTuple} into the capabilities instance. 214 * @param tuples The list of the {@link RcsContactPresenceTuple} to be added into. 215 * @return this PresenceBuilder 216 */ addCapabilityTuples( @onNull List<RcsContactPresenceTuple> tuples)217 public @NonNull PresenceBuilder addCapabilityTuples( 218 @NonNull List<RcsContactPresenceTuple> tuples) { 219 mCapabilities.mPresenceTuples.addAll(tuples); 220 return this; 221 } 222 223 /** 224 * Set the entity URI related to the contact whose capabilities were requested. 225 * @param entityUri the 'pres' URL of the PRESENTITY publishing presence document. 226 */ setEntityUri(@onNull Uri entityUri)227 public @NonNull PresenceBuilder setEntityUri(@NonNull Uri entityUri) { 228 mCapabilities.mEntityUri = entityUri; 229 return this; 230 } 231 232 /** 233 * @return the RcsContactUceCapability instance. 234 */ build()235 public @NonNull RcsContactUceCapability build() { 236 return mCapabilities; 237 } 238 } 239 240 private final Uri mContactUri; 241 private @SourceType int mSourceType; 242 private @CapabilityMechanism int mCapabilityMechanism; 243 private @RequestResult int mRequestResult; 244 private Uri mEntityUri; 245 246 private final Set<String> mFeatureTags = new HashSet<>(); 247 private final List<RcsContactPresenceTuple> mPresenceTuples = new ArrayList<>(); 248 RcsContactUceCapability(@onNull Uri contactUri, @CapabilityMechanism int mechanism, @SourceType int sourceType)249 private RcsContactUceCapability(@NonNull Uri contactUri, @CapabilityMechanism int mechanism, 250 @SourceType int sourceType) { 251 mContactUri = contactUri; 252 mCapabilityMechanism = mechanism; 253 mSourceType = sourceType; 254 } 255 RcsContactUceCapability(Parcel in)256 private RcsContactUceCapability(Parcel in) { 257 mContactUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class); 258 mCapabilityMechanism = in.readInt(); 259 mSourceType = in.readInt(); 260 mRequestResult = in.readInt(); 261 mEntityUri = in.readParcelable(Uri.class.getClassLoader(), android.net.Uri.class); 262 List<String> featureTagList = new ArrayList<>(); 263 in.readStringList(featureTagList); 264 mFeatureTags.addAll(featureTagList); 265 in.readParcelableList(mPresenceTuples, RcsContactPresenceTuple.class.getClassLoader(), android.telephony.ims.RcsContactPresenceTuple.class); 266 } 267 268 @Override writeToParcel(@onNull Parcel out, int flags)269 public void writeToParcel(@NonNull Parcel out, int flags) { 270 out.writeParcelable(mContactUri, flags); 271 out.writeInt(mCapabilityMechanism); 272 out.writeInt(mSourceType); 273 out.writeInt(mRequestResult); 274 out.writeParcelable(mEntityUri, flags); 275 out.writeStringList(new ArrayList<>(mFeatureTags)); 276 out.writeParcelableList(mPresenceTuples, flags); 277 } 278 279 @Override describeContents()280 public int describeContents() { 281 return 0; 282 } 283 284 public static final @NonNull Creator<RcsContactUceCapability> CREATOR = 285 new Creator<RcsContactUceCapability>() { 286 @Override 287 public RcsContactUceCapability createFromParcel(Parcel in) { 288 return new RcsContactUceCapability(in); 289 } 290 291 @Override 292 public RcsContactUceCapability[] newArray(int size) { 293 return new RcsContactUceCapability[size]; 294 } 295 }; 296 297 /** 298 * @return The mechanism used to get the capabilities. 299 */ getCapabilityMechanism()300 public @CapabilityMechanism int getCapabilityMechanism() { 301 return mCapabilityMechanism; 302 } 303 304 /** 305 * @return The feature tags present in the OPTIONS response from the network. 306 * <p> 307 * Note: this is only populated if {@link #getCapabilityMechanism} is 308 * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS} 309 */ getFeatureTags()310 public @NonNull Set<String> getFeatureTags() { 311 if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) { 312 return Collections.emptySet(); 313 } 314 return Collections.unmodifiableSet(mFeatureTags); 315 } 316 317 /** 318 * @return The tuple elements associated with the presence element portion of the PIDF document 319 * contained in the NOTIFY response from the network. 320 * <p> 321 * Note: this is only populated if {@link #getCapabilityMechanism} is 322 * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE} 323 */ getCapabilityTuples()324 public @NonNull List<RcsContactPresenceTuple> getCapabilityTuples() { 325 if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) { 326 return Collections.emptyList(); 327 } 328 return Collections.unmodifiableList(mPresenceTuples); 329 } 330 331 /** 332 * Get the RcsContactPresenceTuple associated with the given service id. 333 * @param serviceId The service id to get the presence tuple. 334 * @return The RcsContactPresenceTuple which has the given service id or {@code null} if the 335 * service id does not exist in the list of presence tuples returned from the network. 336 * 337 * <p> 338 * Note: this is only populated if {@link #getCapabilityMechanism} is 339 * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE} 340 */ getCapabilityTuple(@onNull String serviceId)341 public @Nullable RcsContactPresenceTuple getCapabilityTuple(@NonNull String serviceId) { 342 if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) { 343 return null; 344 } 345 for (RcsContactPresenceTuple tuple : mPresenceTuples) { 346 if (tuple.getServiceId() != null && tuple.getServiceId().equals(serviceId)) { 347 return tuple; 348 } 349 } 350 return null; 351 } 352 353 /** 354 * @return the source of the data that was used to populate the capabilities of the requested 355 * contact. 356 */ getSourceType()357 public @SourceType int getSourceType() { 358 return mSourceType; 359 } 360 361 /** 362 * @return the result of querying the capabilities of the requested contact. 363 */ getRequestResult()364 public @RequestResult int getRequestResult() { 365 return mRequestResult; 366 } 367 368 /** 369 * Retrieve the contact URI requested by the applications. 370 * @return the URI representing the contact associated with the capabilities. 371 */ getContactUri()372 public @NonNull Uri getContactUri() { 373 return mContactUri; 374 } 375 376 /** 377 * Retrieve the entity URI of the contact whose presence information is being requested for. 378 * @return the URI representing the 'pres' URL of the PRESENTITY publishing presence document 379 * or {@code null} if the entity uri does not exist in the presence document. 380 */ getEntityUri()381 public @Nullable Uri getEntityUri() { 382 return mEntityUri; 383 } 384 385 @Override toString()386 public String toString() { 387 StringBuilder builder = new StringBuilder("RcsContactUceCapability"); 388 if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) { 389 builder.append("(presence) {"); 390 } else if (mCapabilityMechanism == CAPABILITY_MECHANISM_OPTIONS) { 391 builder.append("(options) {"); 392 } else { 393 builder.append("(?) {"); 394 } 395 if (Build.IS_ENG) { 396 builder.append("uri="); 397 builder.append(mContactUri); 398 } else { 399 builder.append("uri (isNull)="); 400 builder.append(mContactUri != null ? "XXX" : "null"); 401 } 402 builder.append(", sourceType="); 403 builder.append(mSourceType); 404 builder.append(", requestResult="); 405 builder.append(mRequestResult); 406 if (Build.IS_ENG) { 407 builder.append("entity uri="); 408 builder.append(mEntityUri != null ? mEntityUri : "null"); 409 } else { 410 builder.append("entity uri (isNull)="); 411 builder.append(mEntityUri != null ? "XXX" : "null"); 412 } 413 414 if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) { 415 builder.append(", presenceTuples={"); 416 builder.append(mPresenceTuples); 417 builder.append("}"); 418 } else if (mCapabilityMechanism == CAPABILITY_MECHANISM_OPTIONS) { 419 builder.append(", featureTags={"); 420 builder.append(mFeatureTags); 421 builder.append("}"); 422 } 423 424 return builder.toString(); 425 } 426 } 427