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 * @return the RcsContactUceCapability instance. 225 */ build()226 public @NonNull RcsContactUceCapability build() { 227 return mCapabilities; 228 } 229 } 230 231 private final Uri mContactUri; 232 private @SourceType int mSourceType; 233 private @CapabilityMechanism int mCapabilityMechanism; 234 private @RequestResult int mRequestResult; 235 236 private final Set<String> mFeatureTags = new HashSet<>(); 237 private final List<RcsContactPresenceTuple> mPresenceTuples = new ArrayList<>(); 238 RcsContactUceCapability(@onNull Uri contactUri, @CapabilityMechanism int mechanism, @SourceType int sourceType)239 private RcsContactUceCapability(@NonNull Uri contactUri, @CapabilityMechanism int mechanism, 240 @SourceType int sourceType) { 241 mContactUri = contactUri; 242 mCapabilityMechanism = mechanism; 243 mSourceType = sourceType; 244 } 245 RcsContactUceCapability(Parcel in)246 private RcsContactUceCapability(Parcel in) { 247 mContactUri = in.readParcelable(Uri.class.getClassLoader()); 248 mCapabilityMechanism = in.readInt(); 249 mSourceType = in.readInt(); 250 mRequestResult = in.readInt(); 251 List<String> featureTagList = new ArrayList<>(); 252 in.readStringList(featureTagList); 253 mFeatureTags.addAll(featureTagList); 254 in.readParcelableList(mPresenceTuples, RcsContactPresenceTuple.class.getClassLoader()); 255 } 256 257 @Override writeToParcel(@onNull Parcel out, int flags)258 public void writeToParcel(@NonNull Parcel out, int flags) { 259 out.writeParcelable(mContactUri, flags); 260 out.writeInt(mCapabilityMechanism); 261 out.writeInt(mSourceType); 262 out.writeInt(mRequestResult); 263 out.writeStringList(new ArrayList<>(mFeatureTags)); 264 out.writeParcelableList(mPresenceTuples, flags); 265 } 266 267 @Override describeContents()268 public int describeContents() { 269 return 0; 270 } 271 272 public static final @NonNull Creator<RcsContactUceCapability> CREATOR = 273 new Creator<RcsContactUceCapability>() { 274 @Override 275 public RcsContactUceCapability createFromParcel(Parcel in) { 276 return new RcsContactUceCapability(in); 277 } 278 279 @Override 280 public RcsContactUceCapability[] newArray(int size) { 281 return new RcsContactUceCapability[size]; 282 } 283 }; 284 285 /** 286 * @return The mechanism used to get the capabilities. 287 */ getCapabilityMechanism()288 public @CapabilityMechanism int getCapabilityMechanism() { 289 return mCapabilityMechanism; 290 } 291 292 /** 293 * @return The feature tags present in the OPTIONS response from the network. 294 * <p> 295 * Note: this is only populated if {@link #getCapabilityMechanism} is 296 * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS} 297 */ getFeatureTags()298 public @NonNull Set<String> getFeatureTags() { 299 if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) { 300 return Collections.emptySet(); 301 } 302 return Collections.unmodifiableSet(mFeatureTags); 303 } 304 305 /** 306 * @return The tuple elements associated with the presence element portion of the PIDF document 307 * contained in the NOTIFY response from the network. 308 * <p> 309 * Note: this is only populated if {@link #getCapabilityMechanism} is 310 * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE} 311 */ getCapabilityTuples()312 public @NonNull List<RcsContactPresenceTuple> getCapabilityTuples() { 313 if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) { 314 return Collections.emptyList(); 315 } 316 return Collections.unmodifiableList(mPresenceTuples); 317 } 318 319 /** 320 * Get the RcsContactPresenceTuple associated with the given service id. 321 * @param serviceId The service id to get the presence tuple. 322 * @return The RcsContactPresenceTuple which has the given service id or {@code null} if the 323 * service id does not exist in the list of presence tuples returned from the network. 324 * 325 * <p> 326 * Note: this is only populated if {@link #getCapabilityMechanism} is 327 * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE} 328 */ getCapabilityTuple(@onNull String serviceId)329 public @Nullable RcsContactPresenceTuple getCapabilityTuple(@NonNull String serviceId) { 330 if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) { 331 return null; 332 } 333 for (RcsContactPresenceTuple tuple : mPresenceTuples) { 334 if (tuple.getServiceId() != null && tuple.getServiceId().equals(serviceId)) { 335 return tuple; 336 } 337 } 338 return null; 339 } 340 341 /** 342 * @return the source of the data that was used to populate the capabilities of the requested 343 * contact. 344 */ getSourceType()345 public @SourceType int getSourceType() { 346 return mSourceType; 347 } 348 349 /** 350 * @return the result of querying the capabilities of the requested contact. 351 */ getRequestResult()352 public @RequestResult int getRequestResult() { 353 return mRequestResult; 354 } 355 356 /** 357 * Retrieve the contact URI requested by the applications. 358 * @return the URI representing the contact associated with the capabilities. 359 */ getContactUri()360 public @NonNull Uri getContactUri() { 361 return mContactUri; 362 } 363 364 @Override toString()365 public String toString() { 366 StringBuilder builder = new StringBuilder("RcsContactUceCapability"); 367 if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) { 368 builder.append("(presence) {"); 369 } else if (mCapabilityMechanism == CAPABILITY_MECHANISM_OPTIONS) { 370 builder.append("(options) {"); 371 } else { 372 builder.append("(?) {"); 373 } 374 if (Build.IS_ENG) { 375 builder.append("uri="); 376 builder.append(mContactUri); 377 } else { 378 builder.append("uri (isNull)="); 379 builder.append(mContactUri != null ? "XXX" : "null"); 380 } 381 builder.append(", sourceType="); 382 builder.append(mSourceType); 383 builder.append(", requestResult="); 384 builder.append(mRequestResult); 385 386 if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) { 387 builder.append(", presenceTuples={"); 388 builder.append(mPresenceTuples); 389 builder.append("}"); 390 } else if (mCapabilityMechanism == CAPABILITY_MECHANISM_OPTIONS) { 391 builder.append(", featureTags={"); 392 builder.append(mFeatureTags); 393 builder.append("}"); 394 } 395 396 return builder.toString(); 397 } 398 } 399