1 /* 2 * Copyright (C) 2020 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 com.android.ims.rcs.uce.presence.pidfparser; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assert.fail; 25 26 import android.net.Uri; 27 import android.telephony.ims.RcsContactPresenceTuple; 28 import android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities; 29 import android.telephony.ims.RcsContactUceCapability; 30 import android.telephony.ims.RcsContactUceCapability.PresenceBuilder; 31 32 import androidx.test.ext.junit.runners.AndroidJUnit4; 33 import androidx.test.filters.SmallTest; 34 35 import com.android.ims.ImsTestBase; 36 37 import java.time.Instant; 38 import java.util.ArrayList; 39 import java.util.List; 40 41 import org.junit.After; 42 import org.junit.Before; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 import org.mockito.Mock; 46 47 @RunWith(AndroidJUnit4.class) 48 public class PidfParserTest extends ImsTestBase { 49 50 // The timestamp of the PIDF 51 private final Instant mPidfTimestamp = Instant.now().plusMillis(1); 52 53 @Before setUp()54 public void setUp() throws Exception { 55 super.setUp(); 56 PidfParser.setTimestampProxy(() -> mPidfTimestamp); 57 } 58 59 @After tearDown()60 public void tearDown() throws Exception { 61 super.tearDown(); 62 PidfParser.setTimestampProxy(null); 63 } 64 65 @Test 66 @SmallTest testConvertToPidf()67 public void testConvertToPidf() throws Exception { 68 RcsContactUceCapability capability = getRcsContactUceCapability(); 69 70 String pidfResult = PidfParser.convertToPidf(capability); 71 72 String contact = "<contact>sip:test</contact>"; 73 String audioSupported = "<caps:audio>true</caps:audio>"; 74 String videoSupported = "<caps:video>true</caps:video>"; 75 String description = "<op:version>1.0</op:version>"; 76 assertTrue(pidfResult.contains(contact)); 77 assertTrue(pidfResult.contains(audioSupported)); 78 assertTrue(pidfResult.contains(videoSupported)); 79 assertTrue(pidfResult.contains(description)); 80 } 81 82 @Test 83 @SmallTest testConvertFromPidfToRcsContactUceCapability()84 public void testConvertFromPidfToRcsContactUceCapability() throws Exception { 85 final String contact = "sip:+11234567890@test"; 86 final String serviceId = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel"; 87 final String serviceDescription = "MMTEL feature service"; 88 final boolean isAudioSupported = true; 89 final boolean isVideoSupported = false; 90 91 // Create the first PIDF data 92 String pidfData = getPidfData(contact, serviceId, serviceDescription, isAudioSupported, 93 isVideoSupported); 94 95 // Convert to the class RcsContactUceCapability 96 RcsContactUceCapabilityWrapper capabilitiesWrapper = 97 PidfParser.getRcsContactUceCapabilityWrapper(pidfData); 98 assertNotNull(capabilitiesWrapper); 99 RcsContactUceCapability capabilities = capabilitiesWrapper.toRcsContactUceCapability(); 100 assertNotNull(capabilities); 101 assertEquals(Uri.parse(contact), capabilities.getContactUri()); 102 assertEquals(Uri.parse(contact), capabilities.getEntityUri()); 103 assertEquals(RcsContactUceCapability.SOURCE_TYPE_NETWORK, capabilities.getSourceType()); 104 assertEquals(RcsContactUceCapability.CAPABILITY_MECHANISM_PRESENCE, 105 capabilities.getCapabilityMechanism()); 106 107 List<RcsContactPresenceTuple> presenceTupleList = capabilities.getCapabilityTuples(); 108 assertNotNull(presenceTupleList); 109 assertEquals(1, presenceTupleList.size()); 110 111 RcsContactPresenceTuple presenceTuple1 = presenceTupleList.get(0); 112 assertEquals(serviceId, presenceTuple1.getServiceId()); 113 assertEquals("1.0", presenceTuple1.getServiceVersion()); 114 assertEquals(serviceDescription, presenceTuple1.getServiceDescription()); 115 assertEquals(Uri.parse(contact), presenceTuple1.getContactUri()); 116 assertEquals(mPidfTimestamp.toString(), presenceTuple1.getTime().toString()); 117 assertTrue(presenceTuple1.getServiceCapabilities().isAudioCapable()); 118 assertFalse(presenceTuple1.getServiceCapabilities().isVideoCapable()); 119 } 120 121 @Test 122 @SmallTest testConvertFromNewlineIncludedPidfToRcsContactUceCapability()123 public void testConvertFromNewlineIncludedPidfToRcsContactUceCapability() throws Exception { 124 final String contact = "tel:+11234567890"; 125 126 final RcsContactPresenceTuple.Builder tuple1Builder = new RcsContactPresenceTuple.Builder( 127 "open", 128 "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcse.dp", 129 "1.0"); 130 tuple1Builder.setServiceDescription("DiscoveryPresence") 131 .setContactUri(Uri.parse(contact)); 132 133 final RcsContactPresenceTuple.Builder tuple2Builder = new RcsContactPresenceTuple.Builder( 134 "open", 135 "org.openmobilealliance:StandaloneMsg", 136 "2.0"); 137 tuple2Builder.setServiceDescription("StandaloneMsg") 138 .setContactUri(Uri.parse(contact)); 139 140 final RcsContactPresenceTuple.Builder tuple3Builder = new RcsContactPresenceTuple.Builder( 141 "open", 142 "org.openmobilealliance:ChatSession", 143 "2.0"); 144 tuple3Builder.setServiceDescription("Session Mode Messaging") 145 .setContactUri(Uri.parse(contact)); 146 147 final RcsContactPresenceTuple.Builder tuple4Builder = new RcsContactPresenceTuple.Builder( 148 "open", 149 "org.openmobilealliance:File-Transfer", 150 "1.0"); 151 tuple4Builder.setServiceDescription("File Transfer") 152 .setContactUri(Uri.parse(contact)); 153 154 final RcsContactPresenceTuple.Builder tuple5Builder = new RcsContactPresenceTuple.Builder( 155 "open", 156 "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel", 157 "1.0"); 158 tuple5Builder.setServiceDescription("VoLTE service"); 159 ServiceCapabilities.Builder capBuilder = new ServiceCapabilities.Builder(true, true); 160 tuple5Builder.setServiceCapabilities(capBuilder.build()) 161 .setContactUri(Uri.parse(contact)); 162 163 final List<RcsContactPresenceTuple> expectedTupleList = new ArrayList<>(5); 164 expectedTupleList.add(tuple1Builder.build()); 165 expectedTupleList.add(tuple2Builder.build()); 166 expectedTupleList.add(tuple3Builder.build()); 167 expectedTupleList.add(tuple4Builder.build()); 168 expectedTupleList.add(tuple5Builder.build()); 169 170 // Create the newline included PIDF data 171 String pidfData = getPidfDataWithNewlineAndWhitespaceCharacters(); 172 173 // Convert to the class RcsContactUceCapability 174 RcsContactUceCapabilityWrapper capabilitiesWrapper = 175 PidfParser.getRcsContactUceCapabilityWrapper(pidfData); 176 assertNotNull(capabilitiesWrapper); 177 RcsContactUceCapability capabilities = capabilitiesWrapper.toRcsContactUceCapability(); 178 179 assertNotNull(capabilities); 180 assertEquals(Uri.parse(contact), capabilities.getContactUri()); 181 assertEquals(Uri.parse(contact), capabilities.getEntityUri()); 182 assertEquals(RcsContactUceCapability.SOURCE_TYPE_NETWORK, capabilities.getSourceType()); 183 assertEquals(RcsContactUceCapability.CAPABILITY_MECHANISM_PRESENCE, 184 capabilities.getCapabilityMechanism()); 185 186 List<RcsContactPresenceTuple> presenceTupleList = capabilities.getCapabilityTuples(); 187 assertNotNull(presenceTupleList); 188 assertEquals(expectedTupleList.size(), presenceTupleList.size()); 189 190 for(RcsContactPresenceTuple tuple : presenceTupleList) { 191 String serviceId = tuple.getServiceId(); 192 RcsContactPresenceTuple expectedTuple = findTuple(serviceId, expectedTupleList); 193 if (expectedTuple == null) { 194 fail("The service ID is invalid"); 195 } 196 197 assertEquals(expectedTuple.getStatus(), tuple.getStatus()); 198 assertEquals(expectedTuple.getServiceVersion(), tuple.getServiceVersion()); 199 assertEquals(expectedTuple.getServiceDescription(), tuple.getServiceDescription()); 200 assertEquals(mPidfTimestamp, tuple.getTime()); 201 assertEquals(expectedTuple.getContactUri(), tuple.getContactUri()); 202 203 ServiceCapabilities expectedCap = expectedTuple.getServiceCapabilities(); 204 ServiceCapabilities resultCap = tuple.getServiceCapabilities(); 205 if (expectedCap != null) { 206 assertNotNull(resultCap); 207 assertEquals(expectedCap.isAudioCapable(), resultCap.isAudioCapable()); 208 assertEquals(expectedCap.isVideoCapable(), resultCap.isVideoCapable()); 209 } else { 210 assertNull(resultCap); 211 } 212 } 213 } 214 findTuple(String serviceId, List<RcsContactPresenceTuple> expectedTupleList)215 private RcsContactPresenceTuple findTuple(String serviceId, 216 List<RcsContactPresenceTuple> expectedTupleList) { 217 if (serviceId == null) { 218 return null; 219 } 220 for (RcsContactPresenceTuple tuple : expectedTupleList) { 221 if (serviceId.equalsIgnoreCase(tuple.getServiceId())) { 222 return tuple; 223 } 224 } 225 return null; 226 } 227 228 @Test 229 @SmallTest testConvertToRcsContactUceCapabilityForMultipleTuples()230 public void testConvertToRcsContactUceCapabilityForMultipleTuples() throws Exception { 231 final String contact = "sip:+11234567890@test"; 232 final String serviceId1 = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcse.dp"; 233 final String serviceDescription1 = "capabilities discovery"; 234 final String serviceId2 = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel"; 235 final String serviceDescription2 = "MMTEL feature service"; 236 final boolean isAudioSupported = true; 237 final boolean isVideoSupported = false; 238 239 // Create the PIDF data 240 String pidfData = getPidfDataWithMultiTuples(contact, serviceId1, serviceDescription1, 241 serviceId2, serviceDescription2, isAudioSupported, isVideoSupported); 242 243 // Convert to the class RcsContactUceCapability 244 RcsContactUceCapabilityWrapper capabilitiesWrapper = 245 PidfParser.getRcsContactUceCapabilityWrapper(pidfData); 246 assertNotNull(capabilitiesWrapper); 247 RcsContactUceCapability capabilities = capabilitiesWrapper.toRcsContactUceCapability(); 248 249 assertNotNull(capabilities); 250 assertEquals(Uri.parse(contact), capabilities.getContactUri()); 251 252 List<RcsContactPresenceTuple> presenceTupleList = capabilities.getCapabilityTuples(); 253 assertNotNull(presenceTupleList); 254 assertEquals(2, presenceTupleList.size()); 255 256 // Verify the first tuple information 257 RcsContactPresenceTuple presenceTuple1 = presenceTupleList.get(0); 258 assertEquals(serviceId1, presenceTuple1.getServiceId()); 259 assertEquals("1.0", presenceTuple1.getServiceVersion()); 260 assertEquals(serviceDescription1, presenceTuple1.getServiceDescription()); 261 assertEquals(Uri.parse(contact), presenceTuple1.getContactUri()); 262 assertEquals(mPidfTimestamp.toString(), presenceTuple1.getTime().toString()); 263 assertNull(presenceTuple1.getServiceCapabilities()); 264 265 // Verify the second tuple information 266 RcsContactPresenceTuple presenceTuple2 = presenceTupleList.get(1); 267 assertEquals(serviceId2, presenceTuple2.getServiceId()); 268 assertEquals("1.0", presenceTuple2.getServiceVersion()); 269 assertTrue(presenceTuple2.getServiceCapabilities().isAudioCapable()); 270 assertFalse(presenceTuple2.getServiceCapabilities().isVideoCapable()); 271 assertEquals(serviceDescription2, presenceTuple2.getServiceDescription()); 272 assertEquals(Uri.parse(contact), presenceTuple2.getContactUri()); 273 assertEquals(mPidfTimestamp.toString(), presenceTuple2.getTime().toString()); 274 assertNotNull(presenceTuple2.getServiceCapabilities()); 275 assertEquals(isAudioSupported, presenceTuple2.getServiceCapabilities().isAudioCapable()); 276 assertEquals(isVideoSupported, presenceTuple2.getServiceCapabilities().isVideoCapable()); 277 } 278 279 @Test 280 @SmallTest testConversionAndRestoration()281 public void testConversionAndRestoration() throws Exception { 282 // Create the capability 283 final RcsContactUceCapability capability = getRcsContactUceCapability(); 284 285 // Convert the capability to the pidf 286 final String pidf = PidfParser.convertToPidf(capability); 287 288 // Restore to the RcsContactUceCapability from the pidf 289 RcsContactUceCapabilityWrapper capabilitiesWrapper = 290 PidfParser.getRcsContactUceCapabilityWrapper(pidf); 291 assertNotNull(capabilitiesWrapper); 292 final RcsContactUceCapability restoredCapability = 293 capabilitiesWrapper.toRcsContactUceCapability(); 294 295 assertEquals(capability.getContactUri(), restoredCapability.getContactUri()); 296 assertEquals(capability.getCapabilityMechanism(), 297 restoredCapability.getCapabilityMechanism()); 298 assertEquals(capability.getSourceType(), restoredCapability.getSourceType()); 299 300 // Assert all the tuples are equal 301 List<RcsContactPresenceTuple> originalTuples = capability.getCapabilityTuples(); 302 List<RcsContactPresenceTuple> restoredTuples = restoredCapability.getCapabilityTuples(); 303 304 assertNotNull(restoredTuples); 305 assertEquals(originalTuples.size(), restoredTuples.size()); 306 307 for (int i = 0; i < originalTuples.size(); i++) { 308 RcsContactPresenceTuple tuple = originalTuples.get(i); 309 RcsContactPresenceTuple restoredTuple = restoredTuples.get(i); 310 311 assertEquals(tuple.getContactUri(), restoredTuple.getContactUri()); 312 assertEquals(tuple.getStatus(), restoredTuple.getStatus()); 313 assertEquals(tuple.getServiceId(), restoredTuple.getServiceId()); 314 assertEquals(tuple.getServiceVersion(), restoredTuple.getServiceVersion()); 315 assertEquals(tuple.getServiceDescription(), restoredTuple.getServiceDescription()); 316 317 boolean isAudioCapable = false; 318 boolean isVideoCapable = false; 319 boolean isRestoredAudioCapable = false; 320 boolean isRestoredVideoCapable = false; 321 322 ServiceCapabilities servCaps = tuple.getServiceCapabilities(); 323 if (servCaps != null) { 324 isAudioCapable = servCaps.isAudioCapable(); 325 isVideoCapable = servCaps.isVideoCapable(); 326 } 327 328 ServiceCapabilities restoredServCaps = restoredTuple.getServiceCapabilities(); 329 if (restoredServCaps != null) { 330 isRestoredAudioCapable = restoredServCaps.isAudioCapable(); 331 isRestoredVideoCapable = restoredServCaps.isVideoCapable(); 332 } 333 334 assertEquals(isAudioCapable, isRestoredAudioCapable); 335 assertEquals(isVideoCapable, isRestoredVideoCapable); 336 } 337 } 338 getPidfData(String contact, String serviceId, String serviceDescription, boolean isAudioSupported, boolean isVideoSupported)339 private String getPidfData(String contact, String serviceId, String serviceDescription, 340 boolean isAudioSupported, boolean isVideoSupported) { 341 StringBuilder pidfBuilder = new StringBuilder(); 342 pidfBuilder.append("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>") 343 .append("<presence entity=\"" + contact + "\"") 344 .append(" xmlns=\"urn:ietf:params:xml:ns:pidf\"") 345 .append(" xmlns:op=\"urn:oma:xml:prs:pidf:oma-pres\"") 346 .append(" xmlns:op=\"urn:oma:xml:prs:pidf:oma-pres\"") 347 .append(" xmlns:caps=\"urn:ietf:params:xml:ns:pidf:caps\">") 348 // tuple data 349 .append("<tuple id=\"tid0\">") 350 .append("<status><basic>open</basic></status>") 351 .append("<op:service-description>") 352 .append("<op:service-id>").append(serviceId).append("</op:service-id>") 353 .append("<op:version>1.0</op:version>") 354 .append("<op:description>").append(serviceDescription).append("</op:description>") 355 .append("</op:service-description>") 356 // is audio supported 357 .append("<caps:servcaps>") 358 .append("<caps:audio>").append(isAudioSupported).append("</caps:audio>") 359 // is video supported 360 .append("<caps:video>").append(isVideoSupported).append("</caps:video>") 361 .append("</caps:servcaps>") 362 .append("<contact>").append(contact).append("</contact>") 363 .append("<timestamp>").append(mPidfTimestamp.toString()).append("</timestamp>") 364 .append("</tuple></presence>"); 365 return pidfBuilder.toString(); 366 } 367 getPidfDataWithNewlineAndWhitespaceCharacters()368 private String getPidfDataWithNewlineAndWhitespaceCharacters() { 369 String pidf = "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" " 370 + "xmlns:op=\"urn:oma:xml:prs:pidf:oma-pres\" " 371 + "xmlns:b=\"urn:ietf:params:xml:ns:pidf:caps\" " 372 + "entity=\"tel:+11234567890\">\n" 373 // Tuple: Discovery 374 + " <tuple id=\"DiscoveryPres\">\n\t" 375 + " <status>\n\t" 376 + " <basic>open</basic>\n\t" 377 + " </status>\n\t" 378 + " <op:service-description>\n\t" 379 + " <op:service-id>org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcse.dp" 380 + "</op:service-id>\n\t" 381 + " <op:version>1.0</op:version>\n\t" 382 + " <op:description>DiscoveryPresence</op:description>\n\t" 383 + " </op:service-description>\n\t" 384 + " <contact>tel:+11234567890</contact>\n\t" 385 + " </tuple>\n\t" 386 // Tuple: VoLTE 387 + " <tuple id=\"VoLTE\">\n" 388 + " <status>\n" 389 + " <basic>open</basic>\n" 390 + " </status>\n" 391 + " <b:servcaps>\n" 392 + " <b:audio>true</b:audio>\n" 393 + " <b:video>true</b:video>\n" 394 + " <b:duplex>\n" 395 + " <b:supported>\n" 396 + " <b:full/>\n" 397 + " </b:supported>\n" 398 + " </b:duplex>\n" 399 + " </b:servcaps>\n" 400 + " <op:service-description>\n" 401 + " <op:service-id>org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel" 402 + "</op:service-id>\n" 403 + " <op:version>1.0</op:version>\n" 404 + " <op:description>VoLTE service</op:description>\n" 405 + " </op:service-description>\n" 406 + " <contact>tel:+11234567890</contact>\n" 407 + " </tuple>\n" 408 // Tuple: Standalone Message 409 + " <tuple id=\"StandaloneMsg\">\n" 410 + " <status>\n" 411 + " <basic>open</basic>\n" 412 + " </status>\n" 413 + " <op:service-description>\n" 414 + " <op:service-id>org.openmobilealliance:StandaloneMsg</op:service-id>\n" 415 + " <op:version>2.0</op:version>\n" 416 + " <op:description>StandaloneMsg</op:description>\n" 417 + " </op:service-description>\n" 418 + " <contact>tel:+11234567890</contact>\n" 419 + " </tuple>\n" 420 // Tuple: Session Mode Message 421 + " <tuple id=\"SessModeMessa\">\n" 422 + " <status>\n" 423 + " <basic>open</basic>\n" 424 + " </status>\n" 425 + " <op:service-description>\n" 426 + " <op:service-id>org.openmobilealliance:ChatSession</op:service-id>\n" 427 + " <op:version>2.0</op:version>\n" 428 + " <op:description>Session Mode Messaging</op:description>\n" 429 + " </op:service-description>\n" 430 + " <contact>tel:+11234567890</contact>\n" 431 + " </tuple>\n" 432 // Tuple: File Transfer 433 + " <tuple id=\"FileTransfer\">\n" 434 + " <status>\n" 435 + " <basic>open</basic>\n" 436 + " </status>\n" 437 + " <op:service-description>\n" 438 + " <op:service-id>org.openmobilealliance:File-Transfer</op:service-id>\n" 439 + " <op:version>1.0</op:version>\n" 440 + " <op:description>File Transfer</op:description>\n" 441 + " </op:service-description>\n" 442 + " <contact>tel:+11234567890</contact>\n" 443 + " </tuple>\n" 444 + " </presence>"; 445 446 return pidf; 447 } 448 getPidfDataWithMultiTuples(String contact, String serviceId1, String serviceDescription1, String serviceId2, String serviceDescription2, boolean audioSupported, boolean videoSupported)449 private String getPidfDataWithMultiTuples(String contact, String serviceId1, 450 String serviceDescription1, String serviceId2, String serviceDescription2, 451 boolean audioSupported, boolean videoSupported) { 452 return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 453 + "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"" 454 + " xmlns:op=\"urn:oma:xml:prs:pidf:oma-pres\"" 455 + " xmlns:caps=\"urn:ietf:params:xml:ns:pidf:caps\"" 456 + " entity=\"" + contact + "\">" 457 // tuple 1 458 + "<tuple id=\"a0\">" 459 + "<status><basic>open</basic></status>" 460 + "<op:service-description>" 461 + "<op:service-id>" + serviceId1 + "</op:service-id>" 462 + "<op:version>1.0</op:version>" 463 + "<op:description>" + serviceDescription1 + "</op:description>" 464 + "</op:service-description>" 465 + "<contact>" + contact + "</contact>" 466 + "<timestamp>" + mPidfTimestamp.toString() + "</timestamp>" 467 + "</tuple>" 468 // tuple 2 469 + "<tuple id=\"a1\">" 470 + "<status><basic>open</basic></status>" 471 + "<op:service-description>" 472 + "<op:service-id>" + serviceId2 + "</op:service-id>" 473 + "<op:version>1.0</op:version>" 474 + "<op:description>" + serviceDescription2 + "</op:description>" 475 + "</op:service-description>" 476 + "<caps:servcaps>" 477 + "<caps:audio>" + audioSupported + "</caps:audio>" 478 + "<caps:duplex>" 479 + "<caps:supported><caps:full></caps:full></caps:supported>" 480 + "</caps:duplex>" 481 + "<caps:video>" + videoSupported + "</caps:video>" 482 + "</caps:servcaps>" 483 + "<contact>" + contact + "</contact>" 484 + "<timestamp>" + mPidfTimestamp.toString() + "</timestamp>" 485 + "</tuple>" 486 + "</presence>"; 487 } 488 getRcsContactUceCapability()489 private RcsContactUceCapability getRcsContactUceCapability() { 490 final Uri contact = Uri.fromParts("sip", "test", null); 491 final boolean isAudioCapable = true; 492 final boolean isVideoCapable = true; 493 final String duplexMode = ServiceCapabilities.DUPLEX_MODE_FULL; 494 final String basicStatus = RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN; 495 final String version = "1.0"; 496 final String description = "description test"; 497 498 // init the capabilities 499 ServiceCapabilities.Builder servCapsBuilder = 500 new ServiceCapabilities.Builder(isAudioCapable, isVideoCapable); 501 servCapsBuilder.addSupportedDuplexMode(duplexMode); 502 503 // init the presence tuple 504 RcsContactPresenceTuple.Builder tupleBuilder = new RcsContactPresenceTuple.Builder( 505 basicStatus, RcsContactPresenceTuple.SERVICE_ID_MMTEL, version); 506 tupleBuilder.setContactUri(contact) 507 .setServiceDescription(description) 508 .setTime(mPidfTimestamp) 509 .setServiceCapabilities(servCapsBuilder.build()); 510 511 PresenceBuilder presenceBuilder = new PresenceBuilder(contact, 512 RcsContactUceCapability.SOURCE_TYPE_NETWORK, 513 RcsContactUceCapability.REQUEST_RESULT_FOUND); 514 presenceBuilder.addCapabilityTuple(tupleBuilder.build()); 515 516 return presenceBuilder.build(); 517 } 518 } 519