Skip to content

Update Communication Common SDK for Teams Phone Extensibility identifier #1918

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions sdk/communication/azure-communication-common/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Release History

## 1.3.0 (2025-03-12)

### Features Added
- Added support for a new communication identifier `TeamsExtensionUserIdentifier` which maps rawIds with format `8:acs:{resourceId}_{tenantId}_{userId}`.
- Added `isAnonymous` and `getAssertedId` methods to `PhoneNumberIdentifier`.

## 1.2.1 (2024-02-23)

### Other Changes
Expand Down
8 changes: 4 additions & 4 deletions sdk/communication/azure-communication-common/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This package contains common code for Azure Communication Service libraries.
APIs that would require the Java 8+ API desugaring provided by Android Gradle plugin 4.0.0.

### Versions available
The current version of this library is **1.2.1**.
The current version of this library is **1.3.0**.

### Install the library
To install the Azure client libraries for Android, add them as dependencies within your
Expand All @@ -36,13 +36,13 @@ Add an `implementation` configuration to the `dependencies` block of your app's
// build.gradle
dependencies {
...
implementation "com.azure.android:azure-communication-common:1.2.1"
implementation "com.azure.android:azure-communication-common:1.3.0"
}

// build.gradle.kts
dependencies {
...
implementation("com.azure.android:azure-communication-common:1.2.1")
implementation("com.azure.android:azure-communication-common:1.3.0")
}
```

Expand All @@ -53,7 +53,7 @@ To import the library into your project using the [Maven](https://maven.apache.o
<dependency>
<groupId>com.azure.android</groupId>
<artifactId>azure-communication-common</artifactId>
<version>1.2.1</version>
<version>1.3.0</version>
</dependency>
```

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=1.2.1
version=1.3.0
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ public abstract class CommunicationIdentifier {
* @throws IllegalArgumentException raw id is null or empty.
*/
public static CommunicationIdentifier fromRawId(String rawId) {
if (rawId == null || rawId.trim().length() == 0) {
throw new IllegalArgumentException("The parameter [rawId] cannot be null to empty.");
}
ValidationUtils.validateNotNullOrEmpty(rawId, "rawId");

if (rawId.startsWith(PHONE_NUMBER_PREFIX)) {
return new PhoneNumberIdentifier(rawId.substring(PHONE_NUMBER_PREFIX.length()));
Expand Down Expand Up @@ -60,11 +58,12 @@ public static CommunicationIdentifier fromRawId(String rawId) {
return new MicrosoftTeamsAppIdentifier(suffix, CommunicationCloudEnvironment.DOD);
case TEAMS_APP_GCCH_CLOUD_PREFIX:
return new MicrosoftTeamsAppIdentifier(suffix, CommunicationCloudEnvironment.GCCH);
case ACS_USER_PREFIX:
case SPOOL_USER_PREFIX:
return new CommunicationUserIdentifier(rawId);
case ACS_USER_PREFIX:
case ACS_USER_DOD_CLOUD_PREFIX:
case ACS_USER_GCCH_CLOUD_PREFIX:
return new CommunicationUserIdentifier(rawId);
return tryCreateTeamsExtensionUserOrCommunicationUser(prefix, suffix, rawId);
default:
return new UnknownIdentifier(rawId);
}
Expand Down Expand Up @@ -110,4 +109,38 @@ public boolean equals(Object that) {
public int hashCode() {
return getRawId().hashCode();
}

private static CommunicationIdentifier tryCreateTeamsExtensionUserOrCommunicationUser(String prefix, String suffix,
String rawId) {
String[] segments = suffix.split("_");
if (segments.length != 3) {
return new CommunicationUserIdentifier(rawId);
}

String resourceId = segments[0];
String tenantId = segments[1];
String userId = segments[2];
CommunicationCloudEnvironment cloud = determineCloudEnvironment(prefix);

return new TeamsExtensionUserIdentifier(userId, tenantId, resourceId).setCloudEnvironment(cloud);
}

/**
* Determine the cloud based on identifier prefix.
* @param cloudPrefix .
* @return CommunicationCloudEnvironment.
* @throws IllegalArgumentException thrown if CommunicationCloudEnvironment cannot be initialized.
*/
static CommunicationCloudEnvironment determineCloudEnvironment(String cloudPrefix) {
switch (cloudPrefix) {
case ACS_USER_DOD_CLOUD_PREFIX:
return CommunicationCloudEnvironment.DOD;
case ACS_USER_GCCH_CLOUD_PREFIX:
return CommunicationCloudEnvironment.GCCH;
case ACS_USER_PREFIX:
return CommunicationCloudEnvironment.PUBLIC;
default:
throw new IllegalArgumentException("Cannot initialize CommunicationCloudEnvironment.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public final class MicrosoftTeamsUserIdentifier extends CommunicationIdentifier
* Creates a MicrosoftTeamsUserIdentifier object
*
* @param userId Id of the Microsoft Teams user. If the user isn't anonymous,
* the id is the AAD object id of the user.
* the id is the Entra ID object id of the user.
* @param isAnonymous set this to true if the user is anonymous,
* for example when joining a meeting with a share link
* @throws IllegalArgumentException thrown if userId parameter fail the validation.
Expand All @@ -34,7 +34,7 @@ public MicrosoftTeamsUserIdentifier(String userId, boolean isAnonymous) {
* Creates a MicrosoftTeamsUserIdentifier object
*
* @param userId Id of the Microsoft Teams user. If the user isn't anonymous,
* the id is the AAD object id of the user.
* the id is the Entra ID object id of the user.
* @throws IllegalArgumentException thrown if userId parameter fail the validation.
*/
public MicrosoftTeamsUserIdentifier(String userId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
* Communication identifier for Communication Services Phone Numbers
*/
public final class PhoneNumberIdentifier extends CommunicationIdentifier {
private static final String ANONYMOUS = "anonymous";
private final String phoneNumber;
private String assertedId;

private boolean isAnonymous;

/**
* Creates a PhoneNumberIdentifier object
Expand All @@ -16,10 +20,7 @@ public final class PhoneNumberIdentifier extends CommunicationIdentifier {
* @throws IllegalArgumentException thrown if phoneNumber parameter fail the validation.
*/
public PhoneNumberIdentifier(String phoneNumber) {
if (phoneNumber == null || phoneNumber.trim().length() == 0) {
throw new IllegalArgumentException("The initialization parameter [phoneNumber] cannot be null to empty.");
}
this.phoneNumber = phoneNumber;
this.phoneNumber = ValidationUtils.validateNotNullOrEmpty(phoneNumber, "phoneNumber");
this.setRawId(PHONE_NUMBER_PREFIX + phoneNumber);
}

Expand All @@ -30,6 +31,35 @@ public String getPhoneNumber() {
return phoneNumber;
}

/**
* Checks if the phone number is anonymous, e.g., used to represent a hidden caller ID.
*
* @return true if the phone number is anonymous, false otherwise.
*/
public boolean isAnonymous() {
return isAnonymous;
}

/**
* Gets the asserted ID for the phone number, distinguishing it from other connections made through the same number.
*
* @return the string identifier representing the asserted ID for the phone number.
*/
public String getAssertedId() {
if (assertedId != null && !assertedId.trim().isEmpty()) {
return assertedId;
}

String[] segments = getRawId().substring(PHONE_NUMBER_PREFIX.length()).split("_");
if (segments.length > 1) {
assertedId = segments[segments.length - 1];
return assertedId;
}

assertedId = "";
return null;
}

/**
* Set full id of the identifier
* RawId is the encoded format for identifiers to store in databases or as stable keys in general.
Expand All @@ -40,6 +70,7 @@ public String getPhoneNumber() {
@Override
public PhoneNumberIdentifier setRawId(String rawId) {
super.setRawId(rawId);
isAnonymous = getRawId().equals(PHONE_NUMBER_PREFIX + ANONYMOUS);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.android.communication.common;

/**
* Communication identifier for Microsoft Teams Phone user who is using a Communication Services resource
* to extend their Teams Phone set up.
*/
public final class TeamsExtensionUserIdentifier extends CommunicationIdentifier {

private final String userId;

private final String tenantId;

private final String resourceId;

private CommunicationCloudEnvironment cloudEnvironment;

/**
* Creates a TeamsExtensionUserIdentifier object with PUBLIC cloud environment.
*
* @param userId ID of the Microsoft Teams Extension user i.e. the Entra ID object id of the user.
* @param tenantId Tenant ID of the Microsoft Teams Extension user.
* @param resourceId The Communication Services resource id.
* @throws IllegalArgumentException if any parameter fail the validation.
*/
public TeamsExtensionUserIdentifier(String userId, String tenantId, String resourceId) {
this.userId = ValidationUtils.validateNotNullOrEmpty(userId, "userId");
this.tenantId = ValidationUtils.validateNotNullOrEmpty(tenantId, "tenantId");
this.resourceId = ValidationUtils.validateNotNullOrEmpty(resourceId, "resourceId");
this.cloudEnvironment = CommunicationCloudEnvironment.PUBLIC;

generateRawId();
}

/**
* Set full ID of the identifier
* RawId is the encoded format for identifiers to store in databases or as stable keys in general.
*
* @param rawId full ID of the identifier.
* @return TeamsExtensionUserIdentifier object itself.
*/
@Override
public TeamsExtensionUserIdentifier setRawId(String rawId) {
super.setRawId(rawId);
return this;
}

/**
* Get Microsoft Teams Extension user
* @return ID of the Microsoft Teams Extension user i.e. the Entra ID object id of the user.
*/
public String getUserId() {
return userId;
}

/**
* Get Microsoft Teams Extension user Tenant ID
* @return Tenant ID of the Microsoft Teams Extension user.
*/
public String getTenantId() {
return tenantId;
}

/**
* Get Communication Services resource id.
* @return the Communication Services resource id.
*/
public String getResourceId() {
return resourceId;
}

/**
* Get cloud environment of the Teams Extension User identifier
* @return cloud environment in which this identifier is created
*/
public CommunicationCloudEnvironment getCloudEnvironment() {
return cloudEnvironment;
}

/**
* Set cloud environment of the Teams Extension User identifier
*
* @param cloudEnvironment the cloud environment in which this identifier is created
* @return this object
* @throws IllegalArgumentException if cloudEnvironment .
*
*/
public TeamsExtensionUserIdentifier setCloudEnvironment(CommunicationCloudEnvironment cloudEnvironment) {
this.cloudEnvironment = ValidationUtils.validateNotNull(cloudEnvironment, "cloudEnvironment");
generateRawId();
return this;
}

@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}

if (!(that instanceof TeamsExtensionUserIdentifier)) {
return false;
}

return super.equals(that);
}

@Override
public int hashCode() {
return super.hashCode();
}

private void generateRawId() {
String identifierBase = this.resourceId + "_" + this.tenantId + "_" + this.userId;
if (cloudEnvironment.equals(CommunicationCloudEnvironment.DOD)) {
super.setRawId(ACS_USER_DOD_CLOUD_PREFIX + identifierBase);
} else if (cloudEnvironment.equals(CommunicationCloudEnvironment.GCCH)) {
super.setRawId(ACS_USER_GCCH_CLOUD_PREFIX + identifierBase);
} else {
super.setRawId(ACS_USER_PREFIX + identifierBase);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.android.communication.common;

class ValidationUtils {

/**
* Validate string
* @param value a value to be validated
* @param paramName Parameter name for exceptionMessage
* @return value
*
* @throws IllegalArgumentException when value is null or Empty.
*/
public static String validateNotNullOrEmpty(String value, String paramName) {
if (value == null || value.trim().isEmpty()) {
String message = "The parameter [" + paramName + "] cannot be null or empty.";
throw new IllegalArgumentException(message);
}
return value;
}

/**
* Validate string
* @param cloudEnvironment a value to be validated
* @param paramName Parameter name for exceptionMessage
* @return value
*
* @throws IllegalArgumentException when value is null or Empty.
*/
public static CommunicationCloudEnvironment validateNotNull(CommunicationCloudEnvironment cloudEnvironment,
String paramName) {
if (cloudEnvironment == null) {
String message = "The parameter [" + paramName + "] cannot be null.";
throw new IllegalArgumentException(message);
}
return cloudEnvironment;
}

}
Loading
Loading