From 75d70e0cdbda9fdb77dc351e019019e1d154b048 Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 22 Jan 2020 16:25:19 +0800 Subject: [PATCH 01/16] [SPARK-112716] Android SDK | KitchenSink crashes when posting file in which name starts with "#" sign --- .../java/com/ciscowebex/androidsdk/message/LocalFile.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/LocalFile.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/LocalFile.java index 3d070aa1..179b488e 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/LocalFile.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/LocalFile.java @@ -3,6 +3,8 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import com.cisco.spark.android.util.MimeUtils; + import java.io.File; import java.net.URLConnection; @@ -40,7 +42,7 @@ public Thumbnail(@NonNull java.io.File file, @Nullable String mime, int width, i throw new IllegalArgumentException("File isn't exist"); } this.file = file; - this.mimeType = mime != null ? mime : URLConnection.guessContentTypeFromName(file.getName()); + this.mimeType = mime != null ? mime : MimeUtils.getMimeType(file.getName()); this.width = width; this.height = height; } @@ -157,7 +159,7 @@ public LocalFile(@NonNull File file, throw new IllegalArgumentException("File isn't exist"); } this.file = file; - this.mimeType = mime != null ? mime : URLConnection.guessContentTypeFromName(file.getName()); + this.mimeType = mime != null ? mime : MimeUtils.getMimeType(file.getName());; this.thumbnail = thumbnail; this.progressHandler = progressHandler; } From 38b2c14b075d535f1c54127336b20786b0aed228 Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 26 Feb 2020 11:02:44 +0800 Subject: [PATCH 02/16] SPARK-119680 Android SDK support for threaded messaging --- .../androidsdk/message/Message.java | 26 ++++++ .../androidsdk/message/MessageClient.java | 90 +++++++++++++++++++ .../CallbackablePostCommentOperation.java | 10 +++ ...lbackablePostContentActivityOperation.java | 10 +++ .../message/internal/MessageClientImpl.java | 74 ++++++++++++--- 5 files changed, 197 insertions(+), 13 deletions(-) diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java index 4137d47a..2b49c19e 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java @@ -147,6 +147,10 @@ public String getPlain() { private transient List remoteFiles; + private boolean isReply; + + private ParentObject parent; + protected Message(Activity activity, AuthenticatedUser user, boolean received) { this.activity = activity; this.id = new WebexId(WebexId.Type.MESSAGE_ID, activity.getId()).toHydraId(); @@ -195,6 +199,8 @@ protected Message(Activity activity, AuthenticatedUser user, boolean received) { } } this.remoteFiles = remoteFiles; + this.isReply = activity.isReply(); + this.parent = activity.getParent(); } /** @@ -342,6 +348,26 @@ public List getFiles() { return this.remoteFiles; } + /** + * Checks if this is a reply message. + * + * @return true if this is a reply message. + * @since 2.5.0 + */ + public boolean isReply() { + return isReply; + } + + /** + * Returns the parent object reference, if this message is a reply message. + * + * @return the parent or null if not reply message. + * @since 2.5.0 + */ + public ParentObject getParent() { + return parent; + } + /** * Returns the message in JSON string format. * diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageClient.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageClient.java index 1ac0f4d5..50853ee9 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageClient.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageClient.java @@ -126,6 +126,62 @@ public interface MessageClient { */ void postToPerson(@NonNull EmailAddress email, @Nullable Message.Text text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); + /** + * Posts a message with optional file attachments to a person asynchronously. + *

+ * The content of the message can be plain text, html, or markdown. + * + * @param id The identifier of a person to which the message is to be posted. + * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. + * @param files Local files to be attached with the message. Null if no files to be attached. + * @param parentMessage Parent message. Null if no parent message. + * @param handler A closure to be executed once the message has posted. + * @since 2.5.0 + */ + void postToPerson(@NonNull String id, @Nullable String text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); + + /** + * Posts a message with optional file attachments to a person asynchronously. + *

+ * The content of the message can be plain text, html, or markdown. + * + * @param id The identifier of a person to which the message is to be posted. + * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. + * @param files Local files to be attached with the message. Null if no files to be attached. + * @param parentMessage Parent message. Null if no parent message. + * @param handler A closure to be executed once the message has posted. + * @since 2.5.0 + */ + void postToPerson(@NonNull String id, @Nullable Message.Text text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); + + /** + * Posts a message with optional file attachments to a person asynchronously. + *

+ * The content of the message can be plain text, html, or markdown. + * + * @param email The email address of a person to which the message is to be posted. + * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. + * @param files Local files to be attached with the message. Null if no files to be attached. + * @param parentMessage Parent message. Null if no parent message. + * @param handler A closure to be executed once the message has posted. + * @since 2.5.0 + */ + void postToPerson(@NonNull EmailAddress email, @Nullable String text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); + + /** + * Posts a message with optional file attachments to a person asynchronously. + *

+ * The content of the message can be plain text, html, or markdown. + * + * @param email The email address of a person to which the message is to be posted. + * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. + * @param files Local files to be attached with the message. Null if no files to be attached. + * @param parentMessage Parent message. Null if no parent message. + * @param handler A closure to be executed once the message has posted. + * @since 2.5.0 + */ + void postToPerson(@NonNull EmailAddress email, @Nullable Message.Text text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); + /** * Posts a message with optional file attachments to a space asynchronously. *

@@ -158,6 +214,40 @@ public interface MessageClient { */ void postToSpace(@NonNull String id, @Nullable Message.Text text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); + /** + * Posts a message with optional file attachments to a space asynchronously. + *

+ * The content of the message can be plain text, html, or markdown. + * To notify specific person or everyone in a space, mentions should be used. + * Having @johndoe in the content of the message does not generate notification. + * + * @param id The identifier of a space to which the message is to be posted. + * @param text The content of message to be posted to the space. The content can be plain text, html, or markdown. + * @param mentions Notify either one or all in a space about this message. + * @param files Local files to be attached with the message. Null if no files to be attached. + * @param parentMessage Parent message. Null if no parent message. + * @param handler A closure to be executed once the message has posted. + * @since 2.5.0 + */ + void postToSpace(@NonNull String id, @Nullable String text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); + + /** + * Posts a message with optional file attachments to a space asynchronously. + *

+ * The content of the message can be plain text, html, or markdown. + * To notify specific person or everyone in a space, mentions should be used. + * Having @johndoe in the content of the message does not generate notification. + * + * @param id The identifier of a space to which the message is to be posted. + * @param text The content of message to be posted to the space. The content can be plain text, html, or markdown. + * @param mentions Notify either one or all in a space about this message. + * @param files Local files to be attached with the message. Null if no files to be attached. + * @param parentMessage Parent message. Null if no parent message. + * @param handler A closure to be executed once the message has posted. + * @since 2.5.0 + */ + void postToSpace(@NonNull String id, @Nullable Message.Text text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); + /** * Downloads a file attachement asynchronously. * See File Sharing for more details. diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostCommentOperation.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostCommentOperation.java index 45228b8e..95ec9309 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostCommentOperation.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostCommentOperation.java @@ -2,6 +2,7 @@ import com.cisco.spark.android.core.Injector; import com.cisco.spark.android.model.conversation.Comment; +import com.cisco.spark.android.model.conversation.ParentObject; import com.cisco.spark.android.sync.operationqueue.ActivityOperation; import com.cisco.spark.android.sync.operationqueue.PostCommentOperation; import com.cisco.spark.android.sync.operationqueue.core.SyncState; @@ -10,13 +11,16 @@ public class CallbackablePostCommentOperation extends PostCommentOperation { private Action onOperationFinishAction; + private ParentObject parent; CallbackablePostCommentOperation(Injector injector, String conversationId, Comment comment, + ParentObject parent, Action onOperationFinishAction) { super(injector, conversationId, comment); this.onOperationFinishAction = onOperationFinishAction; + this.parent = parent; } protected void onStateChanged(SyncState oldState) { @@ -25,4 +29,10 @@ protected void onStateChanged(SyncState oldState) { this.onOperationFinishAction.call(this); } } + + @Override + protected void configureActivity() { + super.configureActivity(); + activity.setParent(parent); + } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostContentActivityOperation.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostContentActivityOperation.java index d89ac135..6d6faeaa 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostContentActivityOperation.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostContentActivityOperation.java @@ -3,6 +3,7 @@ import com.cisco.spark.android.core.Injector; import com.cisco.spark.android.model.conversation.Comment; import com.cisco.spark.android.model.conversation.File; +import com.cisco.spark.android.model.conversation.ParentObject; import com.cisco.spark.android.sync.operationqueue.ActivityOperation; import com.cisco.spark.android.sync.operationqueue.PostContentActivityOperation; import com.cisco.spark.android.sync.operationqueue.core.SyncState; @@ -14,15 +15,19 @@ public class CallbackablePostContentActivityOperation extends PostContentActivit private Action onOperationFinishAction; + private ParentObject parent; + CallbackablePostContentActivityOperation(Injector injector, String conversationId, ShareContentData shareContentData, Comment comment, List content, List operationIds, + ParentObject parent, Action onOperationFinishAction) { super(injector, conversationId, shareContentData, comment, content, operationIds); this.onOperationFinishAction = onOperationFinishAction; + this.parent = parent; } protected void onStateChanged(SyncState oldState) { @@ -32,4 +37,9 @@ protected void onStateChanged(SyncState oldState) { } } + @Override + protected void configureActivity() { + super.configureActivity(); + activity.setParent(parent); + } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageClientImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageClientImpl.java index 082e49e4..e5da73fc 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageClientImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageClientImpl.java @@ -26,6 +26,7 @@ import java.net.URISyntaxException; import java.util.*; import java.util.concurrent.*; + import javax.inject.Inject; import android.content.Context; @@ -36,6 +37,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; + import com.cisco.spark.android.authenticator.ApiTokenProvider; import com.cisco.spark.android.content.ContentUploadMonitor; import com.cisco.spark.android.core.ApiClientProvider; @@ -69,8 +71,11 @@ import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; import com.ciscowebex.androidsdk_commlib.SDKCommonInjector; import com.github.benoitdion.ln.Ln; + import me.helloworld.utils.Strings; + import org.greenrobot.eventbus.EventBus; + import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -266,55 +271,85 @@ public void onFailure(Call call, Throwable t) { @Override public void postToPerson(@NonNull String personId, @Nullable String text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(personId, createComment(Message.Text.html(text, text), null), files, handler); + post(personId, createComment(Message.Text.html(text, text), null), files, null, handler); } @Override public void postToPerson(@NonNull String personId, @Nullable Message.Text text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(personId, createComment(text, null), files, handler); + post(personId, createComment(text, null), files, null, handler); } @Override public void postToPerson(@NonNull EmailAddress personEmail, @Nullable String text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(personEmail.toString(), createComment(Message.Text.html(text, text), null), files, handler); + post(personEmail.toString(), createComment(Message.Text.html(text, text), null), files, null, handler); } @Override public void postToPerson(@NonNull EmailAddress personEmail, @Nullable Message.Text text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(personEmail.toString(), createComment(text, null), files, handler); + post(personEmail.toString(), createComment(text, null), files, null, handler); + } + + @Override + public void postToPerson(@NonNull String personId, @Nullable String text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { + post(personId, createComment(Message.Text.html(text, text), null), files, parentMessage, handler); + } + + @Override + public void postToPerson(@NonNull String personId, @Nullable Message.Text text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { + post(personId, createComment(text, null), files, parentMessage, handler); + } + + @Override + public void postToPerson(@NonNull EmailAddress personEmail, @Nullable String text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { + post(personEmail.toString(), createComment(Message.Text.html(text, text), null), files, parentMessage, handler); + } + + @Override + public void postToPerson(@NonNull EmailAddress personEmail, @Nullable Message.Text text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { + post(personEmail.toString(), createComment(text, null), files, parentMessage, handler); } @Override public void postToSpace(@NonNull String spaceId, @Nullable String text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(spaceId, createComment(Message.Text.html(text, text), mentions), files, handler); + post(spaceId, createComment(Message.Text.html(text, text), mentions), files, null, handler); } @Override public void postToSpace(@NonNull String spaceId, @Nullable Message.Text text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(spaceId, createComment(text, mentions), files, handler); + post(spaceId, createComment(text, mentions), files, null, handler); + } + + @Override + public void postToSpace(@NonNull String spaceId, @Nullable String text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { + post(spaceId, createComment(Message.Text.html(text, text), mentions), files, parentMessage, handler); + } + + @Override + public void postToSpace(@NonNull String spaceId, @Nullable Message.Text text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { + post(spaceId, createComment(text, mentions), files, parentMessage, handler); } - private void post(String personOrSpace, Comment comment, LocalFile[] localFiles, CompletionHandler handler) { + private void post(String personOrSpace, Comment comment, LocalFile[] localFiles, Message parentMessage, CompletionHandler handler) { Ln.d("Post to: " + personOrSpace); WebexId webexId = WebexId.from(personOrSpace); if (webexId == null) { if (EmailAddress.fromString(personOrSpace) == null) { - doPost(personOrSpace, comment, localFiles, handler); + doPost(personOrSpace, comment, localFiles, parentMessage, handler); } else { this.createSpaceWithPerson(personOrSpace, result -> { if (result.getData() != null) { - doPost(result.getData(), comment, localFiles, handler); + doPost(result.getData(), comment, localFiles, parentMessage, handler); } else { handler.onComplete(ResultImpl.error(result.getError())); } }); } } else if (webexId.is(WebexId.Type.ROOM_ID)) { - doPost(webexId.getId(), comment, localFiles, handler); + doPost(webexId.getId(), comment, localFiles, parentMessage, handler); } else if (webexId.is(WebexId.Type.PEOPLE_ID)) { this.createSpaceWithPerson(webexId.getId(), result -> { if (result.getData() != null) { - doPost(result.getData(), comment, localFiles, handler); + doPost(result.getData(), comment, localFiles, parentMessage, handler); } else { handler.onComplete(ResultImpl.error(result.getError())); } @@ -324,7 +359,7 @@ private void post(String personOrSpace, Comment comment, LocalFile[] localFiles, } } - private void doPost(String conversationId, Comment comment, LocalFile[] localFiles, CompletionHandler handler) { + private void doPost(String conversationId, Comment comment, LocalFile[] localFiles, Message parentMessage, CompletionHandler handler) { if (TextUtils.isEmpty(conversationId)) { handler.onComplete(ResultImpl.error("Invalid person or id!")); return; @@ -345,6 +380,18 @@ public void call(Activity activity) { } } }; + ParentObject parent = null; + if (parentMessage != null) { + if (parentMessage.getParent() != null) + parent = parentMessage.getParent(); + else { + parent = new ParentObject(); + parent.setId(WebexId.translate(parentMessage.getId())); + parent.setType(Activities.ACTIVITY_TYPE_REPLY); + parent.setPublished(parentMessage.getCreated()); + parent.setActorId(parentMessage.getPersonId()); + } + } if (localFiles != null && localFiles.length > 0) { ShareContentData shareContentData = new ShareContentData(); for (LocalFile localFile : localFiles) { @@ -363,10 +410,11 @@ public void call(Activity activity) { comment, shareContentData.getContentFiles(), shareContentData.getOperationIds(), + parent, callback); operations.submit(postContent); } else { - CallbackablePostCommentOperation postCommentOperation = new CallbackablePostCommentOperation(injector, conversationId, comment, callback); + CallbackablePostCommentOperation postCommentOperation = new CallbackablePostCommentOperation(injector, conversationId, comment, parent, callback); operations.submit(postCommentOperation); } } From 02e035b430fc6c7fe6dea2f7fce4010ef46476fc Mon Sep 17 00:00:00 2001 From: kliu Date: Fri, 6 Mar 2020 13:43:05 +0800 Subject: [PATCH 03/16] Fix sipUri of call membership --- .../androidsdk/phone/internal/CallMembershipImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallMembershipImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallMembershipImpl.java index af1ed342..baf38791 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallMembershipImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallMembershipImpl.java @@ -90,7 +90,7 @@ private static CallMembership.State fromLocusState(LocusParticipant.State state, _personId = new WebexId(WebexId.Type.PEOPLE_ID, person.getId()).toHydraId(); _email = person.getEmail(); _phoneNumber = person.getPhoneNumber(); - _sipUrl = person.getPhoneNumber(); + _sipUrl = person.getSipUrl(); _isInitiator = participant.isCreator(); _state = fromLocusState(participant.getState(), participant.isInLobby()); MediaDirection videoStatus = participant.getStatus().getVideoStatus(); From d90d001a79b61f921079a9f34cc9a10198bdd071 Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 11 Mar 2020 21:56:34 +0800 Subject: [PATCH 04/16] SPARK-125641 Investigate the Android SDK crash when remote expert annotate. --- .../com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java index 07323729..d6dbb3a4 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java @@ -1055,8 +1055,10 @@ public void onEventMainThread(CallControlParticipantLeftEvent event) { if (call != null) { Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); if (!call.isGroup()) { - resetDialStatus(null); - removeCall(new CallObserver.RemoteLeft(call)); + if (call.getRemoteParticipants().isEmpty()){ + resetDialStatus(null); + removeCall(new CallObserver.RemoteLeft(call)); + } } else if (call.getStatus() == Call.CallStatus.INITIATED || call.getStatus() == Call.CallStatus.RINGING) { boolean meetingIsOpen = false; for (CallMembership membership : call.getMemberships()) { From 0d9ff2df74944d742e0a047e30aef36bdfaff844 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 3 Apr 2020 13:40:04 +0800 Subject: [PATCH 05/16] README and CHANGELOG --- CHANGELOG.md | 16 +++++++++++++++- README.md | 43 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97b74357..54b95848 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Change Log All notable changes to this project will be documented in this file. +#### 2.5.0 Releases +- `2.5.0` Releases - [2.5.0](#250) + #### 2.4.0 Releases - `2.4.0` Releases - [2.4.0](#240) @@ -26,11 +29,22 @@ All notable changes to this project will be documented in this file. - `0.2.0` Releases - [0.2.0](#020) --- +## [2.5.0](https://github.com/webex/webex-android-sdk/releases/tag/2.5.0) +Released on 2020-04-01. +#### Added +- Support to send/receive the threaded messaging. + +#### Updated +- Improve dependencies tree. +- Fixed no video if set screenShare view to null. +- Fixed crashes when posting file in which name starts with "#" sign. +- Fixed lock the audio playback when play through bluetooth headset. + ## [2.4.0](https://github.com/webex/webex-android-sdk/releases/tag/2.4.0) Released on 2020-01-15. #### Added - Support to join the meeting where lobby is enabled. -- Support to let-in waiting people from looby to the meeting. +- Support to let-in waiting people from lobby to the meeting. #### Updated - Fixed users' audio cannot be heard mute/unmute. diff --git a/README.md b/README.md index 176d4a61..24c455ca 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Assuming you already have an Android project, e.g. _MyWebexApp_, for your Androi ```groovy dependencies { - compile('com.ciscowebex:androidsdk:2.4.0@aar', { + compile('com.ciscowebex:androidsdk:2.5.0@aar', { transitive = true }) } @@ -333,8 +333,30 @@ Here are some examples of how to use the Android SDK in your app. } })); ``` + +11. Post a threaded message -11. Receive a message + ```java + webex.message().postToPerson( + EmailAddress.fromString("bob@example.com"), + Message.Text.markdown("**Hello**", "Hello", "Hello"), + files, + parentMessage, + new CompletionHandler() { + @Override + public void onComplete(Result result) { + if (result.isSuccessful()) { + // message sent success + ... + } else { + // message sent failed + ... + } + } + })); + ``` + +12. Receive a message ```java webex.message().setMessageObserver( @@ -343,6 +365,9 @@ Here are some examples of how to use the Android SDK in your app. if (event instanceof MessageReceived) { Message message = event.getMessage(); // new message arrived + if(message.getParent != null){ + // threaded message + } } else if (event instanceof MessageDeleted) { // message deleted } @@ -350,7 +375,7 @@ Here are some examples of how to use the Android SDK in your app. } ); ``` -12. Send Read Receipts +13. Send Read Receipts ```java //Mark all exist messages in space as read @@ -360,7 +385,7 @@ Here are some examples of how to use the Android SDK in your app. webex.message().markAsRead(spaceId, messageId); ``` -13. Multi-Stream to receive more video streams +14. Multi-Stream to receive more video streams ```java activeCall.setMultiStreamObserver(new MultiStreamObserver() { @@ -404,7 +429,7 @@ Here are some examples of how to use the Android SDK in your app. } }); ``` -14. Set MembershipObserver to receive Membership events +15. Set MembershipObserver to receive Membership events ```java webex.memberships().setMembershipObserver(new MembershipObserver() { @@ -429,7 +454,7 @@ Here are some examples of how to use the Android SDK in your app. } }); ``` -15. Set SpaceObserver to receive Space events +16. Set SpaceObserver to receive Space events ```java webex.spaces().setSpaceObserver(new SpaceObserver() { @@ -448,7 +473,7 @@ Here are some examples of how to use the Android SDK in your app. } }); ``` -16. Get space meeting details +17. Get space meeting details ```java webex.spaces().getMeeting(spaceId, new CompletionHandler() { @@ -461,7 +486,7 @@ Here are some examples of how to use the Android SDK in your app. } }); ``` -17. Get read status of a space +18. Get read status of a space ```java webex.spaces().getWithReadStatus(spaceId, new CompletionHandler() { @@ -503,7 +528,7 @@ Assuming you already have an Android project with Spark Android SDK integrated. // compile('com.ciscospark:androidsdk:1.4.0@aar', { // transitive = true // }) - compile('com.ciscowebex:androidsdk:2.3.0@aar', { + compile('com.ciscowebex:androidsdk:2.5.0@aar', { transitive = true }) } From 42d65b6506397e9298ce1f6271435f482151060b Mon Sep 17 00:00:00 2001 From: kliu Date: Thu, 9 Apr 2020 22:33:40 +0800 Subject: [PATCH 06/16] Decommission commlib --- README.md | 2 +- build.gradle | 9 +- sdk/build.gradle | 67 +- sdk/libs/cloud-apps-sdk-kms-1.0.17991.jar | Bin 0 -> 42864 bytes sdk/libs/diagnostic-events-gson-1.0.175.jar | Bin 0 -> 188122 bytes .../androidsdk/WebexTestRunner.java | 78 +- .../androidsdk/auth/JWTAuthenticatorTest.java | 20 +- .../membership/MembershipClientTest.java | 88 - sdk/src/main/AndroidManifest.xml | 3 +- .../java/com/ciscowebex/androidsdk/Webex.java | 161 +- .../com/ciscowebex/androidsdk/WebexError.java | 54 +- .../com/ciscowebex/androidsdk/WebexEvent.java | 8 +- .../androidsdk/auth/JWTAuthenticator.java | 181 +- .../androidsdk/auth/OAuthAuthenticator.java | 202 +- .../auth/OAuthTestUserAuthenticator.java | 140 - .../auth/OAuthWebViewAuthenticator.java | 58 +- .../androidsdk/auth/SSOAuthenticator.java | 60 +- .../auth/internal/OAuthLauncher.java | 7 +- .../auth/internal/TokenAuthenticator.java | 72 +- .../internal/AcquirePermissionActivity.java | 54 +- .../androidsdk/internal/ActivityListener.java | 7 + .../androidsdk/internal/Closure.java | 5 + .../androidsdk/internal/Credentials.java | 80 + .../androidsdk/internal/Device.java | 111 + .../androidsdk/internal/ErrorDetail.java | 217 ++ .../androidsdk/internal/MetricsClient.java | 76 - .../androidsdk/internal/MetricsService.java | 29 + .../androidsdk/internal/ResultImpl.java | 70 +- .../androidsdk/internal/SDKComponent.java | 51 - .../androidsdk/internal/SDKModule.java | 26 - .../androidsdk/internal/SDKScope.java | 10 - .../ciscowebex/androidsdk/internal/Service.kt | 98 + .../androidsdk/internal/ServiceReqeust.java | 214 ++ .../androidsdk/internal/Settings.java | 93 + .../internal/adaptor/MercuryEventAdapter.java | 87 + .../internal/adaptor/ObjectModelAdapter.java | 101 + .../internal/adaptor/SimpleAdaptor.java | 93 + .../internal/crypto/CryptoUtils.java | 504 ++++ .../internal/crypto/KeyManager.java | 301 ++ .../androidsdk/internal/crypto/KeyObject.java | 121 + .../internal/crypto/KmsRequestWrapper.java | 88 + .../crypto/KmsResourceObject.java} | 53 +- .../crypto/SecureContentReference.java | 425 +++ .../internal/crypto/SymmetricJWK.java | 43 + .../TypedSecureContentReferenceOutput.java | 52 + .../media/AudioPlaybackStreamType.java | 47 + .../internal/media/MediaCapability.java | 298 ++ .../internal/media/MediaConstraint.java | 27 + .../androidsdk/internal/media/MediaError.java | 87 + .../internal/media/MediaHelper.java | 64 + .../androidsdk/internal/media/MediaSCR.java | 53 + .../androidsdk/internal/media/WMEngine.java | 209 ++ .../internal/media/WmeObserver.java | 44 + .../androidsdk/internal/media/WmeSession.java | 1026 +++++++ .../androidsdk/internal/media/WmeTrack.java | 304 +++ .../device/AudioDeviceConnectionManager.java | 247 ++ .../media/device/AudioManagerDelegate.java | 134 + .../device/BluetoothBroadcastReceiver.java | 73 + .../device/BluetoothServiceListener.java | 57 + .../media/device/HeadsetIntentReceiver.java | 55 + .../media/device/MediaDeviceMananger.java | 149 + .../media/device/ProximitySensor.java | 250 ++ .../media/device/SensorManagerDelegate.java | 50 + .../device/VolumeSettingChangedListener.java | 53 + .../mercury/MercuryActivityEvent.java | 56 + .../internal/mercury/MercuryEnvelope.java | 120 + .../internal/mercury/MercuryEvent.java | 119 + .../internal/mercury/MercuryKmsAckEvent.java | 43 + .../mercury/MercuryKmsMessageEvent.java | 39 + .../internal/mercury/MercuryKmsPushEvent.java | 51 + .../internal/mercury/MercuryLocusEvent.java | 49 + .../internal/mercury/MercuryService.java | 310 +++ .../internal/mercury/MercuryTypingEvent.java | 39 + .../internal/model/ActivityModel.java | 319 +++ .../internal/model/AlertTypeModel.java | 45 + .../internal/model/CalliopeClusterModel.java | 14 + .../internal/model/CommentModel.java | 95 + .../internal/model/ContentModel.java | 156 ++ .../internal/model/ConversationModel.java | 432 +++ .../internal/model/DeviceModel.java | 54 + .../internal/model/DisplayHintsModel.java | 76 + .../androidsdk/internal/model/FileModel.java | 274 ++ .../androidsdk/internal/model/FloorModel.java | 107 + .../internal/model/GroupMentionModel.java | 85 + .../androidsdk/internal/model/ImageModel.java | 149 + .../internal/model/IntentModel.java | 47 + .../androidsdk/internal/model/ItemsModel.java | 65 + .../internal/model/JWTLoginModel.java | 48 + .../internal/model/KmsInfoModel.java | 44 + .../internal/model/KmsMessageModel.java | 71 + .../internal/model/LocusControlMetaModel.java | 43 + .../internal/model/LocusControlModel.java | 56 + .../internal/model/LocusDescriptionModel.java | 120 + .../internal/model/LocusKeyModel.java | 66 + .../internal/model/LocusLinkModel.java | 64 + .../model/LocusListResponseModel.java | 12 + .../internal/model/LocusLockControlModel.java | 41 + .../internal/model/LocusMediaDirection.java | 30 + .../model/LocusMediaResponseModel.java | 39 + .../androidsdk/internal/model/LocusModel.java | 831 ++++++ .../LocusParticipantAudioControlModel.java | 41 + ...LocusParticipantChallengeControlModel.java | 36 + .../model/LocusParticipantControlsModel.java | 67 + .../model/LocusParticipantDeviceModel.java | 119 + .../model/LocusParticipantInfoModel.java | 161 ++ ...cusParticipantLocalRecordControlModel.java | 41 + .../internal/model/LocusParticipantModel.java | 407 +++ .../model/LocusParticipantStatusModel.java | 56 + .../model/LocusRecordControlModel.java | 50 + .../internal/model/LocusReplacesModel.java | 49 + .../model/LocusScheduledMeetingModel.java | 71 + .../internal/model/LocusSelfModel.java | 47 + .../internal/model/LocusSequenceModel.java | 377 +++ .../internal/model/LocusStateModel.java | 93 + .../model/LocusUrlResponseModel.java} | 18 +- .../internal/model/MarkdownableModel.java | 28 + .../internal/model/MediaConnectionModel.java | 77 + .../model/MediaEngineReachabilityModel.java | 31 + .../internal/model/MediaInfoModel.java | 112 + .../internal/model/MediaShareModel.java | 142 + .../internal/model/MentionableModel.java | 28 + .../internal/model/ObjectModel.java | 168 ++ .../internal/model/OrganizationModel.java | 44 + .../model/OrganizationPolicyModel.java | 70 + .../internal/model/ParentModel.java | 70 + .../internal/model/PersonModel.java | 186 ++ .../androidsdk/internal/model/PlaceModel.java | 73 + .../internal/model/ProviderModel.java | 53 + .../internal/model/ReachabilityModel.java | 14 + .../internal/model/RegionModel.java | 39 + .../internal/model/SpacePropertyModel.java | 80 + .../internal/model/SuggestedMediaModel.java | 41 + .../androidsdk/internal/model/TeamModel.java | 94 + .../androidsdk/internal/model/TokenModel.java | 61 + .../internal/model/UploadSessionModel.java | 52 + .../internal/queue/BackgroundQueue.java | 57 + .../androidsdk/internal/queue/MainQueue.java | 49 + .../androidsdk/internal/queue/Operation.java | 170 ++ .../internal/queue/OperationQueue.java | 247 ++ .../androidsdk/internal/queue/Queue.java | 38 + .../internal/queue/QueueWorker.java | 101 + .../androidsdk/internal/queue/Scheduler.java | 48 + .../internal/queue/SerialQueue.java | 139 + .../reachability/BackgroundChecker.java | 208 ++ .../reachability/ForegroundChecker.java | 76 + .../reachability/NetworkConnectionStatus.java | 106 + .../reachability/NetworkReachability.java | 138 + .../internal/reachability/ProxyHelpers.java | 196 ++ .../androidsdk/membership/Membership.java | 24 +- .../membership/MembershipObserver.java | 10 +- .../membership/MembershipReadStatus.java | 9 +- .../internal/InternalMembership.java | 34 +- .../InternalMembershipReadStatus.java | 28 +- .../internal/MembershipClientImpl.java | 245 +- .../androidsdk/message/LocalFile.java | 3 +- .../androidsdk/message/Message.java | 95 +- .../androidsdk/message/MessageClient.java | 106 +- .../androidsdk/message/MessageObserver.java | 8 +- .../CallbackablePostCommentOperation.java | 38 - ...lbackablePostContentActivityOperation.java | 45 - .../internal/DownloadFileOperation.java | 97 + .../message/internal/DraftImpl.java | 81 + .../message/internal/InternalMessage.java | 36 +- .../message/internal/MessageClientImpl.java | 825 ++---- .../internal/MessageMarkReadOperation.java | 54 - .../message/internal/RemoteFileImpl.java | 52 +- .../internal/UploadFileOperations.java | 167 ++ .../people/internal/PersonClientImpl.java | 118 +- .../androidsdk/phone/AuxStream.java | 5 +- .../com/ciscowebex/androidsdk/phone/Call.java | 16 +- .../androidsdk/phone/CallMembership.java | 6 + .../androidsdk/phone/CallObserver.java | 11 + .../androidsdk/phone/MediaOption.java | 31 +- .../androidsdk/phone/MultiStreamObserver.java | 3 +- .../phone/internal/AuxStreamImpl.java | 92 +- .../phone/internal/CallContext.java | 101 + .../androidsdk/phone/internal/CallImpl.java | 1468 ++++++---- .../phone/internal/CallMembershipImpl.java | 150 +- .../phone/internal/CallService.java | 368 +++ .../phone/internal/H264LicensePrompter.java | 22 +- .../phone/internal/LocusResponse.java | 171 ++ .../phone/internal/MediaEngine.java | 82 + .../phone/internal/MediaObserver.java | 246 ++ .../phone/internal/MediaSession.java | 361 +++ .../androidsdk/phone/internal/PhoneImpl.java | 2428 ++++++----------- .../phone/internal/ReachabilityService.java | 82 + .../phone/internal/RegisterOperation.java | 92 + ...tationHandler.java => UIEventHandler.java} | 67 +- .../internal/UnregisterOperation.java} | 36 +- .../ciscowebex/androidsdk/space/Space.java | 17 +- .../androidsdk/space/SpaceObserver.java | 6 +- .../androidsdk/space/SpaceReadStatus.java | 4 +- .../space/internal/InternalSpace.java | 30 +- .../internal/InternalSpaceReadStatus.java | 26 +- .../space/internal/SpaceClientImpl.java | 273 +- .../team/internal/TeamClientImpl.java | 91 +- .../internal/TeamMembershipClientImpl.java | 92 +- .../androidsdk/utils/DateUtils.java | 173 ++ .../androidsdk/utils/EmailAddress.java | 6 +- .../androidsdk/utils/GiphyUtils.java | 76 + .../com/ciscowebex/androidsdk/utils/Json.java | 101 + .../ciscowebex/androidsdk/utils/Lists.java | 31 + .../androidsdk/utils/LoggingLock.java | 222 ++ .../ciscowebex/androidsdk/utils/Metadata.java | 138 + .../androidsdk/utils/MimeUtils.java | 186 ++ .../androidsdk/utils/NetworkUtils.java | 92 + .../ciscowebex/androidsdk/utils/PSUtils.java | 112 + .../androidsdk/utils/TrackingIdGenerator.java | 61 + .../ciscowebex/androidsdk/utils/UriUtils.java | 305 +++ .../ciscowebex/androidsdk/utils/Utils.java | 226 +- .../ciscowebex/androidsdk/utils/WebexId.java | 44 +- .../utils/http/ContentDownloadMonitor.java | 111 + .../utils/http/CountedTypedOutput.java | 90 + .../utils/http/DefaultHeadersInterceptor.java | 23 +- .../androidsdk/utils/http/HttpClient.java | 109 + .../utils/http/ListenerCallback.java | 38 - .../utils/http/RetryCallAdapterFactory.java | 168 -- .../androidsdk/utils/http/ServiceBuilder.java | 178 -- .../androidsdk/utils/log/DebugLn.java | 4 - .../androidsdk/utils/log/LogCaptureUtil.java | 37 +- .../androidsdk/utils/log/MediaLog.java | 29 +- .../ciscowebex/androidsdk/utils/log/NoLn.java | 4 - .../androidsdk/utils/log/WarningLn.java | 4 - .../androidsdk/webhook/Webhook.java | 52 +- .../webhook/internal/WebhookClientImpl.java | 99 +- .../main/jniLibs/arm64-v8a/libaudiopairing.so | Bin 0 -> 96640 bytes .../main/jniLibs/arm64-v8a/libc++_shared.so | Bin 0 -> 919888 bytes .../jniLibs/armeabi-v7a/libaudiopairing.so | Bin 0 -> 75668 bytes .../main/jniLibs/armeabi-v7a/libc++_shared.so | Bin 0 -> 558904 bytes sdk/src/main/jniLibs/x86/libaudiopairing.so | Bin 0 -> 96200 bytes sdk/src/main/jniLibs/x86/libc++_shared.so | Bin 0 -> 935744 bytes .../main/jniLibs/x86_64/libaudiopairing.so | Bin 0 -> 105104 bytes sdk/src/main/jniLibs/x86_64/libc++_shared.so | Bin 0 -> 993896 bytes .../com/ciscowebex/androidsdk/WebexTest.java | 20 + 234 files changed, 22168 insertions(+), 5347 deletions(-) create mode 100644 sdk/libs/cloud-apps-sdk-kms-1.0.17991.jar create mode 100644 sdk/libs/diagnostic-events-gson-1.0.175.jar delete mode 100644 sdk/src/androidTest/java/com/ciscowebex/androidsdk/membership/MembershipClientTest.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthTestUserAuthenticator.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/ActivityListener.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/Closure.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/Credentials.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/Device.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/ErrorDetail.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/MetricsClient.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/MetricsService.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKComponent.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKModule.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKScope.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/Service.kt create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/ServiceReqeust.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/Settings.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/MercuryEventAdapter.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/ObjectModelAdapter.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/SimpleAdaptor.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/CryptoUtils.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KeyManager.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KeyObject.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KmsRequestWrapper.java rename sdk/src/main/java/com/ciscowebex/androidsdk/{utils/http/ListCallback.java => internal/crypto/KmsResourceObject.java} (56%) create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/SecureContentReference.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/SymmetricJWK.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/TypedSecureContentReferenceOutput.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/AudioPlaybackStreamType.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaCapability.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaConstraint.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaError.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaHelper.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaSCR.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WMEngine.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeObserver.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeSession.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeTrack.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/AudioDeviceConnectionManager.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/AudioManagerDelegate.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/BluetoothBroadcastReceiver.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/BluetoothServiceListener.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/HeadsetIntentReceiver.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/MediaDeviceMananger.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/ProximitySensor.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/SensorManagerDelegate.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/VolumeSettingChangedListener.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryActivityEvent.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryEnvelope.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryEvent.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsAckEvent.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsMessageEvent.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsPushEvent.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryLocusEvent.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryService.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryTypingEvent.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ActivityModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/AlertTypeModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/CalliopeClusterModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/CommentModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ContentModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ConversationModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/DeviceModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/DisplayHintsModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/FileModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/FloorModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/GroupMentionModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ImageModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/IntentModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ItemsModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/JWTLoginModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/KmsInfoModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/KmsMessageModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusControlMetaModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusControlModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusDescriptionModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusKeyModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusLinkModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusListResponseModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusLockControlModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusMediaDirection.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusMediaResponseModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantAudioControlModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantChallengeControlModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantControlsModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantDeviceModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantInfoModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantLocalRecordControlModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantStatusModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusRecordControlModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusReplacesModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusScheduledMeetingModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusSelfModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusSequenceModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusStateModel.java rename sdk/src/main/java/com/ciscowebex/androidsdk/{utils/http/ListBody.java => internal/model/LocusUrlResponseModel.java} (82%) create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MarkdownableModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaConnectionModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaEngineReachabilityModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaInfoModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaShareModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MentionableModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ObjectModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/OrganizationModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/OrganizationPolicyModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ParentModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/PersonModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/PlaceModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ProviderModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ReachabilityModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/RegionModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/SpacePropertyModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/SuggestedMediaModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/TeamModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/TokenModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/UploadSessionModel.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/BackgroundQueue.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/MainQueue.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Operation.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/OperationQueue.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Queue.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/QueueWorker.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Scheduler.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/SerialQueue.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ForegroundChecker.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkConnectionStatus.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ProxyHelpers.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostCommentOperation.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostContentActivityOperation.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/DownloadFileOperation.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/DraftImpl.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageMarkReadOperation.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/UploadFileOperations.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallContext.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallService.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/LocusResponse.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaEngine.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaObserver.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaSession.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/ReachabilityService.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/RegisterOperation.java rename sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/{RotationHandler.java => UIEventHandler.java} (51%) rename sdk/src/main/java/com/ciscowebex/androidsdk/{utils/http/ObjectCallback.java => phone/internal/UnregisterOperation.java} (60%) create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/DateUtils.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/GiphyUtils.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/Json.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/LoggingLock.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/Metadata.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/MimeUtils.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/NetworkUtils.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/PSUtils.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/TrackingIdGenerator.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/UriUtils.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ContentDownloadMonitor.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/CountedTypedOutput.java create mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/HttpClient.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ListenerCallback.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/RetryCallAdapterFactory.java delete mode 100644 sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ServiceBuilder.java create mode 100755 sdk/src/main/jniLibs/arm64-v8a/libaudiopairing.so create mode 100755 sdk/src/main/jniLibs/arm64-v8a/libc++_shared.so create mode 100755 sdk/src/main/jniLibs/armeabi-v7a/libaudiopairing.so create mode 100755 sdk/src/main/jniLibs/armeabi-v7a/libc++_shared.so create mode 100755 sdk/src/main/jniLibs/x86/libaudiopairing.so create mode 100755 sdk/src/main/jniLibs/x86/libc++_shared.so create mode 100755 sdk/src/main/jniLibs/x86_64/libaudiopairing.so create mode 100755 sdk/src/main/jniLibs/x86_64/libc++_shared.so diff --git a/README.md b/README.md index 176d4a61..c2305668 100644 --- a/README.md +++ b/README.md @@ -518,7 +518,7 @@ Here are API changes list from Spark Android SDK to Webex Android SDK. | Package name | com.ciscospark.androidsdk | com.ciscowebex.androidsdk | Create a new instance | Spark spark = new Spark(application, authenticator) | Webex webex = new Webex(application, authenticator) | Get error response | SparkError error = result.getError() | WebexError error = result.getError() -| Rename Room to Space | spark.rooms().get(roomId, CompletionHandler< Room > handler) | webex.spaces().get(spaceId, CompletionHandler< Space > handler) +| Rename Room to Space | spark.rooms().get(roomId, CompletionHandler< Room > callback) | webex.spaces().get(spaceId, CompletionHandler< Space > callback) ## Contribute diff --git a/build.gradle b/build.gradle index 210cafe7..4f955b17 100755 --- a/build.gradle +++ b/build.gradle @@ -9,15 +9,12 @@ buildscript { url 'https://maven.fabric.io/public' } } - ext.kotlin_version = "1.3.21" - ext.gradleVersion = "3.3.2" - dependencies { classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.1" classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0' - classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.+' - classpath "com.android.tools.build:gradle:$gradleVersion" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' + classpath "com.android.tools.build:gradle:3.3.2" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.71" } } diff --git a/sdk/build.gradle b/sdk/build.gradle index b00fb355..033d58b2 100755 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -9,7 +9,7 @@ ext { moduleName = 'Cisco Webex Android SDK' moduleGroupId = 'com.ciscowebex' moduleArtifactId = 'androidsdk' - moduleVersion = '2.4.0' + moduleVersion = '2.5.0.6-SNAPSHOT' moduleDescription = 'Cisco Webex SDK for Android' moduleSiteUrl = 'https://developer.webex.com/getting-started.html' moduleProjectUrl = 'https://github.com/webex/webex-android-sdk' @@ -25,6 +25,9 @@ ext { moduleDeveloperOrganizationURL = 'https://www.webex.com/' } +kotlin { +} + jacoco { toolVersion = "0.7.5+" } @@ -59,21 +62,20 @@ task jacocoTestReport(type: JacocoReport, dependsOn: "testDebugUnitTest") { android { compileSdkVersion 27 buildToolsVersion "28.0.3" - defaultConfig { minSdkVersion 21 targetSdkVersion 27 - testInstrumentationRunner "com.ciscowebex.androidsdk.WebexTestRunner" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true versionCode 1 versionName moduleVersion buildConfigField "String", "BUILD_TIME", "\"${buildTime()}\"" buildConfigField "String", "BUILD_REVISION", "\"${revision()}\"" + buildConfigField "boolean", "INTEGRATION_TEST", "false" ndk { abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" } } - buildTypes { release { minifyEnabled false @@ -92,20 +94,16 @@ android { testCoverageEnabled true } } - - testBuildType "jenkins" - + testBuildType "debug" dexOptions { preDexLibraries = false javaMaxHeapSize "4g" dexInProcess false } - compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } - testOptions { unitTests.all { testLogging { @@ -116,24 +114,20 @@ android { jacoco.includeNoLocationClasses = true } } - if (JavaVersion.current().isJava8Compatible()) { tasks.withType(Javadoc) { options.addStringOption('Xdoclint:none', '-quiet') } } - def libraryModuleName = 'sdk' def aarName = libraryModuleName + '-debug.aar' def outputAarDir = rootProject.file(libraryModuleName + '/build/outputs/aar') def outputAarUnzipedDir = rootProject.file(libraryModuleName + '/build/outputs/aar/unziped') def aarReleaseFile = rootProject.file(libraryModuleName + '/build/outputs/aar/' + aarName) - task unzipAar(type: Copy) { from zipTree(aarReleaseFile) into outputAarUnzipedDir } - task addLicenseFileInUnzipedAar(type: Copy, dependsOn: 'unzipAar') { def fromDir = rootProject.file('.') from fromDir @@ -141,23 +135,23 @@ android { include 'LICENSE' include 'CISCO_API_LICENSE.pdf' } - task reZipAar(type: Zip, dependsOn: 'addLicenseFileInUnzipedAar') { from outputAarUnzipedDir include '*' include '*/*' + include '**/**/*' archiveName aarName destinationDir(outputAarDir) } - afterEvaluate { bundleReleaseAar.finalizedBy(reZipAar) bundleDebugAar.finalizedBy(reZipAar) } - packagingOptions { exclude 'META-INF/rxjava.properties' } + productFlavors { + } } publishing { @@ -240,21 +234,22 @@ publishing { } dependencies { - // implementation fileTree(dir: 'libs', include: ['*.jar']) - compileOnly 'com.google.dagger:dagger-compiler:2.24' - kapt 'com.google.dagger:dagger-compiler:2.24' - annotationProcessor 'com.google.dagger:dagger-compiler:2.24' - implementation('com.ciscowebex:androidsdk_commlib:2.4.0@aar', { - transitive = true - changing = true - }) - androidTestImplementation 'com.squareup.okhttp3:okhttp:3.8.0' - androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.8.0' - androidTestImplementation 'junit:junit:4.12' - androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { - exclude group: 'com.android.support', module: 'support-annotations' - }) - androidTestImplementation 'org.testng:testng:6.9.6' + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation('com.webex:wme4android-release:10.3.1.1@aar') + implementation('com.google.code.gson:gson:2.7') + implementation('com.github.benoitdion.ln:ln:0.1.2') + implementation('com.squareup.okhttp3:okhttp:3.12.0') + implementation('com.squareup.okhttp3:logging-interceptor:3.12.0') + implementation('com.android.support:support-annotations:27.1.0') + implementation('com.android.support:support-compat:27.1.0') + implementation('com.nimbusds:nimbus-jose-jwt:2.26') + implementation('com.madgag.spongycastle:core:1.54.0.0') + implementation('com.madgag.spongycastle:prov:1.54.0.0') + implementation('joda-time:joda-time:2.10') + + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support:support-annotations:28.0.0' + androidTestImplementation 'com.android.support.test:runner:1.0.2' } static def buildTime() { @@ -305,14 +300,8 @@ task javadoc(type: Javadoc) { options.footer('Copyright © 2016–2020 Cisco System Inc. All Rights Reserved.') exclude '**/BuildConfig.java' exclude '**/R.java' - exclude '**/internal/*.java' - exclude '**/utils/http/**' - exclude '**/utils/log/**' - exclude '**/utils/Lists.*' - exclude '**/utils/Utils.*' - exclude '**/utils/WebexId.*' - exclude '**/OAuthTestUserAuthenticator.java' - + exclude '**/internal/**' + exclude '**/utils/**' failOnError false } diff --git a/sdk/libs/cloud-apps-sdk-kms-1.0.17991.jar b/sdk/libs/cloud-apps-sdk-kms-1.0.17991.jar new file mode 100644 index 0000000000000000000000000000000000000000..6bc01c830b1f393a046728a412d3728756e13143 GIT binary patch literal 42864 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

W|)VNwUNFe*sTET#-P7I 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 literal 0 HcmV?d00001 diff --git a/sdk/libs/diagnostic-events-gson-1.0.175.jar b/sdk/libs/diagnostic-events-gson-1.0.175.jar new file mode 100644 index 0000000000000000000000000000000000000000..6f5bd1c50b2ced87e25d85c4ea66f983a09a11c6 GIT binary patch literal 188122 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 literal 0 HcmV?d00001 diff --git a/sdk/src/androidTest/java/com/ciscowebex/androidsdk/WebexTestRunner.java b/sdk/src/androidTest/java/com/ciscowebex/androidsdk/WebexTestRunner.java index f8b6ff96..d3467a82 100644 --- a/sdk/src/androidTest/java/com/ciscowebex/androidsdk/WebexTestRunner.java +++ b/sdk/src/androidTest/java/com/ciscowebex/androidsdk/WebexTestRunner.java @@ -26,10 +26,8 @@ import android.app.Application; import android.content.Context; import android.os.Environment; -import android.os.Handler; import android.support.test.runner.AndroidJUnitRunner; -import com.ciscowebex.androidsdk.auth.OAuthTestUserAuthenticator; import com.facebook.drawee.backends.pipeline.Fresco; import java.io.File; @@ -71,48 +69,48 @@ public Application newApplication(ClassLoader cl, String className, Context cont public void callApplicationOnCreate(Application app) { super.callApplicationOnCreate(app); Fresco.initialize(app.getApplicationContext()); - new Handler().post(this::loginBySparkId); + //new Handler().post(this::loginBySparkId); } private void loginBySparkId() { System.out.println("!!! loginBySparkId !!!"); - String path = Environment.getExternalStorageDirectory().getPath(); - //String path = application.getExternalFilesDir("login"); - - File file = new File(path, "login.txt"); - if (file.exists()) { - HashMap map = readKeyValueTxtToMap(file); - SparkUserEmail = (String) map.get("SparkUserEmail"); - SparkUserName = (String) map.get("SparkUserName"); - SparkUserPwd = (String) map.get("SparkUserPwd"); - CLIENT_ID = (String) map.get("CLIENT_ID"); - CLIENT_SEC = (String) map.get("CLIENT_SEC"); - REDIRECT_URL = (String) map.get("REDIRECT_URL"); - SCOPE = (String) map.get("SCOPE"); - } else { - System.out.println("!!! login file is not exist !!!"); - } - System.out.println("Test User:" + SparkUserEmail); - - OAuthTestUserAuthenticator auth = new OAuthTestUserAuthenticator(CLIENT_ID, CLIENT_SEC, SCOPE, REDIRECT_URL, - SparkUserEmail, SparkUserName, SparkUserPwd); - webex = new Webex(application, auth); - final CountDownLatch signal = new CountDownLatch(1); - auth.authorize(result -> { - if (result.isSuccessful()) { - System.out.println("loginBySparkId isSuccessful!"); - } else { - System.out.println("loginBySparkId failed! " + result.getError().toString()); - System.exit(-1); - } - signal.countDown(); - }); - - try { - signal.await(60, TimeUnit.SECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } +// String path = Environment.getExternalStorageDirectory().getPath(); +// //String path = application.getExternalFilesDir("login"); +// +// File file = new File(path, "login.txt"); +// if (file.exists()) { +// HashMap map = readKeyValueTxtToMap(file); +// SparkUserEmail = (String) map.get("SparkUserEmail"); +// SparkUserName = (String) map.get("SparkUserName"); +// SparkUserPwd = (String) map.get("SparkUserPwd"); +// CLIENT_ID = (String) map.get("CLIENT_ID"); +// CLIENT_SEC = (String) map.get("CLIENT_SEC"); +// REDIRECT_URL = (String) map.get("REDIRECT_URL"); +// SCOPE = (String) map.get("SCOPE"); +// } else { +// System.out.println("!!! login file is not exist !!!"); +// } +// System.out.println("Test User:" + SparkUserEmail); +// +// OAuthTestUserAuthenticator auth = new OAuthTestUserAuthenticator(CLIENT_ID, CLIENT_SEC, SCOPE, REDIRECT_URL, +// SparkUserEmail, SparkUserName, SparkUserPwd); +// webex = new Webex(application, auth); +// final CountDownLatch signal = new CountDownLatch(1); +// auth.authorize(result -> { +// if (result.isSuccessful()) { +// System.out.println("loginBySparkId isSuccessful!"); +// } else { +// System.out.println("loginBySparkId failed! " + result.getError().toString()); +// System.exit(-1); +// } +// signal.countDown(); +// }); +// +// try { +// signal.await(60, TimeUnit.SECONDS); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } } private HashMap readKeyValueTxtToMap(File file) { diff --git a/sdk/src/androidTest/java/com/ciscowebex/androidsdk/auth/JWTAuthenticatorTest.java b/sdk/src/androidTest/java/com/ciscowebex/androidsdk/auth/JWTAuthenticatorTest.java index bd683f83..6787c163 100644 --- a/sdk/src/androidTest/java/com/ciscowebex/androidsdk/auth/JWTAuthenticatorTest.java +++ b/sdk/src/androidTest/java/com/ciscowebex/androidsdk/auth/JWTAuthenticatorTest.java @@ -22,22 +22,30 @@ package com.ciscowebex.androidsdk.auth; +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import com.ciscowebex.androidsdk.Webex; +import com.github.benoitdion.ln.DebugLn; +import com.github.benoitdion.ln.Ln; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; -/** - * @author Allen Xiao - * @version 0.1 - */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class JWTAuthenticatorTest { private String auth_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbmRyb2lkX3Rlc3R1c2VyXzEiLCJuYW1lIjoiQW5kcm9pZFRlc3RVc2VyMSIsImlzcyI6ImNkNWM5YWY3LThlZDMtNGUxNS05NzA1LTAyNWVmMzBiMWI2YSJ9.eJ99AY9iNDhG4HjDJsY36wgqOnNQSes_PIu0DKBHBzs"; @Test public void test() { + Context context = InstrumentationRegistry.getTargetContext(); JWTAuthenticator authenticator = new JWTAuthenticator(); - authenticator.authorize(auth_token); - authenticator.getToken(System.out::println); + authenticator.authorize("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNeUpUVzEiLCJuYW1lIjoiTXlKVFcxIiwiaXNzIjoiWTJselkyOXpjR0Z5YXpvdkwzVnpMMDlTUjBGT1NWcEJWRWxQVGk4eU1EVXlNV001WVMwNU1qVXlMVFF6WkRNdE9EUmtNQzAzTUdJMU1HUTJOMkV6WlRjIiwiZXhwIjoxNjAyMTI5NzUyfQ.Exu1Wg-TTzm_zR6BhZMtMcIOExKoTEjLwUOK767lmfo"); + + + try { + Thread.sleep(100000); + } catch (InterruptedException e) { + e.printStackTrace(); + } } } \ No newline at end of file diff --git a/sdk/src/androidTest/java/com/ciscowebex/androidsdk/membership/MembershipClientTest.java b/sdk/src/androidTest/java/com/ciscowebex/androidsdk/membership/MembershipClientTest.java deleted file mode 100644 index 9aeacdc0..00000000 --- a/sdk/src/androidTest/java/com/ciscowebex/androidsdk/membership/MembershipClientTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.ciscowebex.androidsdk.membership; - -import com.ciscowebex.androidsdk.Webex; - -import org.junit.BeforeClass; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runners.MethodSorters; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import static com.ciscowebex.androidsdk.WebexTestRunner.getWebex; -import static org.junit.Assert.*; - -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class MembershipClientTest { - static Webex webex; - static MembershipClient client; - - @BeforeClass - public static void setUpBeforeClass() { - webex = getWebex(); - client = webex.memberships(); - } - - @Test - public void list() throws InterruptedException { - final CountDownLatch signal = new CountDownLatch(1); - client.list(null, null, null, 10, result -> { - if (result.isSuccessful()) { - System.out.println(result.getData()); - } else { - System.out.println(result.getError()); - } - signal.countDown(); - }); - signal.await(30, TimeUnit.SECONDS); - } - - @Test - public void testA_create() throws InterruptedException { - /* - final CountDownLatch signal = new CountDownLatch(1); - client.create("", null, null, true, result -> { - System.out.println(result); - signal.countDown(); - }); - signal.await(30, TimeUnit.SECONDS); - */ - } - - @Test - public void testB_get() throws InterruptedException { - /* - final CountDownLatch signal = new CountDownLatch(1); - client.get("", result -> { - System.out.println(result); - signal.countDown(); - }); - signal.await(30, TimeUnit.SECONDS); - */ - } - - @Test - public void testC_update() throws InterruptedException { - /* - final CountDownLatch signal = new CountDownLatch(1); - client.update("", true, result -> { - System.out.println(result); - signal.countDown(); - }); - signal.await(30, TimeUnit.SECONDS); - */ - } - - @Test - public void testD_delete() throws InterruptedException { - /* - final CountDownLatch signal = new CountDownLatch(1); - client.delete("", result -> { - System.out.println(result); - signal.countDown(); - }); - signal.await(30, TimeUnit.SECONDS); - */ - } -} \ No newline at end of file diff --git a/sdk/src/main/AndroidManifest.xml b/sdk/src/main/AndroidManifest.xml index ab9014d3..3602b81e 100755 --- a/sdk/src/main/AndroidManifest.xml +++ b/sdk/src/main/AndroidManifest.xml @@ -1,7 +1,8 @@ - + + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/Webex.java b/sdk/src/main/java/com/ciscowebex/androidsdk/Webex.java index f9e2350c..59e963cf 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/Webex.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/Webex.java @@ -22,20 +22,12 @@ package com.ciscowebex.androidsdk; -import javax.inject.Inject; - import android.app.Application; -import com.cisco.spark.android.callcontrol.model.Call; -import com.cisco.spark.android.core.BackgroundCheck; -import com.cisco.spark.android.core.LoggingInterceptor; -import com.cisco.spark.android.media.MediaEngine; -import com.cisco.spark.android.reachability.ConnectivityChangeReceiver; -import com.cisco.spark.android.util.UserAgentProvider; import com.ciscowebex.androidsdk.auth.Authenticator; -import com.ciscowebex.androidsdk.internal.DaggerSDKComponent; -import com.ciscowebex.androidsdk.internal.SDKComponent; -import com.ciscowebex.androidsdk.internal.SDKModule; +import com.ciscowebex.androidsdk.internal.reachability.BackgroundChecker; +import com.ciscowebex.androidsdk.internal.reachability.ForegroundChecker; +import com.ciscowebex.androidsdk.internal.Settings; import com.ciscowebex.androidsdk.membership.MembershipClient; import com.ciscowebex.androidsdk.membership.internal.MembershipClientImpl; import com.ciscowebex.androidsdk.message.MessageClient; @@ -43,6 +35,7 @@ import com.ciscowebex.androidsdk.people.PersonClient; import com.ciscowebex.androidsdk.people.internal.PersonClientImpl; import com.ciscowebex.androidsdk.phone.Phone; +import com.ciscowebex.androidsdk.phone.internal.MediaEngine; import com.ciscowebex.androidsdk.phone.internal.PhoneImpl; import com.ciscowebex.androidsdk.space.SpaceClient; import com.ciscowebex.androidsdk.space.internal.SpaceClientImpl; @@ -51,20 +44,11 @@ import com.ciscowebex.androidsdk.team.internal.TeamClientImpl; import com.ciscowebex.androidsdk.team.internal.TeamMembershipClientImpl; import com.ciscowebex.androidsdk.utils.Utils; -import com.ciscowebex.androidsdk.utils.log.NoLn; -import com.ciscowebex.androidsdk.utils.log.WarningLn; +import com.ciscowebex.androidsdk.utils.http.HttpClient; import com.ciscowebex.androidsdk.webhook.WebhookClient; import com.ciscowebex.androidsdk.webhook.internal.WebhookClientImpl; -import com.ciscowebex.androidsdk_commlib.SDKCommon; -import com.ciscowebex.androidsdk_commlib.SDKCommonInjector; -import com.ciscowebex.androidsdk_commlib.SDKCommonModule_ProvideOkHttpClientBuilderFactory; -import com.github.benoitdion.ln.DebugLn; -import com.github.benoitdion.ln.InfoLn; import com.github.benoitdion.ln.Ln; -import com.github.benoitdion.ln.NaturalLog; -import com.github.benoitdion.ln.ReleaseLn; -import com.webex.wme.Log; -import com.webex.wme.MediaSessionAPI; +import me.helloworld.utils.reflect.Methods; /** * Webex object is the entry point to use this Cisco Webex Android SDK. @@ -86,31 +70,19 @@ public enum LogLevel { NO, ERROR, WARNING, INFO, DEBUG_NO_HTTP_DETAILS, DEBUG, VERBOSE, ALL } - private SDKCommonInjector _injector; - - private SDKCommon _common; - - private Authenticator _authenticator; - - private PhoneImpl _phone; - - private MessageClientImpl _messages; + private Authenticator authenticator; - private MembershipClientImpl _memberships; + private PhoneImpl phone; - private SpaceClientImpl _spaces; + private MessageClientImpl messages; - @Inject - MediaEngine _mediaEngine; + private MembershipClientImpl memberships; - @Inject - BackgroundCheck _backgroundCheck; + private SpaceClientImpl spaces; - @Inject - UserAgentProvider _userAgentProvider; + private MediaEngine engine; - @Inject - ConnectivityChangeReceiver connectivityChangeReceiver; + private final BackgroundChecker checker; /** * Constructs a new Webex object with an {@link Authenticator} and Application @@ -120,22 +92,26 @@ public enum LogLevel { * @since 0.1 */ public Webex(Application application, Authenticator authenticator) { - _authenticator = authenticator; - _common = new SDKCommon(application, APP_NAME, APP_VERSION); - _common.create(); - _injector = new SDKCommonInjector<>(); - _injector.setComponent(SDKComponent.class, DaggerSDKComponent.builder().sDKModule(new SDKModule(_injector)).sDKCommonComponent(_common.getInjector().getComponent()).build()); - _injector.inject(this); - _injector.inject(authenticator); - _phone = new PhoneImpl(application.getApplicationContext(), _authenticator, _injector); - _messages = new MessageClientImpl(application.getApplicationContext(), _authenticator, _injector); - _memberships = new MembershipClientImpl(application.getApplicationContext(), _authenticator, _injector); - _spaces = new SpaceClientImpl(application.getApplicationContext(), _authenticator, _injector); - application.registerReceiver(connectivityChangeReceiver, ConnectivityChangeReceiver.getIntentFilter()); + Settings.shared.init(application.getApplicationContext()); + ForegroundChecker.init(application); + try { + Methods.invoke(authenticator, "afterAssociated", (Object[]) null); + } catch (Throwable t) { + Ln.d("Authenticator doest't support afterAssociated method"); + } + this.authenticator = authenticator; + engine = new MediaEngine(application.getApplicationContext(), LogLevel.DEBUG); + phone = new PhoneImpl(application.getApplicationContext(), authenticator, engine); + messages = new MessageClientImpl(application.getApplicationContext(), phone); + memberships = new MembershipClientImpl(phone); + spaces = new SpaceClientImpl(phone); + phone.addActivityListener(messages); + phone.addActivityListener(memberships); + phone.addActivityListener(spaces); + checker = new BackgroundChecker(application, phone); + phone.setChecker(checker); setLogLevel(LogLevel.DEBUG); - Ln.i(_userAgentProvider.get()); Ln.i(Utils.versionInfo()); - Ln.i("SDKCommon (" + com.ciscowebex.androidsdk_commlib.BuildConfig.BUILD_TIME + "-" + com.ciscowebex.androidsdk_commlib.BuildConfig.BUILD_REVISION + ")"); } /** @@ -156,9 +132,9 @@ public String getVersion() { */ public void runInBackground(boolean background) { if (background) { - _backgroundCheck.tryBackground(); + checker.tryBackground(); } else { - _backgroundCheck.tryForeground(); + checker.tryForeground(); } } @@ -167,7 +143,7 @@ public void runInBackground(boolean background) { * @since 0.1 */ public Authenticator getAuthenticator() { - return _authenticator; + return authenticator; } /** @@ -177,7 +153,7 @@ public Authenticator getAuthenticator() { * @since 0.1 */ public Phone phone() { - return _phone; + return phone; } /** @@ -189,7 +165,7 @@ public Phone phone() { * @since 0.1 */ public MessageClient messages() { - return _messages; + return messages; } /** @@ -201,7 +177,7 @@ public MessageClient messages() { * @since 0.1 */ public PersonClient people() { - return new PersonClientImpl(this._authenticator); + return new PersonClientImpl(this.authenticator); } /** @@ -213,7 +189,7 @@ public PersonClient people() { * @since 0.1 */ public MembershipClient memberships() { - return _memberships; + return memberships; } /** @@ -225,7 +201,7 @@ public MembershipClient memberships() { * @since 0.1 */ public TeamClient teams() { - return new TeamClientImpl(this._authenticator); + return new TeamClientImpl(this.authenticator); } /** @@ -237,7 +213,7 @@ public TeamClient teams() { * @since 0.1 */ public TeamMembershipClient teamMembershipClient() { - return new TeamMembershipClientImpl(this._authenticator); + return new TeamMembershipClientImpl(this.authenticator); } /** @@ -247,7 +223,7 @@ public TeamMembershipClient teamMembershipClient() { * @since 0.1 */ public WebhookClient webhooks() { - return new WebhookClientImpl(this._authenticator); + return new WebhookClientImpl(this.authenticator); } /** @@ -259,7 +235,7 @@ public WebhookClient webhooks() { * @since 0.1 */ public SpaceClient spaces() { - return _spaces; + return spaces; } /** @@ -268,55 +244,10 @@ public SpaceClient spaces() { * @param logLevel log message level */ public void setLogLevel(LogLevel logLevel) { - NaturalLog logger = new com.ciscowebex.androidsdk.utils.log.DebugLn(); - MediaSessionAPI.TraceLevelMask mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_INFO; - if (logLevel != null) { - switch (logLevel) { - case NO: - LoggingInterceptor.LogHTTPBody = false; - logger = new NoLn(); - mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_NOTRACE; - break; - case ERROR: - LoggingInterceptor.LogHTTPBody = false; - logger = new ReleaseLn(); - mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_ERROR; - break; - case WARNING: - LoggingInterceptor.LogHTTPBody = false; - logger = new WarningLn(); - mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_WARNING; - break; - case INFO: - LoggingInterceptor.LogHTTPBody = false; - logger = new InfoLn(); - mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_WARNING; - break; - case DEBUG_NO_HTTP_DETAILS: - LoggingInterceptor.LogHTTPBody = false; - logger = new com.ciscowebex.androidsdk.utils.log.DebugLn(); - mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_INFO; - break; - case DEBUG: - LoggingInterceptor.LogHTTPBody = true; - logger = new com.ciscowebex.androidsdk.utils.log.DebugLn(); - mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_INFO; - break; - case VERBOSE: - LoggingInterceptor.LogHTTPBody = true; - logger = new DebugLn(); - mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_DEBUG; - break; - case ALL: - LoggingInterceptor.LogHTTPBody = true; - logger = new DebugLn(); - mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_DETAIL; - } - } - Ln.initialize(logger); - if (_mediaEngine != null) { - _mediaEngine.setLoggingLevel(mask); - } + Ln.initialize(Utils.toLnLog(logLevel)); + HttpClient.setLogLevel(Utils.toHttpLogLevel(logLevel)); + engine.setLoggingLevel(logLevel); } + } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/WebexError.java b/sdk/src/main/java/com/ciscowebex/androidsdk/WebexError.java index 2c44c6bb..945a0a68 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/WebexError.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/WebexError.java @@ -22,8 +22,12 @@ package com.ciscowebex.androidsdk; +import com.github.benoitdion.ln.Ln; import me.helloworld.utils.Objects; import me.helloworld.utils.annotation.StringPart; +import okhttp3.ResponseBody; + +import java.io.IOException; /** * The enumeration of error types in Cisco Webex Android SDK. @@ -32,6 +36,25 @@ */ public class WebexError { + public static WebexError from(String message) { + return new WebexError(WebexError.ErrorCode.UNEXPECTED_ERROR, message); + } + + public static WebexError from(Throwable t) { + return new WebexError(WebexError.ErrorCode.UNEXPECTED_ERROR, t.toString()); + } + + public static WebexError from(okhttp3.Response res) { + StringBuilder message = new StringBuilder().append(res.code()).append("/").append(res.message()); + try { + ResponseBody body = res.body(); + message.append("/").append(body == null ? "" : body.string()); + } catch (IOException e) { + Ln.e(e); + } + return new WebexError(WebexError.ErrorCode.SERVICE_ERROR, message.toString()); + } + public enum ErrorCode { UNEXPECTED_ERROR, SERVICE_ERROR, @@ -39,10 +62,10 @@ public enum ErrorCode { } @StringPart - protected ErrorCode _code = null; + protected int errorCode = -7000; @StringPart - protected String _message = ""; + protected String message = ""; protected T _data = null; @@ -58,7 +81,7 @@ public WebexError() { * @param errorCode the error code */ public WebexError(ErrorCode errorCode) { - _code = errorCode; + this.errorCode = -7000 - errorCode.ordinal(); } /** @@ -68,8 +91,19 @@ public WebexError(ErrorCode errorCode) { * @param message the error message */ public WebexError(ErrorCode errorCode, String message) { - _code = errorCode; - _message = message; + this(errorCode); + this.message = message; + } + + /** + * The constructor with the error code and error message + * + * @param errorCode the error code + * @param message the error message + */ + public WebexError(int errorCode, String message) { + this.errorCode = errorCode; + this.message = message; } /** @@ -80,8 +114,8 @@ public WebexError(ErrorCode errorCode, String message) { * @param data the error data */ public WebexError(ErrorCode errorCode, String message, T data) { - _code = errorCode; - _message = message; + this(errorCode); + this.message = message; _data = data; } @@ -89,8 +123,8 @@ public WebexError(ErrorCode errorCode, String message, T data) { * @return The code of this error. * @since 0.1 */ - public ErrorCode getErrorCode() { - return _code; + public int getErrorCode() { + return errorCode; } /** @@ -98,7 +132,7 @@ public ErrorCode getErrorCode() { * @since 0.1 */ public String getErrorMessage() { - return _message; + return message; } /** diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/WebexEvent.java b/sdk/src/main/java/com/ciscowebex/androidsdk/WebexEvent.java index 5c938886..7e64fffe 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/WebexEvent.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/WebexEvent.java @@ -22,8 +22,8 @@ package com.ciscowebex.androidsdk; -import com.cisco.spark.android.model.Person; -import com.cisco.spark.android.model.conversation.Activity; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; +import com.ciscowebex.androidsdk.internal.model.PersonModel; import com.ciscowebex.androidsdk.utils.WebexId; /** @@ -49,8 +49,8 @@ abstract class Base implements WebexEvent { private String _actorId; - protected Base(Activity activity) { - Person person = activity.getActor(); + protected Base(ActivityModel activity) { + PersonModel person = activity.getActor(); if (person != null) { _actorId = new WebexId(WebexId.Type.PEOPLE_ID, person.getId()).toHydraId(); } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/JWTAuthenticator.java b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/JWTAuthenticator.java index a1c18603..2113f89c 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/JWTAuthenticator.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/JWTAuthenticator.java @@ -22,38 +22,28 @@ package com.ciscowebex.androidsdk.auth; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.HashMap; import java.util.Map; -import javax.inject.Inject; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Base64; -import com.cisco.spark.android.authenticator.ApiTokenProvider; -import com.cisco.spark.android.authenticator.OAuth2Tokens; -import com.cisco.spark.android.core.ApplicationController; -import com.cisco.spark.android.model.AuthenticatedUser; -import com.cisco.spark.android.model.conversation.ActorRecord; import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.WebexError; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.Settings; +import com.ciscowebex.androidsdk.internal.model.TokenModel; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.utils.Json; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.model.JWTLoginModel; import com.ciscowebex.androidsdk.internal.ResultImpl; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; -import com.ciscowebex.androidsdk_commlib.AfterInjected; import com.github.benoitdion.ln.Ln; -import com.google.gson.Gson; -import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; import me.helloworld.utils.Converter; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.http.Header; -import retrofit2.http.POST; - -import static com.ciscowebex.androidsdk.utils.Utils.checkNotNull; /** * A JSON Web Token (JWT) based authentication strategy is to be used to authenticate a user on Cisco Webex. @@ -62,17 +52,9 @@ */ public class JWTAuthenticator implements Authenticator { - private OAuth2Tokens _token = null; - - private String _jwt; - - private AuthService _authService; + private String jwt; - @Inject - ApiTokenProvider _provider; - - @Inject - ApplicationController _applicationController; + private TokenModel tokenModel; /** * Creates a new JWT authentication strategy @@ -80,7 +62,12 @@ public class JWTAuthenticator implements Authenticator { * @since 0.1 */ public JWTAuthenticator() { - _authService = new ServiceBuilder().build(AuthService.class); + } + + public void afterAssociated() { + if (tokenModel != null) { + Settings.shared.store(TokenModel.AUTHENTICATION_INFO, Json.get().toJson(tokenModel)); + } } /** @@ -99,7 +86,7 @@ public boolean isAuthorized() { */ public void authorize(@NonNull String jwt) { deauthorize(); - _jwt = jwt; + this.jwt = jwt; } /** @@ -107,12 +94,9 @@ public void authorize(@NonNull String jwt) { */ @Override public void deauthorize() { - _jwt = null; - _token = null; - if (_applicationController != null) { - Ln.d("deauthorize() clear all!"); - _applicationController.clear(); - } + this.jwt = null; + this.tokenModel = null; + Settings.shared.clear(); } /** @@ -120,10 +104,9 @@ public void deauthorize() { */ @Override public void getToken(@NonNull CompletionHandler handler) { - checkNotNull(handler, "getToken: CompletionHandler should not be null"); String jwt = getUnexpiredJwt(); if (jwt == null) { - handler.onComplete(ResultImpl.error("JWT is null")); + ResultImpl.errorInMain(handler, WebexError.from("JWT is null")); return; } String token = getUnexpiredAccessToken(); @@ -136,32 +119,17 @@ public void getToken(@NonNull CompletionHandler handler) { @Override public void refreshToken(CompletionHandler handler) { - checkNotNull(handler, "refreshToken: CompletionHandler should not be null"); String jwt = getUnexpiredJwt(); if (jwt == null) { - handler.onComplete(ResultImpl.error("JWT is null")); + ResultImpl.errorInMain(handler, WebexError.from("JWT is null")); return; } - _authService.getToken(jwt).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - JwtToken token = response.body(); - if (token == null || token.getAccessToken() == null || token.getAccessToken().isEmpty()) { - handler.onComplete(ResultImpl.error(response)); - } else { - _token = token.toOAuthToken(jwt); - if (_provider != null) { - AuthenticatedUser authenticatedUser = new AuthenticatedUser("", new ActorRecord.ActorKey(""), "", _token, "Unknown", null, 0, null); - _provider.setAuthenticatedUser(authenticatedUser); - } - handler.onComplete(ResultImpl.success(_token.getAccessToken())); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - handler.onComplete(ResultImpl.error(t)); - } + Service.Hydra.post().to("jwt/login").header("Authorization", jwt).header("Cache-Control", "no-cache") + .queue(Queue.main).model(JWTLoginModel.class).error(handler) + .async((Closure) model -> { + tokenModel = model.toToken(jwt); + Settings.shared.store(TokenModel.AUTHENTICATION_INFO, Json.get().toJson(tokenModel)); + handler.onComplete(ResultImpl.success(tokenModel.getAccessToken())); }); } @@ -175,32 +143,26 @@ public Date getExpiration() { if (jwt == null) { return null; } - if (_token == null &&_provider != null){ - AuthenticatedUser user = _provider.getAuthenticatedUserOrNull(); - if (user != null) { - _token = user.getOAuth2Tokens(); - } + if (tokenModel == null){ + tokenModel = Settings.shared.get(TokenModel.AUTHENTICATION_INFO, TokenModel.class, null); } - if (_token != null) { - return new Date(_token.getExpiresIn() * 1000); + if (tokenModel != null) { + return new Date(tokenModel.getExpiresIn() * 1000); } return null; } private @Nullable String getUnexpiredJwt() { - if (_jwt == null && _token == null && _provider != null) { - AuthenticatedUser user = _provider.getAuthenticatedUserOrNull(); - if (user != null) { - _token = user.getOAuth2Tokens(); - } + if (jwt == null && tokenModel == null) { + tokenModel = Settings.shared.get(TokenModel.AUTHENTICATION_INFO, TokenModel.class, null); } - if (_jwt == null && _token != null) { - _jwt = _token.getRefreshToken(); + if (jwt == null && tokenModel != null) { + jwt = tokenModel.getRefreshToken(); } - if (_jwt == null) { + if (jwt == null) { return null; } - Map map = parseJWT(_jwt); + Map map = parseJWT(jwt); if (map == null) { return null; } @@ -209,26 +171,23 @@ public Date getExpiration() { if (exp > 0 && exp <= (System.currentTimeMillis() / 1000)) { return null; } - } catch (Exception ignored) { - Ln.e(ignored); + } catch (Exception e) { + Ln.e(e); } - return _jwt; + return jwt; } private @Nullable String getUnexpiredAccessToken() { if (!isAuthorized()) { return null; } - if (_token == null && _provider != null) { - AuthenticatedUser user = _provider.getAuthenticatedUserOrNull(); - if (user != null) { - _token = user.getOAuth2Tokens(); - } + if (tokenModel == null) { + tokenModel = Settings.shared.get(TokenModel.AUTHENTICATION_INFO, TokenModel.class, null); } - if (_token == null || _token.getExpiresIn() <= (System.currentTimeMillis() / 1000) + (15 * 60)) { + if (tokenModel == null || tokenModel.getExpiresIn() <= (System.currentTimeMillis() / 1000) + (15 * 60)) { return null; } - return _token.getAccessToken(); + return tokenModel.getAccessToken(); } private @Nullable Map parseJWT(String jwt) { @@ -236,51 +195,7 @@ public Date getExpiration() { if (split.length != 3) { return null; } - try { - String json = new String(Base64.decode(split[1], Base64.URL_SAFE), "UTF-8"); - Gson gson = new Gson(); - Type strObjType = new TypeToken>(){}.getType(); - return gson.fromJson(json, strObjType); - } catch (UnsupportedEncodingException e) { - return null; - } - } - - @AfterInjected - private void afterInjected() { - if (_provider != null && _token != null) { - AuthenticatedUser authenticatedUser = new AuthenticatedUser("", new ActorRecord.ActorKey(""), "", _token, "Unknown", null, 0, null); - _provider.setAuthenticatedUser(authenticatedUser); - } - } - - interface AuthService { - @POST("jwt/login") - Call getToken(@Header("Authorization") String authorization); - } - - private class JwtToken { - - @SerializedName("expiresIn") - long expiresIn; - - @SerializedName("token") - String accessToken; - - public long getExpiresIn() { - return this.expiresIn; - } - - String getAccessToken() { - return this.accessToken; - } - - OAuth2Tokens toOAuthToken(String jwt) { - OAuth2Tokens tokens = new OAuth2Tokens(); - tokens.setAccessToken(this.getAccessToken()); - tokens.setExpiresIn(this.getExpiresIn() + (System.currentTimeMillis() / 1000)); - tokens.setRefreshToken(jwt); - return tokens; - } + String json = new String(Base64.decode(split[1], Base64.URL_SAFE), StandardCharsets.UTF_8); + return Json.fromJson(json, new TypeToken>(){}.getType()); } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthAuthenticator.java b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthAuthenticator.java index 26a96a96..abfae41e 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthAuthenticator.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthAuthenticator.java @@ -22,30 +22,20 @@ package com.ciscowebex.androidsdk.auth; - -import javax.inject.Inject; - import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.cisco.spark.android.authenticator.ApiTokenProvider; -import com.cisco.spark.android.authenticator.OAuth2Tokens; -import com.cisco.spark.android.core.ApplicationController; -import com.cisco.spark.android.model.AuthenticatedUser; -import com.cisco.spark.android.model.conversation.ActorRecord; import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.WebexError; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.Settings; +import com.ciscowebex.androidsdk.internal.model.TokenModel; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.utils.Json; +import com.ciscowebex.androidsdk.internal.Service; import com.ciscowebex.androidsdk.internal.ResultImpl; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; -import com.ciscowebex.androidsdk_commlib.AfterInjected; import com.github.benoitdion.ln.Ln; import me.helloworld.utils.Checker; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.http.Field; -import retrofit2.http.FormUrlEncoded; -import retrofit2.http.POST; - -import static com.ciscowebex.androidsdk.utils.Utils.checkNotNull; +import okhttp3.FormBody; /** * An OAuth based authentication strategy for authenticating a user on Cisco Webex. @@ -55,21 +45,13 @@ */ public class OAuthAuthenticator implements Authenticator { - private String _clientId; - private String _clientSecret; - private String _scope; - private String _redirectUri; - - private OAuth2Tokens _token; - private AuthService _authService; + private String clientId; + private String clientSecret; + private String scope; + private String redirectUri; - private static final String DEPARTMENT_UNKNOWN = "Unknown"; + private TokenModel tokenModel; - @Inject - ApiTokenProvider _provider; - - @Inject - ApplicationController _applicationController; /** * Creates a new OAuth authentication strategy * @@ -81,13 +63,17 @@ public class OAuthAuthenticator implements Authenticator { * @since 0.1 */ public OAuthAuthenticator(@NonNull String clientId, @NonNull String clientSecret, @NonNull String scope, @NonNull String redirectUri) { - _clientId = clientId; - _clientSecret = clientSecret; - _redirectUri = redirectUri; - _scope = scope; - _authService = new ServiceBuilder().build(AuthService.class); + this.clientId = clientId; + this.clientSecret = clientSecret; + this.redirectUri = redirectUri; + this.scope = scope; } + public void afterAssociated() { + if (tokenModel != null) { + Settings.shared.store(TokenModel.AUTHENTICATION_INFO, Json.get().toJson(tokenModel)); + } + } /** * @see Authenticator */ @@ -101,11 +87,8 @@ public boolean isAuthorized() { */ @Override public void deauthorize() { - _token = null; - if (_applicationController != null) { - Ln.d("deauthorize() clear all!"); - _applicationController.clear(); - } + tokenModel = null; + Settings.shared.clear(); } /** @@ -116,30 +99,22 @@ public void deauthorize() { * @since 0.1 */ public void authorize(@NonNull String code, @NonNull CompletionHandler handler) { - checkNotNull(handler, "CompletionHandler is null"); deauthorize(); Ln.d("Authorize: " + code); - _authService.getToken(_clientId, _clientSecret, _redirectUri, "authorization_code", code).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - _token = response.body(); - Ln.d("Authorize: " + _token + ", " + _provider); - if (_token == null || _token.getAccessToken() == null || _token.getAccessToken().isEmpty()) { - handler.onComplete(ResultImpl.error(response)); - } else { - _token.setExpiresIn(_token.getExpiresIn() + System.currentTimeMillis() / 1000); - if (_provider != null) { - AuthenticatedUser authenticatedUser = new AuthenticatedUser("", new ActorRecord.ActorKey(""), "", _token, DEPARTMENT_UNKNOWN, null, 0, null); - _provider.setAuthenticatedUser(authenticatedUser); - } - handler.onComplete(ResultImpl.success(null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - handler.onComplete(ResultImpl.error(t)); - } + FormBody formBody = new FormBody.Builder() + .add("client_id", clientId) + .add("client_secret", clientSecret) + .add("redirect_uri", redirectUri) + .add("grant_type", "authorization_code") + .add("code", code) + .build(); + Service.Hydra.post(formBody).to("access_token").queue(Queue.main).model(TokenModel.class).error(handler) + .async((Closure) model -> { + Ln.d("Authorized: " + model); + tokenModel = model; + tokenModel.setExpiresIn(tokenModel.getExpiresIn() + System.currentTimeMillis() / 1000); + Settings.shared.store(TokenModel.AUTHENTICATION_INFO, Json.get().toJson(tokenModel)); + handler.onComplete(ResultImpl.success(null)); }); } @@ -148,15 +123,14 @@ public void onFailure(Call call, Throwable t) { */ @Override public void getToken(@NonNull CompletionHandler handler) { - checkNotNull(handler, "getToken: CompletionHandler is null"); - OAuth2Tokens token = getToken(); - Ln.d("GetToken: " + token + ", " + _provider); + TokenModel token = getToken(); + Ln.d("GetToken: " + token); if (token == null) { - handler.onComplete(ResultImpl.error("Not authorized")); + ResultImpl.errorInMain(handler, WebexError.from("Not authorized")); return; } if (!Checker.isEmpty(token.getAccessToken()) && token.getExpiresIn() > (System.currentTimeMillis() / 1000) + (15 * 60)) { - handler.onComplete(ResultImpl.success(token.getAccessToken())); + ResultImpl.inMain(handler, token.getAccessToken()); return; } refreshToken(handler); @@ -164,92 +138,50 @@ public void getToken(@NonNull CompletionHandler handler) { @Override public void refreshToken(CompletionHandler handler) { - checkNotNull(handler, "refreshToken: CompletionHandler is null"); - OAuth2Tokens token = getToken(); - Ln.d("refreshToken: " + token + ", " + _provider); - if (token == null) { - handler.onComplete(ResultImpl.error("Not authorized")); + TokenModel saved = getToken(); + Ln.d("RefreshToken: " + saved); + if (saved == null) { + ResultImpl.errorInMain(handler, WebexError.from("Not authorized")); return; } - _authService.refreshToken(_clientId, _clientSecret, token.getRefreshToken(), "refresh_token").enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - _token = response.body(); - if (_token == null || Checker.isEmpty(_token.getAccessToken())) { - handler.onComplete(ResultImpl.error(response)); - } else { - _token.setExpiresIn(_token.getExpiresIn() + System.currentTimeMillis() / 1000); - if (_provider != null) { - AuthenticatedUser authenticatedUser = new AuthenticatedUser("", new ActorRecord.ActorKey(""), "", _token, DEPARTMENT_UNKNOWN, null, 0, null); - _provider.setAuthenticatedUser(authenticatedUser); - } - handler.onComplete(ResultImpl.success(_token.getAccessToken())); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - handler.onComplete(ResultImpl.error(t)); - } + FormBody formBody = new FormBody.Builder() + .add("client_id", clientId) + .add("client_secret", clientSecret) + .add("refresh_token", saved.getRefreshToken()) + .add("grant_type", "refresh_token") + .build(); + Service.Hydra.post(formBody).to("access_token").queue(Queue.main).model(TokenModel.class).error(handler).async((Closure) model -> { + Ln.d("Refreshed: " + model); + tokenModel = model; + tokenModel.setExpiresIn(tokenModel.getExpiresIn() + System.currentTimeMillis() / 1000); + Settings.shared.store(TokenModel.AUTHENTICATION_INFO, Json.get().toJson(tokenModel)); + handler.onComplete(ResultImpl.success(tokenModel.getAccessToken())); }); } - private @Nullable OAuth2Tokens getToken() { - if (_token == null && _provider != null) { - AuthenticatedUser user = _provider.getAuthenticatedUserOrNull(); - Ln.d("Get user: " + user + ", " + _provider); - if (user != null) { - _token = user.getOAuth2Tokens(); - } + private @Nullable TokenModel getToken() { + if (tokenModel == null) { + tokenModel = Settings.shared.get(TokenModel.AUTHENTICATION_INFO, TokenModel.class, null); } - if (_token == null || _token.getExpiresIn() <= (System.currentTimeMillis() / 1000) + (15 * 60)) { - Ln.d("Check token: " + _token + ", " + _provider); - if (_token != null) { - Ln.d("Check token: " + _token.getExpiresIn() + ", " + (System.currentTimeMillis() / 1000) + (15 * 60) + ", " + _provider); - } + if (tokenModel == null || tokenModel.getExpiresIn() <= (System.currentTimeMillis() / 1000) + (15 * 60)) { return null; } - return _token; - } - - @AfterInjected - private void afterInjected() { - if (_provider != null && _token != null) { - AuthenticatedUser authenticatedUser = new AuthenticatedUser("", new ActorRecord.ActorKey(""), "", _token, DEPARTMENT_UNKNOWN, null, 0, null); - _provider.setAuthenticatedUser(authenticatedUser); - } + return tokenModel; } protected String getClientId() { - return _clientId; + return clientId; } protected String getClientSecret() { - return _clientSecret; + return clientSecret; } protected String getScope() { - return _scope; + return scope; } protected String getRedirectUri() { - return _redirectUri; - } - - interface AuthService { - @FormUrlEncoded - @POST("access_token") - Call getToken(@Field("client_id") String clientId, - @Field("client_secret") String clientSecret, - @Field("redirect_uri") String redirectUri, - @Field("grant_type") String grantType, - @Field("code") String code); - - @FormUrlEncoded - @POST("access_token") - Call refreshToken(@Field("client_id") String clientId, - @Field("client_secret") String clientSecret, - @Field("refresh_token") String refreshToken, - @Field("grant_type") String grantType); + return redirectUri; } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthTestUserAuthenticator.java b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthTestUserAuthenticator.java deleted file mode 100644 index 8715ed57..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthTestUserAuthenticator.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2016-2020 Cisco Systems Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.ciscowebex.androidsdk.auth; - -import javax.inject.Inject; - -import android.os.AsyncTask; -import android.support.annotation.NonNull; -import com.cisco.spark.android.BuildConfig; -import com.cisco.spark.android.authenticator.AuthenticatedUserTask; -import com.cisco.spark.android.authenticator.OAuth2Tokens; -import com.cisco.spark.android.core.ApiClientProvider; -import com.cisco.spark.android.core.ApplicationController; -import com.cisco.spark.android.model.AuthenticatedUser; -import com.cisco.spark.android.model.LoginTestUserRequest; -import com.cisco.spark.android.model.conversation.ActorRecord; -import com.cisco.spark.android.util.LoggingLock; -import com.ciscowebex.androidsdk.CompletionHandler; -import com.ciscowebex.androidsdk.internal.ResultImpl; -import com.github.benoitdion.ln.Ln; - -/** - * Created by qimdeng on 12/7/17. - */ - -public class OAuthTestUserAuthenticator extends OAuthAuthenticator { - private LoggingLock lock = new LoggingLock(BuildConfig.DEBUG, "OAuthTestUserAuthenticator Lock"); - - private String email; - - private String name; - - private String password; - - private String scope; - - @Inject - ApiClientProvider apiClientProvider; - - @Inject - ApplicationController applicationController; - - /** - * Creates a new OAuth authentication strategy - * - * @param clientId the OAuth client id - * @param clientSecret the OAuth client secret - * @param scope space-separated string representing which permissions the application needs - * @param redirectUri the redirect URI that will be called when completing the authentication. This must match the redirect URI registered to your clientId. - * @see Cisco Webex Integration - * @since 1.3.0 - */ - public OAuthTestUserAuthenticator(@NonNull String clientId, @NonNull String clientSecret, @NonNull String scope, @NonNull String redirectUri, - @NonNull String email, @NonNull String name, @NonNull String password) { - super(clientId, clientSecret, scope, redirectUri); - this.email = email; - this.name = name; - this.password = password; - this.scope = scope; - } - - /** - * Brings up a web-based authorization view and directs the user through the OAuth process. - * - * @param handler the completion handler will be called when authentication is complete, the error to indicate if the authentication process was successful. - * @since 1.3.0 - */ - public void authorize(@NonNull CompletionHandler handler) { - Ln.d("authorize: " + _provider + " apiClientProvider: " + apiClientProvider + " applicationController: " + applicationController); - if (_provider != null && apiClientProvider != null && applicationController != null) { - deauthorize(); - new AsyncTask() { - @Override - protected Object doInBackground(Object[] objects) { - boolean ret = authenticateDrone(); - Ln.d("authenticateDrone: " + ret); - if (ret) { - handler.onComplete(ResultImpl.success(null)); - } else { - handler.onComplete(ResultImpl.error("Not authorized")); - } - return null; - } - }.execute(); - } else { - handler.onComplete(ResultImpl.error("Not authorized")); - } - } - - private boolean authenticateDrone() { - this.lock.lock(); - boolean var4; - try { - if (email != null && name != null && password != null) { - LoginTestUserRequest loginTestUserRequest = new LoginTestUserRequest(email, password); - java.lang.reflect.Field privateStringField = LoginTestUserRequest.class.getDeclaredField("scopes"); - privateStringField.setAccessible(true); - privateStringField.set(loginTestUserRequest, scope); - - OAuth2Tokens token = apiClientProvider.getUserClient().loginTestUser(loginTestUserRequest).execute().body(); - if (token != null) { - token.setExpiresIn(token.getExpiresIn() + System.currentTimeMillis() / 1000); - AuthenticatedUser authenticatedUser = new AuthenticatedUser(email, new ActorRecord.ActorKey(email), name, token, "Unknown", (String) null, 0L, (String) null); - _provider.setAuthenticatedUser(authenticatedUser); - (new AuthenticatedUserTask(applicationController)).execute(); - return true; - } - } - - return _provider.getAuthenticatedUserOrNull() != null; - } catch (Exception var16) { - Ln.e(var16); - var4 = false; - } finally { - this.lock.unlock(); - } - - return var4; - } -} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthWebViewAuthenticator.java b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthWebViewAuthenticator.java index 01db8048..7261b9c4 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthWebViewAuthenticator.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/OAuthWebViewAuthenticator.java @@ -22,21 +22,14 @@ package com.ciscowebex.androidsdk.auth; - -import javax.inject.Inject; -import javax.inject.Named; - import android.net.Uri; import android.support.annotation.NonNull; -import android.util.Log; import android.webkit.WebView; -import com.cisco.spark.android.core.Injector; import com.ciscowebex.androidsdk.CompletionHandler; import com.ciscowebex.androidsdk.auth.internal.OAuthLauncher; import com.ciscowebex.androidsdk.internal.ResultImpl; -import com.ciscowebex.androidsdk.internal.SDKScope; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; -import com.ciscowebex.androidsdk_commlib.AfterInjected; +import com.ciscowebex.androidsdk.internal.Service; +import com.github.benoitdion.ln.Ln; import me.helloworld.utils.Checker; /** @@ -48,15 +41,9 @@ */ public class OAuthWebViewAuthenticator implements Authenticator { - private static final String TAG = OAuthWebViewAuthenticator.class.getSimpleName(); - - private OAuthAuthenticator _authenticator; - - private OAuthLauncher _launcher; + private OAuthAuthenticator authenticator; - @Inject - @Named("SDK") - Injector _injector; + private OAuthLauncher launcher; /** * Creates a new OAuth authentication strategy @@ -70,8 +57,12 @@ public class OAuthWebViewAuthenticator implements Authenticator { */ public OAuthWebViewAuthenticator(@NonNull String clientId, @NonNull String clientSecret, @NonNull String scope, @NonNull String redirectUri) { super(); - _authenticator = new OAuthAuthenticator(clientId, clientSecret, scope, redirectUri); - _launcher = new OAuthLauncher(); + authenticator = new OAuthAuthenticator(clientId, clientSecret, scope, redirectUri); + launcher = new OAuthLauncher(); + } + + public void afterAssociated() { + authenticator.afterAssociated(); } /** @@ -79,7 +70,7 @@ public OAuthWebViewAuthenticator(@NonNull String clientId, @NonNull String clien */ @Override public boolean isAuthorized() { - return _authenticator.isAuthorized(); + return authenticator.isAuthorized(); } /** @@ -87,7 +78,7 @@ public boolean isAuthorized() { */ @Override public void deauthorize() { - _authenticator.deauthorize(); + authenticator.deauthorize(); } /** @@ -98,13 +89,13 @@ public void deauthorize() { * @since 0.1 */ public void authorize(@NonNull WebView view, @NonNull CompletionHandler handler) { - _launcher.launchOAuthView(view, buildCodeGrantUrl(), _authenticator.getRedirectUri(), result -> { - Log.d(TAG, "authorize: " + result); + launcher.launchOAuthView(view, buildCodeGrantUrl(), authenticator.getRedirectUri(), result -> { + Ln.d("Authorize: " + result); String code = result.getData(); if (!Checker.isEmpty(code)) { - _authenticator.authorize(code, handler); + authenticator.authorize(code, handler); } else { - handler.onComplete(ResultImpl.error(result.getError())); + ResultImpl.errorInMain(handler, result); } }); } @@ -114,28 +105,23 @@ public void authorize(@NonNull WebView view, @NonNull CompletionHandler ha */ @Override public void getToken(CompletionHandler handler) { - _authenticator.getToken(handler); + authenticator.getToken(handler); } @Override public void refreshToken(CompletionHandler handler) { - _authenticator.refreshToken(handler); + authenticator.refreshToken(handler); } private String buildCodeGrantUrl() { - Uri.Builder builder = Uri.parse(ServiceBuilder.HYDRA_URL).buildUpon(); + Uri.Builder builder = Uri.parse(Service.Hydra.endpoint(null)).buildUpon(); builder.appendPath("authorize") .appendQueryParameter("response_type", "code") - .appendQueryParameter("client_id", _authenticator.getClientId()) - .appendQueryParameter("redirect_uri", _authenticator.getRedirectUri()) - .appendQueryParameter("scope", _authenticator.getScope()) + .appendQueryParameter("client_id", authenticator.getClientId()) + .appendQueryParameter("redirect_uri", authenticator.getRedirectUri()) + .appendQueryParameter("scope", authenticator.getScope()) .appendQueryParameter("state", "androidsdkstate"); return builder.toString(); } - @AfterInjected - private void afterInjected() { - Log.d(TAG, "Inject authenticator after self injected"); - _injector.inject(_authenticator); - } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/SSOAuthenticator.java b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/SSOAuthenticator.java index 831ca869..f7d3ef04 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/SSOAuthenticator.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/SSOAuthenticator.java @@ -29,20 +29,15 @@ package com.ciscowebex.androidsdk.auth; import java.util.Map; -import javax.inject.Inject; -import javax.inject.Named; - import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.util.Log; import android.webkit.WebView; -import com.cisco.spark.android.core.Injector; import com.ciscowebex.androidsdk.CompletionHandler; import com.ciscowebex.androidsdk.auth.internal.OAuthLauncher; import com.ciscowebex.androidsdk.internal.ResultImpl; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; -import com.ciscowebex.androidsdk_commlib.AfterInjected; +import com.ciscowebex.androidsdk.internal.Service; +import com.github.benoitdion.ln.Ln; import me.helloworld.utils.Checker; /** @@ -52,11 +47,10 @@ * @since 1.3.0 */ public class SSOAuthenticator implements Authenticator { - private static final String TAG = SSOAuthenticator.class.getSimpleName(); - private OAuthAuthenticator _authenticator; + private OAuthAuthenticator authenticator; - private OAuthLauncher _launcher; + private OAuthLauncher launcher; private String email; @@ -64,10 +58,6 @@ public class SSOAuthenticator implements Authenticator { private Map additionalQueryItems; - @Inject - @Named("SDK") - Injector _injector; - /** * Creates a new OAuth authentication strategy * @@ -81,22 +71,26 @@ public class SSOAuthenticator implements Authenticator { * @see Cisco Webex Integration * @since 1.3.0 */ + @Deprecated public SSOAuthenticator(@NonNull String clientId, @NonNull String clientSecret, @NonNull String scope, @NonNull String redirectUri, @NonNull String email, @NonNull String identityProviderUri, @Nullable Map queryItems) { - super(); - _authenticator = new OAuthAuthenticator(clientId, clientSecret, scope, redirectUri); - _launcher = new OAuthLauncher(); + authenticator = new OAuthAuthenticator(clientId, clientSecret, scope, redirectUri); + launcher = new OAuthLauncher(); this.email = email; this.identityProviderUri = identityProviderUri; this.additionalQueryItems = queryItems; } + public void afterAssociated() { + authenticator.afterAssociated(); + } + /** * @see Authenticator */ @Override public boolean isAuthorized() { - return _authenticator.isAuthorized(); + return authenticator.isAuthorized(); } /** @@ -104,7 +98,7 @@ public boolean isAuthorized() { */ @Override public void deauthorize() { - _authenticator.deauthorize(); + authenticator.deauthorize(); } /** @@ -115,13 +109,13 @@ public void deauthorize() { * @since 1.3.0 */ public void authorize(@NonNull WebView view, @NonNull CompletionHandler handler) { - _launcher.launchOAuthView(view, buildCodeGrantUrl(), _authenticator.getRedirectUri(), result -> { - Log.d(TAG, "authorize: " + result); + launcher.launchOAuthView(view, buildCodeGrantUrl(), authenticator.getRedirectUri(), result -> { + Ln.d("Authorize: " + result); String code = result.getData(); if (!Checker.isEmpty(code)) { - _authenticator.authorize(code, handler); + authenticator.authorize(code, handler); } else { - handler.onComplete(ResultImpl.error(result.getError())); + ResultImpl.errorInMain(handler, result); } }); } @@ -131,12 +125,12 @@ public void authorize(@NonNull WebView view, @NonNull CompletionHandler ha */ @Override public void getToken(CompletionHandler handler) { - _authenticator.getToken(handler); + authenticator.getToken(handler); } @Override public void refreshToken(CompletionHandler handler) { - _authenticator.refreshToken(handler); + authenticator.refreshToken(handler); } /** Create the authorizationUrl by taking the original url and redirecting the request through the @@ -148,12 +142,12 @@ public void refreshToken(CompletionHandler handler) { * use their account. */ private String buildCodeGrantUrl() { - Uri.Builder orginalUrl = Uri.parse(ServiceBuilder.HYDRA_URL).buildUpon(); + Uri.Builder orginalUrl = Uri.parse(Service.Hydra.endpoint(null)).buildUpon(); orginalUrl.appendPath("authorize") .appendQueryParameter("response_type", "code") - .appendQueryParameter("client_id", _authenticator.getClientId()) - .appendQueryParameter("redirect_uri", _authenticator.getRedirectUri()) - .appendQueryParameter("scope", _authenticator.getScope()) + .appendQueryParameter("client_id", authenticator.getClientId()) + .appendQueryParameter("redirect_uri", authenticator.getRedirectUri()) + .appendQueryParameter("scope", authenticator.getScope()) .appendQueryParameter("state", "androidsdkstate"); if (email != null && !email.isEmpty()) { // Extend the original authorization url with the email parameter. @@ -169,13 +163,7 @@ private String buildCodeGrantUrl() { builder.appendQueryParameter(entry.getKey(), entry.getValue()); } } - Log.d(TAG, builder.toString()); + Ln.d(builder.toString()); return builder.toString(); } - - @AfterInjected - private void afterInjected() { - Log.d(TAG, "Inject authenticator after self injected"); - _injector.inject(_authenticator); - } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/internal/OAuthLauncher.java b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/internal/OAuthLauncher.java index e2d21a0b..f4a13b10 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/internal/OAuthLauncher.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/internal/OAuthLauncher.java @@ -41,10 +41,6 @@ import me.helloworld.utils.Checker; -/** - * Created by zhiyuliu on 01/09/2017. - */ - public class OAuthLauncher { public void launchOAuthView(WebView view, String authorizationUrl, String redirectUri, CompletionHandler handler) { @@ -54,7 +50,6 @@ public void launchOAuthView(WebView view, String authorizationUrl, String redire WebSettings webSettings = view.getSettings(); webSettings.setSupportZoom(true); webSettings.setJavaScriptEnabled(true); - // Required for javascript to work with HTML5 webSettings.setDomStorageEnabled(true); webSettings.setSaveFormData(false); webSettings.setAllowFileAccess(false); @@ -64,7 +59,7 @@ public void launchOAuthView(WebView view, String authorizationUrl, String redire view.loadUrl(authorizationUrl); } - private class BrowserWebViewClient extends WebViewClient { + private static class BrowserWebViewClient extends WebViewClient { private String _redirectUri; diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/internal/TokenAuthenticator.java b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/internal/TokenAuthenticator.java index c65f47ce..ab605539 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/auth/internal/TokenAuthenticator.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/auth/internal/TokenAuthenticator.java @@ -1,74 +1,64 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.auth.internal; import android.support.annotation.NonNull; -import com.cisco.spark.android.authenticator.ApiTokenProvider; -import com.cisco.spark.android.authenticator.OAuth2Tokens; -import com.cisco.spark.android.core.ApplicationController; -import com.cisco.spark.android.model.AuthenticatedUser; -import com.cisco.spark.android.model.conversation.ActorRecord; import com.ciscowebex.androidsdk.CompletionHandler; import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.model.TokenModel; import com.ciscowebex.androidsdk.internal.ResultImpl; -import com.ciscowebex.androidsdk_commlib.AfterInjected; -import com.github.benoitdion.ln.Ln; - -import javax.inject.Inject; public class TokenAuthenticator implements Authenticator { - @Inject - ApiTokenProvider _provider; - - @Inject - ApplicationController _applicationController; - - private OAuth2Tokens _token = null; + private TokenModel tokenModel; public TokenAuthenticator() { } public void authorize(@NonNull String token, int expire) { deauthorize(); - _token = new OAuth2Tokens(); - _token.setAccessToken(token); - _token.setExpiresIn(expire + (System.currentTimeMillis() / 1000)); - _token.setRefreshToken(token); - if (_provider != null) { - AuthenticatedUser authenticatedUser = new AuthenticatedUser("", new ActorRecord.ActorKey(""), "", _token, "Unknown", null, 0, null); - _provider.setAuthenticatedUser(authenticatedUser); - } + tokenModel = new TokenModel(token, expire + (System.currentTimeMillis() / 1000), token); } @Override public boolean isAuthorized() { - return _token != null && _token.getAccessToken() != null && System.currentTimeMillis() < (_token.getExpiresIn() * 1000); + return tokenModel != null + && tokenModel.getAccessToken() != null + && System.currentTimeMillis() < (tokenModel.getExpiresIn() * 1000); } @Override public void deauthorize() { - _token = null; - if (_applicationController != null) { - Ln.d("deauthorize() clear all!"); - _applicationController.clear(); - } + tokenModel = null; } @Override public void getToken(CompletionHandler handler) { - handler.onComplete(ResultImpl.success(_token.getAccessToken())); + handler.onComplete(ResultImpl.success(tokenModel.getAccessToken())); } @Override public void refreshToken(CompletionHandler handler) { - handler.onComplete(ResultImpl.success(_token.getRefreshToken())); + handler.onComplete(ResultImpl.success(tokenModel.getRefreshToken())); } - - @AfterInjected - private void afterInjected() { - if (_provider != null && _token != null) { - AuthenticatedUser authenticatedUser = new AuthenticatedUser("", new ActorRecord.ActorKey(""), "", _token, "Unknown", null, 0, null); - _provider.setAuthenticatedUser(authenticatedUser); - } - } - } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/AcquirePermissionActivity.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/AcquirePermissionActivity.java index c505c3ee..26de83b1 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/AcquirePermissionActivity.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/AcquirePermissionActivity.java @@ -34,20 +34,18 @@ import android.support.v4.content.ContextCompat; import android.view.WindowManager; -import com.cisco.spark.android.callcontrol.CallControlService; -import com.ciscowebex.androidsdk.phone.internal.RotationHandler; +import com.ciscowebex.androidsdk.phone.internal.UIEventHandler; import com.github.benoitdion.ln.Ln; -import javax.inject.Inject; - -/** - * Created by qimdeng on 3/1/18. - */ public class AcquirePermissionActivity extends Activity { + public static final String PERMISSION_TYPE = "permission_type"; public static final String PERMISSION_SCREEN_SHOT = "permission_screen_shot"; public static final String PERMISSION_CAMERA_MIC = "permission_camera_mic"; - public static final String CALL_DIRECTION = "call_direction"; + + public static final String ACTION_MEDIA_PERMISSION = "action_media_permission"; + public static final String PERMISSION_RESULT = "permission_result"; + public static final String CALL_KEY = "call_key"; public static final String CALL_STRING = "call_string"; public static final String CALL_TAG = "call_tag"; @@ -55,11 +53,6 @@ public class AcquirePermissionActivity extends Activity { protected static final int REQUEST_CAMERA_MIC = 0; protected static final int REQUEST_MEDIA_PROJECTION = 1; - @Inject - CallControlService _callControlService; - - private Bundle _callData; - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -71,38 +64,31 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { Ln.d("request PERMISSION_SCREEN_SHOT"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); - startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION); + if (mediaProjectionManager != null) { + startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION); + } } else { Ln.e("Android version is lower than LOLLIPOP"); finish(); } - } else if (PERMISSION_CAMERA_MIC.equals(type)) { + } + else if (PERMISSION_CAMERA_MIC.equals(type)) { Ln.d("request PERMISSION_CAMERA_MIC"); - _callData = getIntent().getBundleExtra(CALL_DATA); - int permissionCheckCamera = ContextCompat.checkSelfPermission(this, - Manifest.permission.CAMERA); - int permissionCheckMic = ContextCompat.checkSelfPermission(this, - Manifest.permission.RECORD_AUDIO); + int permissionCheckCamera = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA); + int permissionCheckMic = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO); String[] permissions = null; if (permissionCheckCamera != PackageManager.PERMISSION_GRANTED && permissionCheckMic != PackageManager.PERMISSION_GRANTED) { - permissions = new String[]{ - Manifest.permission.CAMERA, - Manifest.permission.RECORD_AUDIO - }; + permissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}; } else if (permissionCheckCamera != PackageManager.PERMISSION_GRANTED) { - permissions = new String[]{ - Manifest.permission.CAMERA - }; + permissions = new String[]{Manifest.permission.CAMERA}; } else if (permissionCheckMic != PackageManager.PERMISSION_GRANTED) { - permissions = new String[]{ - Manifest.permission.RECORD_AUDIO - }; + permissions = new String[]{Manifest.permission.RECORD_AUDIO}; } if (permissions != null) { ActivityCompat.requestPermissions(this, permissions, REQUEST_CAMERA_MIC); } else { Ln.i("Do not need request permission, and make call directly"); - RotationHandler.makeCall(_callData, true); + UIEventHandler.get().doMediaPermission(true); finish(); } } else { @@ -115,10 +101,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_MEDIA_PROJECTION) { if (resultCode == Activity.RESULT_OK) { - RotationHandler.setScreenshotPermission((Intent) data.clone()); + UIEventHandler.get().doScreenCapturePermission((Intent) data.clone()); } else { Ln.i("User cancelled screen request"); - RotationHandler.setScreenshotPermission(null); + UIEventHandler.get().doScreenCapturePermission(null); } } finish(); @@ -135,7 +121,7 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, in } } Ln.d("onRequestPermissionsResult: " + resultOk); - RotationHandler.makeCall(_callData, resultOk); + UIEventHandler.get().doMediaPermission(resultOk); } finish(); } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ActivityListener.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ActivityListener.java new file mode 100644 index 00000000..7fefb8a2 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ActivityListener.java @@ -0,0 +1,7 @@ +package com.ciscowebex.androidsdk.internal; + +import com.ciscowebex.androidsdk.internal.model.ActivityModel; + +public interface ActivityListener { + void processActivity(ActivityModel model); +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Closure.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Closure.java new file mode 100644 index 00000000..26dbc746 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Closure.java @@ -0,0 +1,5 @@ +package com.ciscowebex.androidsdk.internal; + +public interface Closure { + void invoke(T data); +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Credentials.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Credentials.java new file mode 100644 index 00000000..5032bbd9 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Credentials.java @@ -0,0 +1,80 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal; + +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.people.Person; +import com.ciscowebex.androidsdk.people.internal.PersonClientImpl; +import com.ciscowebex.androidsdk.utils.WebexId; + +public class Credentials { + + public static void auth(Authenticator authenticator, CompletionHandler callback) { + authenticator.getToken(tokenResult -> { + String token = tokenResult.getData(); + if (token == null) { + callback.onComplete(ResultImpl.error(tokenResult.getError())); + } + else { + new PersonClientImpl(authenticator).getMe(personResult -> { + Person person = personResult.getData(); + if (person == null) { + callback.onComplete(ResultImpl.error(personResult.getError())); + } + else { + callback.onComplete(ResultImpl.success(new Credentials(authenticator, person, token))); + } + }); + } + }); + } + + private Authenticator authenticator; + private String userId; + private Person person; + private String token; + + public Credentials(Authenticator authenticator, Person person, String token) { + this.authenticator =authenticator; + this.userId = WebexId.translate(person.getId()); + this.person = person; + this.token = token; + } + + public Authenticator getAuthenticator() { + return authenticator; + } + + public String getUserId() { + return userId; + } + + public Person getPerson() { + return person; + } + + public String getToken() { + return token; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Device.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Device.java new file mode 100644 index 00000000..8d71155c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Device.java @@ -0,0 +1,111 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal; + +import android.net.Uri; +import com.ciscowebex.androidsdk.internal.model.DeviceModel; +import com.ciscowebex.androidsdk.internal.model.RegionModel; +import com.github.benoitdion.ln.Ln; +import me.helloworld.utils.collection.Maps; + +import java.util.HashMap; +import java.util.Map; + +public class Device { + + public static final String DEVICE_URL = "DEVICE_URL"; + + public static final String SPARKBOARD_DEVICE_TYPE = "SPARK_BOARD"; + public static final String SPARKBOARD_MEDIA_ENGINE_TYPE = "ACANO_MEDIA_ENGINE"; + public static final String ANDROID_DEVICE_TYPE = "ANDROID"; + public static final String ANDROID_MEDIA_ENGINE_TYPE = "WME"; + public static final String UC_DEVICE_TYPE = "UC"; + public static final String TP_DEVICE_TYPE = "TP_ENDPOINT"; + public static final String PROVISIONAL_DEVICE_TYPE = "PROVISIONAL"; + public static final String SIP_DEVICE_TYPE = "SIP"; + public static final String WEBEX_DEVICE_TYPE = "WEBEX"; + public static final String WEBEX_SHARE_TYPE = "SPARK_SHARE"; + public static final String WEB_DEVICE_TYPE = "WEB"; + + private static final String MERCURY_REGISTRATION_QUERIES = "?mercuryRegistrationStatus=true"; + + private String deviceType; + + private DeviceModel deviceModel; + + private RegionModel regionModel; + + private String webSocketUrl; + + public Device(DeviceModel device, RegionModel region) { + this.deviceType = ANDROID_DEVICE_TYPE; + this.deviceModel = device; + this.regionModel = region; + this.webSocketUrl = deviceModel.getWebSocketUrl(); + if (!this.webSocketUrl.endsWith(MERCURY_REGISTRATION_QUERIES)) { + try { + this.webSocketUrl = Uri.parse(webSocketUrl + MERCURY_REGISTRATION_QUERIES).toString(); + } catch (Throwable t) { + Ln.w(t); + } + } + } + + public String getDeviceUrl() { + return deviceModel.getDeviceUrl(); + } + + public String getWebSocketUrl() { + return webSocketUrl; + } + + public String getDeviceType() { + return deviceType; + } + + public String getRegionCode() { + return regionModel.getRegionCode(); + } + + public String getCountryCode() { + return regionModel.getCountryCode(); + } + + public String getDeviceSettings() { + return deviceModel.getDeviceSettings(); + } + + public String getServiceUrl(String key) { + return deviceModel.getServiceUrl(key); + } + + public Map toJsonMap(String overwriteType) { + Map json = new HashMap<>(); + json.put("url", getDeviceUrl()); + json.put("deviceType", overwriteType == null ? getDeviceType() : overwriteType); + json.put("regionCode", getRegionCode()); + json.put("countryCode", getCountryCode()); + json.put("capabilities", Maps.makeMap("groupCallSupported", true, "sdpSupported", true)); + return json; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ErrorDetail.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ErrorDetail.java new file mode 100644 index 00000000..3313c6c2 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ErrorDetail.java @@ -0,0 +1,217 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.SparseArray; +import me.helloworld.utils.Checker; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class ErrorDetail { + public enum CustomErrorCode { + Unknown(0), + CantDeleteActivityType(1400005), + UserNotPresentInCI(1400006), + SideboardingExistingParticipant(1403001), + SideboardingFailed(1403003), + InvalidParticipantsSize(1403012), + AlreadyAnnouncementSpace(1403014), + NotAnnouncementSpace(1403015), + NotModeratorInAnnouncementSpace(1403016), + MissingEntitlement(1403021), + AssignModeratorFailed(1403022), + ActionNotAllowedIn1on1(1403023), + RoomAlreadyLocked(1403024), + UserNotModerator(1403025), + RoomNotLocked(1403027), + ClientTempIdAlreadyExists(1409001), + KmsMessageOperationFailed(1900000), + LocusInvalidLocusURL(2400002), + LocusArgumentNullOrEmpty(2400003), + LocusInvalidUser(2400004), + LocusInvalidPhoneNumberOrCountryCode(2400005), + LocusPhoneNumberInvalidCountryCode(2400007), + LocusPhoneNumberNotANumber(2400008), + LocusPhoneNumberTooShortAfterIdd(2400009), + LocusPhoneNumberTooShortNSN(2400010), + LocusPhoneNumberTooLong(2400011), + LocusInvalidDialableKey(2400012), + LocusInvalidMeetingLink(2400013), + LocusInvalidSinceOrSequenceHashInRequest(2400014), + LocusInvalidLocusId(2400015), + LocusInvalidMeetingIdFormat(2400020), + LocusInvalidSipUrlFormat(2400021), + LocusEmptyInviteeRecord(2400022), + LocusEmptyInviteeAddress(2400023), + LocusInvalidInviteeAddress(2400025), + LocusInvalidAttendeeId(2400026), + LocusInvalidInLobby(2400027), + LocusInvalidInvitee(2400032), + LocusInvalidAddress(2400033), + LocusNoInviteeOrAddress(2400033), + LocusNotPartOfRoster(2401002), + LocusExceededMaxNumberParticipantsFreeUser(2403001), + LocusExceededMaxNumberParticipantsPaidUser(2403002), + LocusExceededMaxNumberParticipantsTeamMember(2403003), + LocusMeetingIsInactive(2403004), + LocusOneOnOneToSelfNotAllowed(2403007), + LocusUserIsNotAuthorized(2403010), + LocusMeetingNotFound(2403014), + LocusInvalidWebExSite(2403015), + LocusPstnCallingNotEnabled(2403030), + LocusUserNotAuthorizedForMedia(2403039), + LocusMeetingIsMigrated(2409018), + LocusExceededMaxRosterSizeFreePaidUser(2423001), + LocusExceededMaxRosterSizeTeamMember(2423002), + LocusMeetingIsLocked(2423003), + LocusLockedWhileTerminatingPreviousMeeting(2423004), + LocusRequiresModeratorPINOrGuest(2423005), + LocusRequiresModeratorPINorGuestPIN(2423006), + LocusPMRAccountSuspended(2423008), + LocusMeetingNotStarted(2423010), + LocusRequiresWebexLogin(2423011), + LocusHostSessionLimitExceeded(2423012), + NewUserInDirSycnedOrg(400110), + CreatorFromBlockedOrg(7400901), + UserFromBlockedOrg(7400902), + OwnerBlockingOtherOrg(7400903), + ParticipantFromBlockingOrg(7400904); + + private int errorCode; + + private static final SparseArray errorCodes = new SparseArray<>(); + + static { + for (ErrorDetail.CustomErrorCode errorCode : ErrorDetail.CustomErrorCode.values()) { + errorCodes.put(errorCode.getErrorCode(), errorCode); + } + } + + CustomErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + public int getErrorCode() { + return errorCode; + } + + @NonNull + public static ErrorDetail.CustomErrorCode fromErrorCode(int errorCode) { + ErrorDetail.CustomErrorCode code = errorCodes.get(errorCode); + return code == null ? Unknown : code; + } + } + + @Nullable + private Integer errorCode; + private String message; + @Nullable + private List errors; + private String trackingId; + private String stackTrace; + + public ErrorDetail(@Nullable Integer errorCode, String message, List errors, String trackingId, String stackTrace) { + this.errorCode = errorCode; + this.message = message; + this.errors = errors; + this.trackingId = trackingId; + this.stackTrace = stackTrace; + } + + public int getErrorCode() { + return errorCode == null ? ErrorDetail.CustomErrorCode.Unknown.getErrorCode() : errorCode; + } + + @NonNull + public ErrorDetail.CustomErrorCode extractCustomErrorCode() { + return ErrorDetail.CustomErrorCode.fromErrorCode(getErrorCode()); + } + + public String getMessage() { + return message; + } + + public String getTrackingId() { + return trackingId; + } + + public String getStackTrace() { + return stackTrace; + } + + @Nullable + public List getErrors() { + return errors; + } + + private static class ErrorDescription { + private String errorCode; + private String description; + + public String getErrorCode() { + return errorCode; + } + + public String getDescription() { + return description; + } + } + + public HashMap> extractBlockedParticipantIdsFromErrorDescription() { + HashMap> blockedParticipantsWithOrgIDMap = new HashMap<>(); + ArrayList blockedParticipantIds = null; + String orgID = null; + for (ErrorDetail.ErrorDescription errorDescription : errors) { + if (errorDescription != null && !Checker.isEmpty(errorDescription.description)) { + List orgIDWithParticipantIDList = convertStringToList(errorDescription.description); + if (!Checker.isEmpty(orgIDWithParticipantIDList)) { + orgID = orgIDWithParticipantIDList.get(0); + if (!Checker.isEmpty(orgID)) { + if (!blockedParticipantsWithOrgIDMap.containsKey(orgID)) { + blockedParticipantIds = new ArrayList<>(); + blockedParticipantIds.add(orgIDWithParticipantIDList.get(1)); + blockedParticipantsWithOrgIDMap.put(orgID, blockedParticipantIds); + } else { + blockedParticipantIds = blockedParticipantsWithOrgIDMap.get(orgID); + blockedParticipantIds.add(orgIDWithParticipantIDList.get(1)); + } + } + } + } + } + return blockedParticipantsWithOrgIDMap; + } + + private static List convertStringToList(String listAsString) { + listAsString = listAsString.replaceAll("\\s+",""); + if (!Checker.isEmpty(listAsString)) { + return new ArrayList(Arrays.asList(listAsString.split(","))); + } + return null; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/MetricsClient.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/MetricsClient.java deleted file mode 100644 index b4157895..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/MetricsClient.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2016-2020 Cisco Systems Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.ciscowebex.androidsdk.internal; - -import java.util.List; -import java.util.Map; - -import com.ciscowebex.androidsdk.auth.Authenticator; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; -import com.github.benoitdion.ln.Ln; - -import me.helloworld.utils.collection.Maps; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.http.Body; -import retrofit2.http.Header; -import retrofit2.http.POST; - -public class MetricsClient { - - private Authenticator _authenticator; - - private MetricsService _service; - - public MetricsClient(Authenticator authenticator, String url) { - _authenticator = authenticator; - _service = new ServiceBuilder().baseURL(url).build(MetricsService.class); - } - - public void post(List> metrics) { - _authenticator.getToken(result -> { - String token = result.getData(); - if (token != null) { - _service.post("Bearer " + token, Maps.makeMap("metrics", metrics)).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - Ln.d("%s", response); - } - - @Override - public void onFailure(Call call, Throwable t) { - Ln.e(t); - } - }); - } - }); - } - - interface MetricsService { - - @POST("metrics") - Call post(@Header("Authorization") String authorization, @Body Map parameters); - } - -} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/MetricsService.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/MetricsService.java new file mode 100644 index 00000000..55b88876 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/MetricsService.java @@ -0,0 +1,29 @@ +package com.ciscowebex.androidsdk.internal; + +import android.support.annotation.NonNull; +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.github.benoitdion.ln.Ln; +import me.helloworld.utils.collection.Maps; + +import java.util.List; +import java.util.Map; + +public class MetricsService { + + private Authenticator authenticator; + + public MetricsService(@NonNull Authenticator authenticator) { + this.authenticator = authenticator; + } + + public void post(List> metrics) { + Service.Metrics.post(Maps.makeMap("metrics", metrics)).to("metrics") + .auth(authenticator) + .queue(Queue.main) + .error((CompletionHandler) result -> Ln.e("" + result.getError())) + .async((Closure) data -> Ln.e("" + data)); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ResultImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ResultImpl.java index 7e154888..714cbf7b 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ResultImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ResultImpl.java @@ -22,15 +22,15 @@ package com.ciscowebex.androidsdk.internal; -import java.io.IOException; - +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.ciscowebex.androidsdk.CompletionHandler; import com.ciscowebex.androidsdk.Result; import com.ciscowebex.androidsdk.WebexError; -import com.github.benoitdion.ln.Ln; +import com.ciscowebex.androidsdk.internal.queue.Queue; import me.helloworld.utils.Objects; import me.helloworld.utils.annotation.StringPart; -import retrofit2.Response; public class ResultImpl implements Result { @@ -39,19 +39,59 @@ public static Result success(T data) { } public static Result error(String message) { - return new ResultImpl<>(null, new WebexError(WebexError.ErrorCode.UNEXPECTED_ERROR, message)); + return new ResultImpl<>(null, WebexError.from(message)); } public static Result error(Throwable t) { - return new ResultImpl<>(null, makeError(t)); + return new ResultImpl<>(null, WebexError.from(t)); } public static Result error(WebexError error) { return new ResultImpl<>(null, error); } - public static Result error(Response response) { - return new ResultImpl<>(null, makeError(response)); + public static Result error(okhttp3.Response response) { + return new ResultImpl<>(null, WebexError.from(response)); + } + + public static Result error(Result result) { + WebexError error = result == null ? WebexError.from("No Result") : result.getError(); + if (error == null) { + error = WebexError.from("No Result"); + } + return new ResultImpl<>(null, error); + } + + public static void inMain(@NonNull CompletionHandler handler, @Nullable T data) { + Queue.main.run(() -> handler.onComplete(ResultImpl.success(data))); + } + + public static void inMain(@NonNull CompletionHandler handler, @Nullable Result result) { + if (result == null) { + errorInMain(handler, "No Result"); + } + else if (result.getError() != null) { + errorInMain(handler, result); + } + else { + inMain(handler, result.getData()); + } + } + + public static void errorInMain(@NonNull CompletionHandler handler, @NonNull Throwable t) { + errorInMain(handler, WebexError.from(t)); + } + + public static void errorInMain(@NonNull CompletionHandler handler, @NonNull String message) { + errorInMain(handler, WebexError.from(message)); + } + + public static void errorInMain(@NonNull CompletionHandler handler, @NonNull Result result) { + Queue.main.run(() -> handler.onComplete(ResultImpl.error(result))); + } + + public static void errorInMain(@NonNull CompletionHandler handler, @NonNull WebexError error) { + Queue.main.run(() -> handler.onComplete(ResultImpl.error(error))); } @StringPart @@ -81,18 +121,4 @@ public String toString() { return Objects.toStringByAnnotation(this); } - private static WebexError makeError(Throwable t) { - return new WebexError(WebexError.ErrorCode.UNEXPECTED_ERROR, t.toString()); - } - - private static WebexError makeError(Response res) { - StringBuilder message = new StringBuilder().append(res.code()).append("/").append(res.message()); - try { - String body = res.errorBody().string(); - message.append("/").append(body); - } catch (IOException e) { - Ln.e(e); - } - return new WebexError(WebexError.ErrorCode.SERVICE_ERROR, message.toString()); - } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKComponent.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKComponent.java deleted file mode 100644 index 6b1f6c51..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKComponent.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.ciscowebex.androidsdk.internal; - -import com.ciscowebex.androidsdk.Webex; -import com.ciscowebex.androidsdk.auth.*; -import com.ciscowebex.androidsdk.auth.internal.TokenAuthenticator; -import com.ciscowebex.androidsdk.membership.internal.MembershipClientImpl; -import com.ciscowebex.androidsdk.message.Message; -import com.ciscowebex.androidsdk.message.internal.CallbackablePostCommentOperation; -import com.ciscowebex.androidsdk.message.internal.CallbackablePostContentActivityOperation; -import com.ciscowebex.androidsdk.message.internal.MessageClientImpl; -import com.ciscowebex.androidsdk.message.internal.MessageMarkReadOperation; -import com.ciscowebex.androidsdk.phone.internal.CallImpl; -import com.ciscowebex.androidsdk.phone.internal.PhoneImpl; -import com.ciscowebex.androidsdk.space.internal.SpaceClientImpl; -import com.ciscowebex.androidsdk_commlib.internal.SDKCommonComponent; -import dagger.Component; - -@SDKScope -@Component(dependencies = SDKCommonComponent.class, modules = SDKModule.class) -public interface SDKComponent { - - Webex inject(Webex webex); - - JWTAuthenticator inject(JWTAuthenticator authenticator); - - OAuthAuthenticator inject(OAuthAuthenticator authenticator); - - OAuthWebViewAuthenticator inject(OAuthWebViewAuthenticator authenticator); - - OAuthTestUserAuthenticator inject(OAuthTestUserAuthenticator authenticator); - - SSOAuthenticator inject(SSOAuthenticator authenticator); - - TokenAuthenticator inject(TokenAuthenticator authenticator); - - PhoneImpl inject(PhoneImpl phone); - - CallImpl inject(CallImpl call); - - MessageClientImpl inject(MessageClientImpl client); - - MessageMarkReadOperation inject(MessageMarkReadOperation operation); - - CallbackablePostCommentOperation inject(CallbackablePostCommentOperation operation); - - CallbackablePostContentActivityOperation inject(CallbackablePostContentActivityOperation operation); - - MembershipClientImpl inject(MembershipClientImpl client); - - SpaceClientImpl inject(SpaceClientImpl client); -} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKModule.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKModule.java deleted file mode 100644 index 47748452..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKModule.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.ciscowebex.androidsdk.internal; - -import com.cisco.spark.android.core.Injector; -import com.ciscowebex.androidsdk_commlib.SDKCommonInjector; -import dagger.Module; -import dagger.Provides; - -import javax.inject.Named; -import javax.inject.Singleton; - -@Module -public class SDKModule { - - private SDKCommonInjector injector; - - public SDKModule(SDKCommonInjector injector) { - this.injector = injector; - } - - @Provides - @SDKScope - @Named("SDK") - Injector provideInjector() { - return injector; - } -} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKScope.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKScope.java deleted file mode 100644 index e382fba6..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/SDKScope.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.ciscowebex.androidsdk.internal; - -import javax.inject.Scope; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Scope -@Retention(RetentionPolicy.RUNTIME) -public @interface SDKScope { -} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Service.kt b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Service.kt new file mode 100644 index 00000000..ad5721f3 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Service.kt @@ -0,0 +1,98 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal + +import com.ciscowebex.androidsdk.BuildConfig +import com.ciscowebex.androidsdk.utils.Json +import okhttp3.MediaType +import okhttp3.Request +import okhttp3.RequestBody + +enum class Service { + + Hydra, Region, Wdm, Kms, Locus, Conv, Metrics, CalliopeDiscorey, Common; + + fun get(vararg paths: String?): ServiceReqeust { + return ServiceReqeust(this, Request.Builder().get()).to(*paths) + } + + fun delete(vararg paths: String?): ServiceReqeust { + return ServiceReqeust(this, Request.Builder().delete()).to(*paths) + } + + @JvmOverloads + fun post(o: Any? = null): ServiceReqeust { + return ServiceReqeust(this, Request.Builder().post(toBody(o))) + } + + @JvmOverloads + fun put(o: Any? = null): ServiceReqeust { + return ServiceReqeust(this, Request.Builder().put(toBody(o))) + } + + @JvmOverloads + fun patch(o: Any? = null): ServiceReqeust { + return ServiceReqeust(this, Request.Builder().patch(toBody(o))) + } + + private fun toBody(o: Any?): RequestBody { + return when (o) { + null -> RequestBody.create(null, byteArrayOf()) + is RequestBody -> o + else -> RequestBody.create(MediaType.get("application/json; charset=utf-8"), Json.get().toJson(o)) + } + } + + fun endpoint(device: Device?): String { + return when (this) { + Region -> "https://ds.ciscospark.com/v1" + Wdm -> if (BuildConfig.INTEGRATION_TEST) "https://wdm-intb.ciscospark.com/wdm/api/v1" else "https://wdm-a.wbx2.com/wdm/api/v1" + Hydra -> if (BuildConfig.INTEGRATION_TEST) "https://apialpha.ciscospark.com/v1" else "https://api.ciscospark.com/v1" + Locus -> dynamicEndpoint(device, "https://locus-a.wbx2.com/locus/api/v1") + Metrics -> dynamicEndpoint(device, "https://metrics-a.wbx2.com/metrics/api/v1") + CalliopeDiscorey -> dynamicEndpoint(device, "https://calliope-a.wbx2.com/calliope/api/discovery/v1") + Kms -> { + val defaultValue = if (BuildConfig.INTEGRATION_TEST) "https://encryption-intb.ciscospark.com/encryption/api/v1" else "https://encryption-a.wbx2.com/encryption/api/v1" + dynamicEndpoint(device, defaultValue) + } + Conv -> { + val defaultValue = if (BuildConfig.INTEGRATION_TEST) "https://conversation-intb.ciscospark.com/conversation/api/v1" else "https://conv-a.wbx2.com/conversation/api/v1" + dynamicEndpoint(device, defaultValue) + } + else -> "" + } + } + + private fun dynamicEndpoint(device: Device?, defaultValue: String): String { + return device?.getServiceUrl(key()) ?: defaultValue + } + + private fun key(): String { + return when (this) { + Kms -> "encryptionServiceUrl" + Conv -> "conversationServiceUrl" + CalliopeDiscorey -> "calliopeDiscoveryServiceUrl" + else -> name + "ServiceUrl" + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ServiceReqeust.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ServiceReqeust.java new file mode 100644 index 00000000..a0ae49fe --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/ServiceReqeust.java @@ -0,0 +1,214 @@ +package com.ciscowebex.androidsdk.internal; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.WebexError; +import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.internal.queue.SerialQueue; +import com.ciscowebex.androidsdk.utils.Json; +import com.ciscowebex.androidsdk.utils.Utils; +import com.ciscowebex.androidsdk.utils.http.HttpClient; +import com.github.benoitdion.ln.Ln; +import okhttp3.*; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.*; + +public class ServiceReqeust { + + private final Service service; + + private String url; + + private final List paths = new ArrayList<>(); + + private final Map queries = new HashMap<>(); + + private RequestBody body; + + private Device device; + + private Authenticator authenticator; + + private CompletionHandler errorHandler; + + private Queue queue; + + private Type typeOfModel; + + private Request.Builder builder; + + public ServiceReqeust(Service service, Request.Builder builder) { + this.service = service; + this.builder = builder; + } + + public ServiceReqeust url(String url) { + this.url = url; + return this; + } + + public ServiceReqeust to(String... paths) { + this.paths.addAll(Arrays.asList(paths)); + return this; + } + + public ServiceReqeust with(String key, String value) { + if (key != null && value != null) { + queries.put(key, value); + } + return this; + } + + public ServiceReqeust header(String key, String value) { + if (key != null && value != null) { + builder.header(key, value); + } + return this; + } + + public ServiceReqeust auth(Authenticator authenticator) { + this.authenticator = authenticator; + return this; + } + + public ServiceReqeust error(CompletionHandler handler) { + this.errorHandler = handler; + return this; + } + + public ServiceReqeust queue(Queue queue) { + this.queue = queue; + return this; + } + + public ServiceReqeust device(Device device) { + this.device = device; + return this; + } + + public ServiceReqeust model(Type typeOfModel) { + this.typeOfModel = typeOfModel; + return this; + } + + public ServiceReqeust model(Class typeOfModel) { + this.typeOfModel = typeOfModel; + return this; + } + + public void async(Closure closure) { + String base = this.url; + if (base == null && service != null) { + base = service.endpoint(device); + } + HttpUrl.Builder url = HttpUrl.parse(base).newBuilder(); + if (paths.size() > 0) { + url.addPathSegments(Utils.join("/", paths)); + } + if (queries.size() > 0) { + for (Map.Entry entry : queries.entrySet()) { + url.addQueryParameter(entry.getKey(), entry.getValue()); + } + } + builder.url(url.build()); + + if (authenticator == null) { + async(builder.build(), false, closure); + } + else { + authenticator.getToken(tokenResult -> { + String token = tokenResult.getData(); + if (token == null) { + doError(tokenResult.getError() == null ? WebexError.from("Token is null") : tokenResult.getError()); + } else { + builder.header("Authorization", "Bearer " + token); + async(builder.build(), true, closure); + } + }); + } + } + + private void async(Request request, boolean refresh, Closure closure) { + HttpClient.client.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + doError(WebexError.from(e)); + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.code() == 401 && refresh && authenticator != null) { + authenticator.refreshToken(refreshResult -> { + String refreshedToken = refreshResult.getData(); + if (refreshedToken == null) { + doError(refreshResult.getError() == null ? WebexError.from("Token is null") : refreshResult.getError()); + } else { + async(request.newBuilder().header("Authorization", "Bearer " + refreshedToken).build(), false, closure); + } + }); + } + else if (response.isSuccessful()) { + try { + ResponseBody body = response.body(); + if (typeOfModel == Response.class) { + doResult(closure, (M) response); + } else if (typeOfModel == ResponseBody.class) { + doResult(closure, (M) body); + } else if (typeOfModel == null || typeOfModel == Void.class || typeOfModel == void.class) { + doResult(closure, null); + } else { + String data = body == null ? null : body.string(); + if (data == null) { + doError(WebexError.from("No body in the response")); + } else { + M model = Json.fromJson(data, typeOfModel); + if (model == null) { + doError(WebexError.from("Illegal body in the response")); + } else { + doResult(closure, model); + } + } + } + } catch (Throwable t) { + doError(WebexError.from(t)); + } + } else { + doError(WebexError.from(response)); + } + } + }); + } + + private void doError(@NonNull WebexError error) { + Ln.e("HTTP Error: " + error); + if (errorHandler != null) { + if (queue == null) { + Queue.main.run(() -> errorHandler.onComplete(ResultImpl.error(error))); + return; + } + if (queue instanceof SerialQueue) { + Queue.main.run(() -> { + errorHandler.onComplete(ResultImpl.error(error)); + queue.yield(); + }); + } else { + queue.run(() -> errorHandler.onComplete(ResultImpl.error(error))); + } + } + } + + private void doResult(Closure modelCallback, @Nullable M1 model) { + if (modelCallback != null) { + if (queue == null || queue instanceof SerialQueue) { + modelCallback.invoke(model); + return; + } + queue.run(() -> modelCallback.invoke(model)); + } + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Settings.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Settings.java new file mode 100644 index 00000000..c6657ffb --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/Settings.java @@ -0,0 +1,93 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal; + +import android.content.Context; +import android.content.SharedPreferences; +import com.ciscowebex.androidsdk.Webex; +import com.ciscowebex.androidsdk.utils.Json; +import me.helloworld.utils.Objects; + +import static android.content.Context.MODE_PRIVATE; + +public class Settings { + + public static Settings shared = new Settings(); + + private SharedPreferences store; + + private Settings() {} + + public void init(Context context) { + this.store = context.getSharedPreferences(Webex.class.getPackage().getName(), MODE_PRIVATE); + } + + public void store(String key, String value) { + if (store != null) { + store.edit().putString(key, value).apply(); + } + } + + public void store(String key, boolean value) { + if (store != null) { + store.edit().putBoolean(key, value).apply(); + } + } + + public void clear(String key) { + if (store != null) { + store.edit().remove(key).apply(); + } + } + + public void clear() { + if (store != null) { + store.edit().clear().apply(); + } + } + + public String get(String key, String defaultValue) { + if (store != null) { + return store.getString(key, defaultValue); + } + return defaultValue; + } + + public boolean get(String key, boolean defaultValue) { + if (store != null) { + return store.getBoolean(key, defaultValue); + } + return defaultValue; + } + + public T get(String key, Class clazz, T defaultValue) { + if (store != null) { + String value = store.getString(key, null); + if (value != null) { + return Objects.defaultIfNull(Json.fromJson(value, clazz), defaultValue); + } + } + return defaultValue; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/MercuryEventAdapter.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/MercuryEventAdapter.java new file mode 100644 index 00000000..7fa97fdf --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/MercuryEventAdapter.java @@ -0,0 +1,87 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.adaptor; + +import com.ciscowebex.androidsdk.internal.mercury.*; +import com.ciscowebex.androidsdk.utils.Json; +import com.github.benoitdion.ln.Ln; +import com.google.gson.*; +import me.helloworld.utils.Checker; + +import java.lang.reflect.Type; + +public class MercuryEventAdapter implements JsonDeserializer { + + public static class MercuryEventTypeAdapter implements JsonDeserializer, JsonSerializer { + + @Override + public MercuryEvent.Type deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) { + String eventTypeString = jsonElement.getAsString(); + return MercuryEvent.Type.fromString(eventTypeString); + } + + @Override + public JsonElement serialize(MercuryEvent.Type src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.toString()); + } + } + + @Override + public MercuryEvent deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) { + JsonObject object = jsonElement.getAsJsonObject(); + JsonElement eventTypeElement = object.get("eventType"); + if (eventTypeElement == null) { + return null; + } + String eventType = eventTypeElement.getAsString(); + if (Checker.isEmpty(eventType)) { + Ln.d("No eventType in Mercury payload."); + return null; + } + Ln.d("Mercury event type: %s", eventType); + MercuryEvent event = null; + if (eventType.equals(MercuryEvent.Type.CONVERSATION_ACTIVITY.phrase())) { + event = jsonDeserializationContext.deserialize(jsonElement, MercuryActivityEvent.class); + } + else if (eventType.equals(MercuryEvent.Type.KMS_MESSAGE.phrase())) { + event = jsonDeserializationContext.deserialize(jsonElement, MercuryKmsMessageEvent.class); + } + else if (eventType.equals(MercuryEvent.Type.KEY_PUSH.phrase())) { + jsonElement = Json.extractJsonObjectFromString(jsonElement); + event = jsonDeserializationContext.deserialize(jsonElement, MercuryKmsPushEvent.class); + } + else if (eventType.equals(MercuryEvent.Type.KMS_ACK.phrase())) { + event = jsonDeserializationContext.deserialize(jsonElement, MercuryKmsAckEvent.class); + } + else if (eventType.startsWith("locus")) { + event = jsonDeserializationContext.deserialize(jsonElement, MercuryLocusEvent.class); + } + else if (eventType.equals(MercuryEvent.Type.START_TYPING.phrase()) || eventType.equals(MercuryEvent.Type.STOP_TYPING.phrase())) { + event = jsonDeserializationContext.deserialize(jsonElement, MercuryTypingEvent.class); + } + else { + Ln.d("Unsupport mercury event: %s", eventType); + } + return event; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/ObjectModelAdapter.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/ObjectModelAdapter.java new file mode 100644 index 00000000..02962db2 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/ObjectModelAdapter.java @@ -0,0 +1,101 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.adaptor; + +import android.net.Uri; +import com.ciscowebex.androidsdk.internal.model.*; +import com.google.gson.*; + +import java.lang.reflect.Type; +import java.util.Date; + +public class ObjectModelAdapter implements JsonDeserializer, JsonSerializer { + + private static Gson gson = new GsonBuilder() + .registerTypeAdapter(Date.class, new SimpleAdaptor.DateType()) + .registerTypeHierarchyAdapter(Uri.class, new SimpleAdaptor.UriType()) + .create(); + + @Override + public ObjectModel deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + JsonObject object = jsonElement.getAsJsonObject(); + JsonElement objectTypeElement = object.get("objectType"); + String objectType = objectTypeElement != null ? objectTypeElement.getAsString() : ""; + + if (ObjectModel.Type.person.equals(objectType)) { + return jsonDeserializationContext.deserialize(jsonElement, PersonModel.class); + } + else if (ObjectModel.Type.team.equals(objectType)) { + return jsonDeserializationContext.deserialize(jsonElement, TeamModel.class); + } + else if (ObjectModel.Type.conversation.equals(objectType)) { + return jsonDeserializationContext.deserialize(jsonElement, ConversationModel.class); + } + else if (ObjectModel.Type.comment.equals(objectType)) { + return jsonDeserializationContext.deserialize(jsonElement, CommentModel.class); + } + else if (ObjectModel.Type.activity.equals(objectType) || object.has("verb")) { + return jsonDeserializationContext.deserialize(jsonElement, ActivityModel.class); + } + else if (ObjectModel.Type.file.equals(objectType)) { + return jsonDeserializationContext.deserialize(jsonElement, FileModel.class); + } + else if (ObjectModel.Type.content.equals(objectType)) { + return jsonDeserializationContext.deserialize(jsonElement, ContentModel.class); + } + else if (ObjectModel.Type.spaceProperty.equals(objectType)) { + return jsonDeserializationContext.deserialize(jsonElement, SpacePropertyModel.class); + } + else if (ObjectModel.Type.groupMention.equals(objectType)) { + return jsonDeserializationContext.deserialize(jsonElement, GroupMentionModel.class); + } + else { + ObjectModel ret = new ObjectModel(objectType); + ret.setId(getField(object, "id")); + ret.setDisplayName(getField(object, "displayName")); + JsonElement urlElement = object.get("url"); + if (urlElement != null) { + ret.setUrl(jsonDeserializationContext.deserialize(urlElement, Uri.class)); + } + JsonElement publishedElement = object.get("published"); + if (publishedElement != null) { + ret.setPublished(jsonDeserializationContext.deserialize(publishedElement, Date.class)); + } + return ret; + } + } + + public JsonElement serialize(ObjectModel model, Type typeOfId, JsonSerializationContext context) { + if (model instanceof ContentModel) { + return context.serialize(model, ContentModel.class); + } else { + return gson.toJsonTree(model); + } + } + + private String getField(JsonObject object, String name) { + JsonPrimitive field = object.getAsJsonPrimitive(name); + return field != null ? field.getAsString() : null; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/SimpleAdaptor.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/SimpleAdaptor.java new file mode 100644 index 00000000..28a82e75 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/adaptor/SimpleAdaptor.java @@ -0,0 +1,93 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.adaptor; + +import android.net.Uri; +import com.ciscowebex.androidsdk.internal.model.LocusKeyModel; +import com.ciscowebex.androidsdk.utils.DateUtils; +import com.google.gson.*; + +import java.lang.reflect.Type; +import java.text.DateFormat; +import java.util.Date; + +public class SimpleAdaptor { + + public static class DateType implements JsonSerializer { + + private ThreadLocal threadLocalDateFormat = new ThreadLocal() { + @Override + protected DateFormat initialValue() { + return DateUtils.buildIso8601Format(); + } + }; + + @Override + public JsonElement serialize(Date date, Type type, JsonSerializationContext jsonSerializationContext) { + return date == null ? null : new JsonPrimitive(threadLocalDateFormat.get().format(date)); + } + } + +// public static class InstantType implements JsonSerializer, JsonDeserializer { +// public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) { +// return new JsonPrimitive(src.toString()); +// } +// +// public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { +// return json.getAsString() != null && !json.getAsString().isEmpty() ? Instant.parse(json.getAsString()) : null; +// } +// } + + public static class UriType implements JsonDeserializer, JsonSerializer { + @Override + public Uri deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + String uriString = json.getAsString(); + try { + return Uri.parse(uriString); + } catch (Exception e) { + throw new JsonSyntaxException(uriString, e); + } + } + + @Override + public JsonElement serialize(Uri src, Type typeOfSrc, JsonSerializationContext context) { + return src == null ? null : new JsonPrimitive(src.toString()); + } + } + + public static class LocusKeyType implements JsonDeserializer, JsonSerializer { + @Override + public LocusKeyModel deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + String uriString = json.getAsString(); + return new LocusKeyModel(uriString); + } + + @Override + public JsonElement serialize(LocusKeyModel src, Type typeOfSrc, JsonSerializationContext context) { + if (src == null) { + return null; + } + return new JsonPrimitive(src.getUrl()); + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/CryptoUtils.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/CryptoUtils.java new file mode 100644 index 00000000..3bbbf675 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/CryptoUtils.java @@ -0,0 +1,504 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.crypto; + +import android.net.Uri; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.Base64; +import com.cisco.wx2.sdk.kms.*; +import com.ciscowebex.androidsdk.internal.Credentials; +import com.ciscowebex.androidsdk.internal.ErrorDetail; +import com.ciscowebex.androidsdk.internal.model.KmsMessageModel; +import com.ciscowebex.androidsdk.utils.UriUtils; +import com.github.benoitdion.ln.Ln; +import com.nimbusds.jose.*; +import com.nimbusds.jose.crypto.DirectDecrypter; +import com.nimbusds.jose.crypto.DirectEncrypter; +import com.nimbusds.jose.crypto.RSASSAVerifier; +import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.OctetSequenceKey; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.util.Base64URL; +import com.nimbusds.jose.util.JSONObjectUtils; +import me.helloworld.utils.Checker; +import org.spongycastle.crypto.digests.MD5Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.net.URI; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.Security; +import java.security.interfaces.ECPublicKey; +import java.text.ParseException; +import java.util.*; + +public class CryptoUtils { + + private static boolean isInit; + + public static void init() { + if (isInit) { + return; + } + Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1); + KmsApi.useGson(true); + KmsApi.useSpongyCastle(true); + KmsApi.setLogger(new KmsApiLn()); + isInit = true; + } + + public static JWK convertStringToJWK(String keyString) { + JWK jwk = null; + try { + jwk = JWK.parse(keyString); + } catch (ParseException e) { + Ln.e(false, "Parse Exception while extracting public key", e.getMessage()); + } + return jwk; + } + + public static KeyObject convertKmsKeytoKeyObject(KmsKey kmsKey) { + if (kmsKey == null || kmsKey.getJwk() == null) { + return null; + } + String[] resourceUri = null; + if (kmsKey.getResourceUri() != null) { + resourceUri = new String[]{UriUtils.toString(kmsKey.getResourceUri())}; + } + return new KeyObject(UriUtils.toString(kmsKey.getUri()), new SymmetricJWK(kmsKey.getJwk().getK(), UriUtils.parseIfNotNull(kmsKey.getJwk().getKid())), null, resourceUri, kmsKey.getExpirationDate()); + } + + public static KmsResponseBody decryptKmsMessage(String kmsMessage, JWK sharedKeyWithKms) { + init(); + if (TextUtils.isEmpty(kmsMessage) || sharedKeyWithKms == null) { + return null; + } + KmsResponse kmsResponse = null; + try { + kmsResponse = new KmsResponse(kmsMessage); + return (kmsResponse.getBody(sharedKeyWithKms)); + } catch (ParseException e) { + Ln.e(false, e, "Exception while trying to decrypt kmsMessages. Shared key kid is used to encrypt this kmsMessage " + kmsResponse.getKid().equals(sharedKeyWithKms.getKeyID())); + } catch (Exception e) { + Ln.e(false, e, "Exception while trying to decrypt kmsMessages"); + } + return null; + } + + public static List decryptKmsMessages(KmsMessageModel encryptionKmsMessage, JWK sharedKeyWithKms) { + init(); + ArrayList decryptedKmsMessageList = new ArrayList<>(); + KmsResponseBody decryptedKmsResponse; + for (String kmsMessage : encryptionKmsMessage.getKmsMessages()) { + decryptedKmsResponse = decryptKmsMessage(kmsMessage, sharedKeyWithKms); + if (decryptedKmsResponse != null) { + decryptedKmsMessageList.add(decryptedKmsResponse); + } + } + return decryptedKmsMessageList; + } + + public static KeyObject generateEphemeralKey(KmsMessageModel encryptionKmsMessage, String kmsStaticKeyString, KmsRequest kmsRequest) { + init(); + if (kmsRequest == null) { + return null; + } + if (encryptionKmsMessage.getKmsMessages() != null && !encryptionKmsMessage.getKmsMessages().isEmpty()) { + KmsResponse kmsResponse; + try { + kmsResponse = new KmsResponse(encryptionKmsMessage.getKmsMessages().get(0)); + KmsResponseBody kmsResponseBody = kmsResponse.getBody(convertStringToJWK(kmsStaticKeyString)); + KmsKey sharedKey = kmsResponseBody.getKey(); + OctetSequenceKey sharedKeyValue = kmsRequest.deriveEphemeralKey(kmsResponse); + if (sharedKeyValue != null && sharedKeyValue.getKeyValue() != null && sharedKeyValue.getKeyID() != null) { + Uri keyUrl = UriUtils.parseIfNotNull(sharedKeyValue.getKeyID()); + if (keyUrl != null) { + return new KeyObject(keyUrl.toString(), new SymmetricJWK(sharedKeyValue.getKeyValue().toString(), + UriUtils.parseIfNotNull(sharedKeyValue.getKeyID())), null, null, sharedKey.getExpirationDate()); + } + } + } catch (ParseException e) { + Ln.e(false, e, "Unable to derive Ephemeral Key from KmsResponse"); + } + } + return null; + } + + public static KmsRequest generateEphemeralKeyRequest(String deviceId, Credentials credentials, Uri kmsCluster, String requestId) { + init(); + KmsRequestBody.Client client = getKmsRequestBodyClient(deviceId, credentials); + return KmsRequestFactory.getInstance().newCreateEphemeralKeyRequest(client, requestId, kmsCluster.toString()); + } + + public static KmsRequest generateBoundKeyRequest(String deviceId, Credentials credentials, String requestId, String keyUri) { + init(); + KmsRequestBody.Client client = getKmsRequestBodyClient(deviceId, credentials); + URI requestUri = UriUtils.toURI(keyUri); + if (requestUri != null) { + Ln.v("Request ID" + requestId + " Building bound key request for " + keyUri + " requestUri" + requestUri); + return KmsRequestFactory.getInstance().newRetrieveKeyRequest(client, requestId, requestUri); + } + return null; + } + + public static KmsRequest generateUnboundKeyRequest(String deviceId, Credentials credentials, String requestId, int count) { + init(); + KmsRequestBody.Client client = getKmsRequestBodyClient(deviceId, credentials); + return KmsRequestFactory.getInstance().newCreateKeysRequest(client, requestId, count); + } + + public static KmsRequest getBoundKeyAuthorizationRequest(String deviceId, Credentials credentials, String requestId, KmsResourceObject kro) { + init(); + KmsRequestBody.Client client = getKmsRequestBodyClient(deviceId, credentials); + Uri requestUri = UriUtils.parseIfNotNull(kro.getUri()).buildUpon().appendPath("authorizations").build(); + if (requestUri != null) { + Ln.v("Request ID" + requestId + " Building bound key request for requestUri" + requestUri); + return KmsRequestFactory.getInstance().newRetrieveAuthorizationsRequest(client, requestId, URI.create(requestUri.toString())); + } + return null; + } + + public static KmsRequest authorizeNewParticipantsRequest(String deviceId, Credentials credentials, String requestId, KmsResourceObject kro, Collection uuIDs) { + init(); + KmsRequestBody.Client client = getKmsRequestBodyClient(deviceId, credentials); + if (kro == null) { + return null; + } + return KmsRequestFactory.getInstance().newCreateAuthorizationsRequest(client, requestId, kro.getURI(), new ArrayList<>(uuIDs)); + } + + public static KmsRequest updateEncryptionKeyRequest(String deviceId, Credentials credentials, String requestId, KmsResourceObject kro, KeyObject newKey) { + init(); + KmsRequestBody.Client client = getKmsRequestBodyClient(deviceId, credentials); + return KmsRequestFactory.getInstance().newUpdateKeyRequest(client, requestId, UriUtils.toURI(newKey.getKeyUrl()), kro.getURI()); + } + + public static KmsRequest createResourceRequest(String deviceId, Credentials self, String requestId, List userIds, Uri oneKeyUri) { + List uriList = Collections.singletonList(UriUtils.toURI(oneKeyUri)); + return createResourceRequest(deviceId, self, requestId, userIds, uriList); + } + + public static KmsRequest createResourceRequest(String deviceId, Credentials self, String requestId, List userIds, List keyUris) { + init(); + String userId = self.getUserId(); + KmsRequestBody.Client client = getKmsRequestBodyClient(deviceId, self); + return KmsRequestFactory.getInstance().newCreateResourceRequest(client, requestId, userIds, keyUris); + } + + public static boolean verify(String rsaPublicKeyString, String jwsObjectString) { + JWSObject jwsObject; + RSAKey rsaPublicKey; + try { + rsaPublicKey = (RSAKey) JWK.parse(rsaPublicKeyString); + JWSVerifier verifier = new RSASSAVerifier(rsaPublicKey.toRSAPublicKey()); + jwsObject = JWSObject.parse(jwsObjectString); + return jwsObject.verify(verifier); + } catch (Exception e) { + Ln.e(e.getMessage(), "Exception while verifying public key"); + } + return false; + } + + public static String encryptToJwe(KeyObject key, String message) { + if (Checker.isEmpty(message) || key == null) { + return message; + } + try { + JWEObject jwe = new JWEObject(new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A256GCM), new Payload(message)); + jwe.encrypt(new DirectEncrypter(new SecretKeySpec(key.getKeyBytes(), "AES"))); + return jwe.serialize(); + } catch (JOSEException e) { + Ln.d(e); + } + return message; + } + + public static String decryptFromJwe(KeyObject key, String message) { + if (Checker.isEmpty(message) || key == null) { + return message; + } + try { + JWEObject jwe = JWEObject.parse(message); + jwe.decrypt(new DirectDecrypter(new SecretKeySpec(key.getKeyBytes(), "AES"))); + return jwe.getPayload().toString(); + } catch (JOSEException e) { + String exceptionMessage = "Unable to decrypt "; + if (key.getKeyValue() != null && !UriUtils.equals(key.getKeyUrl(), key.getKeyId())) { + exceptionMessage += "Mismatched keys"; + } + Ln.d(exceptionMessage + ", " + message, e); + } catch (ParseException | NullPointerException e) { + Ln.d("Failed to decrypt message: " + message, e); + } + return message; + } + + public static String encryptAES(String message, String key) { + if (message == null) { + return null; + } + String jweString = null; + + try { + Base64URL base64Key = new Base64URL(key); + byte[] byteKey = base64Key.decode(); + SecretKeySpec secretKeySpec = new SecretKeySpec(byteKey, "AES"); + JWEEncrypter encrypter = new DirectEncrypter(secretKeySpec); + JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A256GCM); + Payload payload = new Payload(message); + JWEObject jweObj = new JWEObject(header, payload); + jweObj.encrypt(encrypter); + jweString = jweObj.serialize(); + + } catch (JOSEException ex) { + Ln.e(ex.getMessage(), "encryption JOSE exception"); + } + return jweString; + } + + public static String decryptAES(String encryptedText, String key) { + if (encryptedText == null || key == null) { + return null; + } + + String msgOut = null; + try { + + Base64URL base64Key = new Base64URL(key); + byte[] byteKey = base64Key.decode(); + SecretKeySpec secretKeySpec = new SecretKeySpec(byteKey, "AES"); + JWEObject jweObjOut = JWEObject.parse(encryptedText); + JWEDecrypter decrypter = new DirectDecrypter(secretKeySpec); + jweObjOut.decrypt(decrypter); + msgOut = jweObjOut.getPayload().toString(); + } catch (JOSEException ex) { + Ln.e(ex.getMessage(), "Decryption Exception"); + } catch (ParseException ex) { + Ln.e(ex.getMessage(), "Decryption parse Exception"); + } + return msgOut; + } + + public static ECPublicKey extractPublicKey(String jwkPublicString) { + try { + JWSObject jwsObject = JWSObject.parse(jwkPublicString); + Payload payload = jwsObject.getPayload(); + ECKey serverPublicKey = ECKey.parse(payload.toJSONObject()); + return serverPublicKey.toECPublicKey(); + } catch (Exception e) { + Ln.e(e.getMessage(), "Exception while extracting public key"); + } + return null; + } + + public static String base64EncodedString(Uri value) { + if (value == null) { + return null; + } + return Base64.encodeToString(value.toString().getBytes(), Base64.URL_SAFE | Base64.NO_WRAP); + } + + public static boolean isPlainTextMessage(String message) { + if (message == null) { + return false; + } + return !looksLikeCipherText(message); + } + + public static boolean looksLikeCipherText(String str) { + if (TextUtils.isEmpty(str)) { + return false; + } + String[] parts = TextUtils.split(str, "\\."); + if (parts.length != 5) { + return false; + } + try { + JSONObjectUtils.parseJSONObject(new String(Base64.decode(parts[0], Base64.URL_SAFE))); + return true; + } catch (Exception ignored) { + } + return false; + } + + public static KmsResponseBody extractKmsResponseBody(@Nullable ErrorDetail errorDetail, OctetSequenceKey sharedKeyWithKMSAsJWK) { + try { + if (errorDetail == null) + return null; + + ErrorDetail.CustomErrorCode errorCode = errorDetail.extractCustomErrorCode(); + if (errorCode == ErrorDetail.CustomErrorCode.KmsMessageOperationFailed) { + if (errorDetail.getMessage() != null) { + return CryptoUtils.decryptKmsMessage(errorDetail.getMessage(), sharedKeyWithKMSAsJWK); + } + } + } catch (Exception e) { + Ln.w(e, "Failure while decrypting Kms Error Message"); + } + return null; + } + + public static OctetSequenceKey parseOctetSequenceKey(KeyObject key) { + if (key == null || TextUtils.isEmpty(key.getKey())) { + return null; + } + OctetSequenceKey.Builder keyBuilder = new OctetSequenceKey.Builder(new Base64URL(key.getKey())); + keyBuilder.keyID(UriUtils.toString(key.getKeyId())); + return keyBuilder.build(); + } + + public static KmsRequest leaveKmsMessagingApiRequest(String deviceId, KmsResourceObject kro, Credentials credentials, String requestId, String userId) { + init(); + KmsRequestBody.Client client = getKmsRequestBodyClient(deviceId, credentials); + if (kro == null || TextUtils.isEmpty(userId)) { + return null; + } + Uri requestUri = UriUtils.parseIfNotNull(kro.getUri()).buildUpon().appendPath("authorizations").appendQueryParameter("authId", userId).build(); + URI requestURI = URI.create(UriUtils.toString(requestUri)); + return KmsRequestFactory.getInstance().newDeleteAuthorizationByResourceRequest(client, requestId, requestURI); + } + + public static String getKmsErrorMessage(ErrorDetail errorDetail, OctetSequenceKey sharedKeyWithKMSAsJWK) { + + KmsResponseBody errorMessage = CryptoUtils.extractKmsResponseBody(errorDetail, sharedKeyWithKMSAsJWK); + String message = "Encryption service error: "; + if (errorMessage != null) { + message += errorMessage.getReason(); + } + return message; + } + + private static KmsRequestBody.Client getKmsRequestBodyClient(String deviceId, Credentials user) { + KmsRequestBody.Client client = new KmsRequestBody.Client(); + client.setClientId(deviceId); + client.getCredential().setUserId(user.getUserId()); + client.getCredential().setBearer(user.getToken()); + return client; + } + + private static class KmsApiLn implements KmsApiLogger { + + @Override + public void log(Level level, String s, Exception e) { + switch (level) { + + case DEBUG: + Ln.d(e, s); + break; + case VERBOSE: + Ln.v(e, s); + break; + case INFO: + Ln.i(e, s); + break; + case WARN: + Ln.w(false, e, s); + break; + case ERROR: + Ln.e(false, e, s); + break; + } + } + + @Override + public void log(Level level, String s) { + switch (level) { + case DEBUG: + Ln.d(s); + break; + case VERBOSE: + Ln.v(s); + break; + case INFO: + Ln.i(s); + break; + case WARN: + Ln.w(s); + break; + case ERROR: + Ln.e(s); + break; + } + } + } + + public static Key createDESKey(final byte[] bytes, final int offset) { + final byte[] keyBytes = new byte[7]; + System.arraycopy(bytes, offset, keyBytes, 0, 7); + final byte[] material = new byte[8]; + material[0] = keyBytes[0]; + material[1] = (byte) (keyBytes[0] << 7 | (keyBytes[1] & 0xff) >>> 1); + material[2] = (byte) (keyBytes[1] << 6 | (keyBytes[2] & 0xff) >>> 2); + material[3] = (byte) (keyBytes[2] << 5 | (keyBytes[3] & 0xff) >>> 3); + material[4] = (byte) (keyBytes[3] << 4 | (keyBytes[4] & 0xff) >>> 4); + material[5] = (byte) (keyBytes[4] << 3 | (keyBytes[5] & 0xff) >>> 5); + material[6] = (byte) (keyBytes[5] << 2 | (keyBytes[6] & 0xff) >>> 6); + material[7] = (byte) (keyBytes[6] << 1); + oddParity(material); + return new SecretKeySpec(material, "DES"); + } + + public static byte[] hmacMD5(byte[] key, byte[] data) { + KeyParameter param = new KeyParameter(key); + HMac hmac = new HMac(new MD5Digest()); + byte[] result; + hmac.init(param); + hmac.update(data, 0, data.length); + result = new byte[hmac.getMacSize()]; + hmac.doFinal(result, 0); + return result; + } + + public static byte[] hmacMd5(Key key, byte[] data) { + byte[] hashedData; + try { + Mac mac = Mac.getInstance("HmacMd5"); + mac.init(key); + hashedData = mac.doFinal(data); + return hashedData; + } catch (NoSuchAlgorithmException | InvalidKeyException ex) { + // TODO: Handle.... + return null; + } + } + + private static void oddParity(final byte[] bytes) { + for (int i = 0; i < bytes.length; i++) { + final byte b = bytes[i]; + final boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) + ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0; + if (needsParity) { + bytes[i] |= (byte) 0x01; + } else { + bytes[i] &= (byte) 0xfe; + } + } + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KeyManager.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KeyManager.java new file mode 100644 index 00000000..e00a056e --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KeyManager.java @@ -0,0 +1,301 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.crypto; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.cisco.wx2.sdk.kms.KmsRequest; +import com.cisco.wx2.sdk.kms.KmsResponseBody; +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.*; +import com.ciscowebex.androidsdk.internal.model.*; +import com.ciscowebex.androidsdk.internal.queue.BackgroundQueue; +import com.ciscowebex.androidsdk.utils.Lists; +import com.ciscowebex.androidsdk.utils.UriUtils; +import com.github.benoitdion.ln.Ln; +import com.nimbusds.jose.jwk.JWK; +import me.helloworld.utils.Checker; +import me.helloworld.utils.collection.Maps; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class KeyManager { + + public static KeyManager shared = new KeyManager(); + + private BackgroundQueue queue = new BackgroundQueue(); + private KmsInfoModel kmsInfo; + private Map> requests = new ConcurrentHashMap<>(); + + private KeyObject ephemeralKey; + private final Map keys = new ConcurrentHashMap<>(); + private final Map encryptionUrls = new ConcurrentHashMap<>(); + private final Map> userIds = new ConcurrentHashMap<>(); + + public void processKmsMessage(@NonNull KmsMessageModel model) { + queue.run(() -> { + JWK decryptKmsMessageKey = (ephemeralKey == null ? CryptoUtils.convertStringToJWK(kmsInfo.getRsaPublicKey()) : ephemeralKey.getKeyValueAsJWK()); + List decryptedKmsMessages = CryptoUtils.decryptKmsMessages(model, decryptKmsMessageKey); + for (KmsResponseBody decryptedKmsMessage : decryptedKmsMessages) { + KmsRequestWrapper kmsRequest = requests.remove(decryptedKmsMessage.getRequestId()); + if (kmsRequest == null) { + Ln.d("ERROR unexpected KMS message: " + decryptedKmsMessage); + continue; + } + Ln.d("Response for Request ID " + decryptedKmsMessage.getRequestId() + " type:" + kmsRequest.getType() + " response " + decryptedKmsMessage.toString()); + if (kmsRequest.getType() == KmsRequestWrapper.RequestType.CREATE_EPHEMERAL_KEY) { + ephemeralKey = CryptoUtils.generateEphemeralKey(model, kmsInfo.getRsaPublicKey(), kmsRequest.getKmsRequest()); + kmsRequest.getCallback().onComplete(ephemeralKey == null ? ResultImpl.error("Get the illegal ephemeral key") : ResultImpl.success(ephemeralKey)); + return; + } else if (kmsRequest.getType() == KmsRequestWrapper.RequestType.GET_KEYS) { + if (decryptedKmsMessage.getKey() != null) { + KeyObject key = CryptoUtils.convertKmsKeytoKeyObject(decryptedKmsMessage.getKey()); + if (key != null) { + this.keys.put(key.getKeyUrl(), key); + } + kmsRequest.getCallback().onComplete(key == null ? ResultImpl.error("Get the illegal key") : ResultImpl.success(key)); + return; + } else if (!Checker.isEmpty(decryptedKmsMessage.getKeys()) && kmsRequest.getConversationId() != null) { + KeyObject key = CryptoUtils.convertKmsKeytoKeyObject(decryptedKmsMessage.getKeys().get(0)); + if (key == null) { + kmsRequest.getCallback().onComplete(ResultImpl.error("Get the illegal key")); + return; + } + this.keys.put(key.getKeyUrl(), key); + Set userIds = this.userIds.remove(kmsRequest.getConversationId()); + Device device = kmsRequest.getDevice(); + Credentials credentials = kmsRequest.getCredentials(); + getEphemeralKey(credentials, device, ephemeral -> { + if (ephemeral.getError() != null) { + kmsRequest.getCallback().onComplete(ResultImpl.error(ephemeral)); + return; + } + String requestId = UUID.randomUUID().toString(); + KmsRequest kr = CryptoUtils.createResourceRequest(device.getDeviceUrl(), credentials, requestId, new ArrayList<>(userIds), Lists.asList(UriUtils.toURI(key.getKeyUrl()))); + if (kr == null) { + kmsRequest.getCallback().onComplete(ResultImpl.error("Failed generating key request message")); + return; + } + String encryptedBlob = kr.asEncryptedBlob(this.ephemeralKey.getKeyValueAsJWK()); + if (Checker.isEmpty(encryptedBlob)) { + kmsRequest.getCallback().onComplete(ResultImpl.error("Generate Key Request is empty")); + return; + } + Map params = new HashMap<>(); + params.put("objectType", ObjectModel.Type.activity); + params.put("verb", ActivityModel.Verb.updateKey.name()); + params.put("object", Maps.makeMap("objectType", ObjectModel.Type.conversation, "defaultActivityEncryptionKeyUrl", key.getKeyUrl())); + params.put("target", Maps.makeMap("objectType", ObjectModel.Type.conversation, "id", kmsRequest.getConversationId())); + params.put("kmsMessage", encryptedBlob); + Service.Conv.post(params).to("activities").auth(credentials.getAuthenticator()).device(device).queue(queue).model(ActivityModel.class).error(kmsRequest.getCallback()) + .async((Closure) result -> { + if (kmsRequest.getConversationId() != null) { + encryptionUrls.put(kmsRequest.getConversationId(), key.getKeyUrl()); + } + kmsRequest.getCallback().onComplete(ResultImpl.success(key)); + }); + }); + } + } + } + }); + } + + public void tryRefresh(String conversationId, String encryptionUrl) { + if (encryptionUrl != null && !Checker.isEqual(this.encryptionUrls.get(conversationId), encryptionUrl)) { + encryptionUrls.put(conversationId, encryptionUrl); + } + } + + public void getKey(String conversationId, Credentials credentials, Device device, CompletionHandler callback) { + queue.run(() -> getEncryptionUrl(conversationId, credentials.getAuthenticator(), device, result -> { + if (result.getError() != null) { + callback.onComplete(ResultImpl.error(result.getError())); + return; + } + getKey(conversationId, result.getData(), credentials, device, callback); + })); + + } + + private void getEncryptionUrl(String conversationId, Authenticator authenticator, Device device, CompletionHandler callback) { + queue.run(() -> { + String url = encryptionUrls.get(conversationId); + if (url != null) { + callback.onComplete(ResultImpl.success(url)); + return; + } + + Service.Conv.get("conversations", conversationId) + .with("includeActivities", String.valueOf(false)) + .with("includeParticipants", String.valueOf(false)) + .auth(authenticator) + .device(device) + .queue(queue) + .model(ConversationModel.class) + .error(callback) + .async((Closure) model -> { + if (model == null) { + callback.onComplete(ResultImpl.error("No result")); + return; + } + String encryptionUrl = model.getTitleEncryptionKeyUrl(); + if (encryptionUrl == null) { + encryptionUrl = model.getDefaultActivityEncryptionKeyUrl(); + } + if (encryptionUrl == null) { + if (model.getKmsResourceObject() == null) { + callback.onComplete(ResultImpl.error("No result")); + return; + } + ItemsModel items = model.getParticipants(); + List participants = items == null ? null : items.getItems(); + Set participantUuids = participants == null ? null : new HashSet<>(participants.size()); + if (participantUuids != null) { + for (PersonModel person : participants) { + participantUuids.add(person.getUuid()); + } + } + userIds.put(conversationId, participantUuids); + } + if (encryptionUrl != null) { + encryptionUrls.put(conversationId, encryptionUrl); + } + callback.onComplete(ResultImpl.success(encryptionUrl)); + }); + }); + } + + private void getKey(@NonNull String spaceId, @Nullable String encryptionUrl, @NonNull Credentials credentials, @NonNull Device device, @NonNull CompletionHandler callback) { + queue.run(() -> { + KeyObject key = encryptionUrl == null ? null : keys.get(encryptionUrl); + if (key != null) { + callback.onComplete(ResultImpl.success(key)); + return; + } + getEphemeralKey(credentials, device, ephemeral -> { + if (ephemeral.getError() != null) { + callback.onComplete(ephemeral); + return; + } + String requestId = UUID.randomUUID().toString(); + KmsRequest kmsRequest; + if (encryptionUrl == null) { + kmsRequest = CryptoUtils.generateUnboundKeyRequest(device.getDeviceUrl(), credentials, requestId, 1); + } else { + kmsRequest = CryptoUtils.generateBoundKeyRequest(device.getDeviceUrl(), credentials, requestId, encryptionUrl); + } + if (kmsRequest == null) { + Ln.d("Failed generating key request message"); + callback.onComplete(ResultImpl.error("Failed generating key request message")); + return; + } + String encryptedBlob = kmsRequest.asEncryptedBlob(ephemeral.getData().getKeyValueAsJWK()); + if (Checker.isEmpty(encryptedBlob)) { + Ln.d("Generate Key Request is empty"); + callback.onComplete(ResultImpl.error("Generate Key Request is null")); + return; + } + KmsRequestWrapper wrapper = new KmsRequestWrapper<>(KmsRequestWrapper.RequestType.GET_KEYS, kmsRequest, callback); + if (encryptionUrl == null) { + wrapper.setDevice(device); + wrapper.setCredentials(credentials); + wrapper.setConversationId(spaceId); + } + requests.put(requestId, wrapper); + Service.Kms.post(Maps.makeMap("kmsMessages", Lists.asList(encryptedBlob), "destination", kmsInfo.getKmsCluster().toString())).to("kms", "messages") + .header("Cisco-Request-ID", requestId) + .auth(credentials.getAuthenticator()).device(device).queue(queue) + .error((CompletionHandler) result -> { + requests.remove(requestId); + callback.onComplete(result); + }) + .async(null); + }); + }); + } + + private void getEphemeralKey(Credentials credentials, Device device, CompletionHandler callback) { + queue.run(() -> { + if (ephemeralKey != null) { + callback.onComplete(ResultImpl.success(ephemeralKey)); + return; + } + getClusterAndRSAPubKey(credentials.getAuthenticator(), device, info -> { + if (info.getError() != null) { + callback.onComplete(ResultImpl.error(info.getError())); + return; + } + if (device == null || device.getDeviceUrl() == null) { + Ln.d("No Device Info"); + callback.onComplete(ResultImpl.error("No Device Info")); + return; + } + if (kmsInfo == null) { + Ln.d("Failed getting KMS Info"); + callback.onComplete(ResultImpl.error("Failed getting KMS Info")); + return; + } + String requestId = UUID.randomUUID().toString(); + KmsRequest kmsRequest = CryptoUtils.generateEphemeralKeyRequest(device.getDeviceUrl(), credentials, kmsInfo.getKmsCluster(), requestId); + if (kmsRequest == null) { + Ln.d("Generate Ephemeral Key Request is null"); + callback.onComplete(ResultImpl.error("Generate Ephemeral Key Request is null")); + return; + } + String encryptedRequest = kmsRequest.asEncryptedBlob(CryptoUtils.convertStringToJWK(kmsInfo.getRsaPublicKey())); + if (Checker.isEmpty(encryptedRequest)) { + Ln.d("Generate Ephemeral Key Request is empty"); + callback.onComplete(ResultImpl.error("Generate Ephemeral Key Request is null")); + return; + } + requests.put(requestId, new KmsRequestWrapper<>(KmsRequestWrapper.RequestType.CREATE_EPHEMERAL_KEY, kmsRequest, callback)); + + Service.Kms.post(Maps.makeMap("kmsMessages", encryptedRequest, "destination", kmsInfo.getKmsCluster().toString())).to("kms", "messages") + .header("Cisco-Request-ID", requestId) + .auth(credentials.getAuthenticator()).device(device).queue(queue) + .error((CompletionHandler) result -> { + requests.remove(requestId); + callback.onComplete(result); + }) + .async(null); + }); + }); + } + + private void getClusterAndRSAPubKey(Authenticator authenticator, Device device, CompletionHandler callback) { + if (kmsInfo != null) { + callback.onComplete(ResultImpl.success(kmsInfo)); + return; + } + Service.Kms.get("kms").auth(authenticator).device(device).queue(queue).model(KmsInfoModel.class).error(callback) + .async((Closure) model -> { + kmsInfo = model; + callback.onComplete(ResultImpl.success(kmsInfo)); + }); + } + + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KeyObject.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KeyObject.java new file mode 100644 index 00000000..ba951d88 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KeyObject.java @@ -0,0 +1,121 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.crypto; + +import android.net.Uri; +import android.support.annotation.NonNull; +import com.ciscowebex.androidsdk.utils.UriUtils; +import com.nimbusds.jose.jwk.OctetSequenceKey; +import com.nimbusds.jose.util.Base64URL; + +import java.util.Date; + +public class KeyObject { + private String keyUrl; + private SymmetricJWK keyValue; + private String[] authorizations; + private String[] resources; + private Date expirationDate; + + public KeyObject(@NonNull String keyUrl, @NonNull SymmetricJWK keyString, String[] authorizations, String[] resources, Date expirationDate) { + this(keyUrl, keyString, authorizations, resources); + this.expirationDate = expirationDate; + } + + public KeyObject(@NonNull String keyUrl, @NonNull SymmetricJWK keyString, String[] authorizations, String[] resources) { + this.keyUrl = keyUrl; + this.keyValue = keyString; + this.authorizations = authorizations; + this.resources = resources; + } + + public SymmetricJWK getKeyValue() { + return this.keyValue; + } + + public OctetSequenceKey getKeyValueAsJWK() { + if (this.keyValue != null) { + return CryptoUtils.parseOctetSequenceKey(this); + } + return null; + } + + public String getKey() { + if (keyValue == null) { + return null; + } + return this.keyValue.getOctetSequenceKey(); + } + + public byte[] getKeyBytes() { + Base64URL base64Key = new Base64URL(getKey()); + return base64Key.decode(); + } + + public String getKeyUrl() { + return keyUrl; + } + + public String[] getAuthorizations() { + return this.authorizations; + } + + public String[] getResources() { + return this.resources; + } + + public KmsResourceObject getKmsResourceObject() { + if (resources == null || resources.length == 0) { + return null; + } + String uri = resources[0]; + if (uri == null) { + return null; + } + return new KmsResourceObject(uri); + } + + public Uri getKeyId() { + return this.keyValue.getKId(); + } + + public Date getExpirationDate() { + return expirationDate; + } + + public long getExpirationTime() { + if (this.expirationDate != null) { + return this.expirationDate.getTime(); + } + return 0; + } + + public boolean isKeyExpired() { + return ((System.currentTimeMillis() - getExpirationTime()) >= 0); + } + + public boolean isValid() { + return getKeyId() != null && getKeyValue() != null && !isKeyExpired(); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KmsRequestWrapper.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KmsRequestWrapper.java new file mode 100644 index 00000000..776eb039 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KmsRequestWrapper.java @@ -0,0 +1,88 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.crypto; + +import com.cisco.wx2.sdk.kms.KmsRequest; +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.internal.Credentials; +import com.ciscowebex.androidsdk.internal.Device; + +public class KmsRequestWrapper { + + public enum RequestType { + AUTHORIZATIONS, + CREATE_EPHEMERAL_KEY, + GET_KEYS, + PING, + CREATE_RESOURCE; + } + + private RequestType type; + private KmsRequest kmsRequest; + private CompletionHandler callback; + private String conversationId; + private Device device; + private Credentials credentials; + + public KmsRequestWrapper(RequestType type, KmsRequest kmsRequest, CompletionHandler callback) { + this.type = type; + this.kmsRequest = kmsRequest; + this.callback = callback; + } + + public void setConversationId(String conversationId) { + this.conversationId = conversationId; + } + + public void setDevice(Device device) { + this.device = device; + } + + public Device getDevice() { + return device; + } + + public Credentials getCredentials() { + return credentials; + } + + public void setCredentials(Credentials credentials) { + this.credentials = credentials; + } + + public RequestType getType() { + return type; + } + + public KmsRequest getKmsRequest() { + return kmsRequest; + } + + public String getConversationId() { + return conversationId; + } + + public CompletionHandler getCallback() { + return callback; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ListCallback.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KmsResourceObject.java similarity index 56% rename from sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ListCallback.java rename to sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KmsResourceObject.java index 51acff5b..8a3e2e82 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ListCallback.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/KmsResourceObject.java @@ -20,40 +20,51 @@ * THE SOFTWARE. */ -package com.ciscowebex.androidsdk.utils.http; +package com.ciscowebex.androidsdk.internal.crypto; -import java.util.List; +import android.net.Uri; +import android.support.annotation.NonNull; +import com.github.benoitdion.ln.Ln; -import com.ciscowebex.androidsdk.CompletionHandler; -import com.ciscowebex.androidsdk.internal.ResultImpl; +import java.net.URI; +import java.net.URISyntaxException; -import retrofit2.Call; -import retrofit2.Response; +public class KmsResourceObject { -/** - * Created by zhiyuliu on 02/09/2017. - */ + String uri; + + public KmsResourceObject(@NonNull String uri) { + this.uri = uri; + } -public class ListCallback extends ListenerCallback> { + public URI getURI() { + try { + return new URI(uri); + } catch (URISyntaxException e) { + Ln.e(e); + } + return null; + } - private CompletionHandler> _handler; + public String getUri() { + return uri; + } - public ListCallback(CompletionHandler> handler) { - _handler = handler; + @Override + public String toString() { + return uri.toString(); } @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful()) { - _handler.onComplete(ResultImpl.success(response.body().getItems())); - } else if (!checkUnauthError(response)) { - _handler.onComplete(ResultImpl.error(response)); + public boolean equals(Object o) { + if (o instanceof KmsResourceObject && uri != null) { + return uri.equals(((KmsResourceObject) o).uri); } + return false; } @Override - public void onFailure(Call> call, Throwable t) { - _handler.onComplete(ResultImpl.error(t)); + public int hashCode() { + return uri.hashCode(); } - } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/SecureContentReference.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/SecureContentReference.java new file mode 100644 index 00000000..21c441ec --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/SecureContentReference.java @@ -0,0 +1,425 @@ +package com.ciscowebex.androidsdk.internal.crypto; + +import com.nimbusds.jose.*; +import com.nimbusds.jose.crypto.DirectDecrypter; +import com.nimbusds.jose.crypto.DirectEncrypter; +import com.nimbusds.jose.util.Base64URL; +import net.minidev.json.JSONObject; +import org.jetbrains.annotations.NotNull; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.io.InvalidCipherTextIOException; +import org.spongycastle.crypto.modes.AEADBlockCipher; +import org.spongycastle.crypto.modes.GCMBlockCipher; +import org.spongycastle.crypto.params.AEADParameters; +import org.spongycastle.crypto.params.KeyParameter; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +public class SecureContentReference { + private String enc; + private byte[] key; + + private byte[] iv; + private String aad; + private byte[] tag; + private String loc; + + private boolean isGiphy; + + private SecureContentReference() { + } + + public static SecureContentReference createInstance() { + SecureContentReference scr = new SecureContentReference(); + SecureRandom rng = new SecureRandom(); + scr.setEnc("A256GCM"); + byte[] data; + data = new byte[32]; + rng.nextBytes(data); + scr.setKey(data); + data = new byte[12]; + rng.nextBytes(data); + scr.setIV(data); + Date ts = new Date(); + DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US); + fmt.setTimeZone(TimeZone.getTimeZone("GMT")); + String aad = fmt.format(ts); + scr.setAAD(aad); + scr.isGiphy = false; + return scr; + } + + public static SecureContentReference fromJWEForGiphy(byte[] key, String str) throws ParseException, JOSEException { + JWEObject jwe = JWEObject.parse(str); + jwe.decrypt(new DirectDecrypter(key)); + SecureContentReference scr = new SecureContentReference(); + JSONObject json = jwe.getPayload().toJSONObject(); + Object value; + value = json.get("loc"); + scr.setLoc(value.toString()); + return scr; + } + + public static SecureContentReference fromJWE(byte[] key, String str) throws ParseException, JOSEException { + JWEObject jwe = JWEObject.parse(str); + jwe.decrypt(new DirectDecrypter(key)); + SecureContentReference scr = new SecureContentReference(); + JSONObject json = jwe.getPayload().toJSONObject(); + Object value; + byte[] data; + value = json.get("enc"); + scr.setEnc(value.toString()); + value = json.get("aad"); + scr.setAAD(value.toString()); + value = json.get("loc"); + scr.setLoc(value.toString()); + value = json.get("key"); + data = new Base64URL(value.toString()).decode(); + scr.setKey(data); + value = json.get("iv"); + data = new Base64URL(value.toString()).decode(); + scr.setIV(data); + value = json.get("tag"); + data = new Base64URL(value.toString()).decode(); + scr.setTag(data); + return scr; + } + + public final String getEnc() { + return enc; + } + + private void setEnc(String enc) { + this.enc = enc; + } + + public final byte[] getKey() { + return key; + } + + private void setKey(byte[] key) { + this.key = key; + } + + public final byte[] getIV() { + return iv; + } + + public final void setIsGiphy(boolean value) { + this.isGiphy = value; + } + + private void setIV(byte[] iv) { + this.iv = iv; + } + + public final String getAAD() { + return aad; + } + + private void setAAD(String aad) { + this.aad = aad; + } + + public final String getLoc() { + return loc; + } + + public final void setLoc(String loc) { + this.loc = loc; + } + + public final byte[] getTag() { + return tag; + } + + private void setTag(byte[] tag) { + this.tag = tag; + } + + public String toJWE(byte[] key) throws JOSEException { + JSONObject json = new JSONObject(); + String value; + if (!isGiphy) { + value = getEnc(); + json.put("enc", value); + + value = Base64URL.encode(getKey()).toString(); + json.put("key", value); + + value = Base64URL.encode(getIV()).toString(); + json.put("iv", value); + + value = getAAD(); + json.put("aad", value); + + value = Base64URL.encode(getTag()).toString(); + json.put("tag", value); + } + + value = getLoc(); + json.put("loc", value); + + JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A256GCM); + Payload payload = new Payload(json); + JWEObject jwe = new JWEObject(header, payload); + jwe.encrypt(new DirectEncrypter(key)); + return jwe.serialize(); + } + + public OutputStream encrypt(OutputStream os) { + AEADBlockCipher c = createCipher(true); + return new SecureContentReference.CipherOutputStream(os, c); + } + + public InputStream decrypt(InputStream is) { + AEADBlockCipher c = createCipher(false); + return new CipherInputStream(is, c); + } + + private AEADBlockCipher createCipher(boolean encrypting) { + KeyParameter k = new KeyParameter(getKey()); + byte[] aad = getAAD().getBytes(StandardCharsets.UTF_8); + AEADParameters params = new AEADParameters(k, 128, getIV(), aad); + GCMBlockCipher c = new GCMBlockCipher(new AESFastEngine()); + c.init(encrypting, params); + return c; + } + + private class CipherOutputStream extends FilterOutputStream { + private final byte[] oneByte = new byte[1]; + AEADBlockCipher cipher; + private byte[] buf; + + public CipherOutputStream(OutputStream out, AEADBlockCipher c) { + super(out); + cipher = c; + } + + @Override + public void write(int b) throws IOException { + oneByte[0] = (byte) b; + write(oneByte, 0, 1); + } + + @Override + public void write(@NotNull byte[] b) throws IOException { + write(b, 0, b.length); + } + + @Override + public void write(@NotNull byte[] b, int off, int len) throws IOException { + ensureCapacity(len, false); + int outLen = cipher.processBytes(b, off, len, buf, 0); + if (outLen != 0) { + out.write(buf, 0, outLen); + } + } + + private void ensureCapacity(int updateSize, boolean finalOutput) { + int bufLen; + if (finalOutput) { + bufLen = cipher.getOutputSize(updateSize); + } else { + bufLen = cipher.getUpdateOutputSize(updateSize); + } + if ((buf == null) || (buf.length < bufLen)) { + buf = new byte[bufLen]; + } + } + + @Override + public void close() throws IOException { + ensureCapacity(0, true); + IOException error = null; + try { + int outLen = cipher.doFinal(buf, 0); + if (outLen > 16) { + out.write(buf, 0, outLen - 16); + } + setTag(Arrays.copyOfRange(buf, outLen - 16, outLen)); + } catch (final InvalidCipherTextException e) { + error = new InvalidCipherTextIOException("Error finalising cipher data", e); + } catch (Exception e) { + error = new IOException("Error closing stream: ", e); + } + try { + flush(); + } catch (IOException e) { + if (error == null) { + error = e; + } + } + if (error != null) { + throw error; + } + } + } + + public class CipherInputStream extends FilterInputStream { + private static final int INPUT_BUF_SIZE = 2048; + + private byte[] inBuf; + + private AEADBlockCipher cipher; + + private byte[] buf; + private byte[] markBuf; + + private int bufOff; + private int maxBuf; + private boolean finalized; + private int markBufOff; + + public CipherInputStream(InputStream is, AEADBlockCipher cipher) { + this(is, cipher, INPUT_BUF_SIZE); + } + + public CipherInputStream(InputStream is, AEADBlockCipher cipher, int bufSize) { + super(is); + this.cipher = cipher; + this.inBuf = new byte[bufSize]; + } + + private int nextChunk() throws IOException { + if (finalized) { + return -1; + } + bufOff = 0; + maxBuf = 0; + + while (maxBuf == 0) { + try { + int read = in.read(inBuf); + if (read == -1) { + finaliseCipher(); + if (maxBuf == 0) { + return -1; + } + return maxBuf; + } + ensureCapacity(read, false); + maxBuf = cipher.processBytes(inBuf, 0, read, buf, 0); + } catch (Exception e) { + throw new IOException("Error processing stream ", e); + } + } + return maxBuf; + } + + private void finaliseCipher() throws IOException { + try { + finalized = true; + ensureCapacity(0, true); + maxBuf = cipher.processBytes(tag, 0, tag.length, buf, 0); + maxBuf = cipher.doFinal(buf, maxBuf) + maxBuf; + } catch (final InvalidCipherTextException e) { + throw new InvalidCipherTextIOException("Error finalising cipher", e); + } catch (Exception e) { + throw new IOException("Error finalising cipher " + e); + } + } + + public int read() throws IOException { + if (bufOff >= maxBuf) { + if (nextChunk() < 0) { + return -1; + } + } + return buf[bufOff++] & 0xff; + } + + public int read(@NotNull byte[] b) throws IOException { + return read(b, 0, b.length); + } + + public int read(@NotNull byte[] b, int off, int len) throws IOException { + if (bufOff >= maxBuf) { + if (nextChunk() < 0) { + return -1; + } + } + int toSupply = Math.min(len, available()); + System.arraycopy(buf, bufOff, b, off, toSupply); + bufOff += toSupply; + return toSupply; + } + + public long skip(long n) { + if (n <= 0) { + return 0; + } + int skip = (int) Math.min(n, available()); + bufOff += skip; + return skip; + } + + public int available() { + return maxBuf - bufOff; + } + + private void ensureCapacity(int updateSize, boolean finalOutput) { + int bufLen; + if (finalOutput) { + bufLen = cipher.getOutputSize(updateSize); + } else { + bufLen = cipher.getUpdateOutputSize(updateSize); + } + if ((buf == null) || (buf.length < bufLen)) { + buf = new byte[bufLen]; + } + } + + public void close() throws IOException { + try { + in.close(); + } finally { + if (!finalized) { + // Reset the cipher, discarding any data buffered in it + // Errors in cipher finalisation trump I/O error closing input + finaliseCipher(); + } + } + maxBuf = bufOff = 0; + markBufOff = 0; + long markPosition = 0; + if (markBuf != null) { + Arrays.fill(markBuf, (byte) 0); + markBuf = null; + } + if (buf != null) { + Arrays.fill(buf, (byte) 0); + buf = null; + } + Arrays.fill(inBuf, (byte) 0); + } + + public void mark(int readlimit) { + in.mark(readlimit); + if (buf != null) { + markBuf = new byte[buf.length]; + System.arraycopy(buf, 0, markBuf, 0, buf.length); + } + markBufOff = bufOff; + } + + public void reset() throws IOException { + throw new IOException("Reset not supported"); + } + + public boolean markSupported() { + return false; + } + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/SymmetricJWK.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/SymmetricJWK.java new file mode 100644 index 00000000..4e2ad169 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/SymmetricJWK.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.crypto; + +import android.net.Uri; + +public class SymmetricJWK { + private String k; + private Uri kid; + + public SymmetricJWK(String octetSequenceKey, Uri kid) { + this.k = octetSequenceKey; + this.kid = kid; + } + + public String getOctetSequenceKey() { + return this.k; + } + + public Uri getKId() { + return this.kid; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/TypedSecureContentReferenceOutput.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/TypedSecureContentReferenceOutput.java new file mode 100644 index 00000000..48526ca0 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/crypto/TypedSecureContentReferenceOutput.java @@ -0,0 +1,52 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.crypto; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; + +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.utils.http.CountedTypedOutput; +import okio.BufferedSink; + +public class TypedSecureContentReferenceOutput extends CountedTypedOutput { + private final SecureContentReference secureContentReference; + + public TypedSecureContentReferenceOutput(String mimeType, File file, Closure callback) { + super(mimeType, file, callback); + secureContentReference = SecureContentReference.createInstance(); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + OutputStream out = secureContentReference.encrypt(sink.outputStream()); + super.writeTo(out); + // SecureContentReference.out() doesn't close the wrapped OutputStream, should closes it later. + out.close(); + } + + public SecureContentReference getSecureContentReference() { + return secureContentReference; + } +} \ No newline at end of file diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/AudioPlaybackStreamType.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/AudioPlaybackStreamType.java new file mode 100644 index 00000000..c08282a3 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/AudioPlaybackStreamType.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media; + +public enum AudioPlaybackStreamType { + + VOICE_CALL(0), SYSTEM(1), RING(2), MUSIC(3), ALARM(4), NOTIFICATION(5), DTMF(8); + + private final int audioPlaybackStreamType; + + public static AudioPlaybackStreamType from(int i) { + for (AudioPlaybackStreamType type : AudioPlaybackStreamType.values()) { + if (type.getValue() == i) { + return type; + } + } + return null; + } + + AudioPlaybackStreamType(final int audioPlaybackStreamType) { + this.audioPlaybackStreamType = audioPlaybackStreamType; + } + + public int getValue() { + return audioPlaybackStreamType; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaCapability.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaCapability.java new file mode 100644 index 00000000..8b150a57 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaCapability.java @@ -0,0 +1,298 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media; + +import android.os.Build; +import android.os.Environment; +import com.ciscowebex.androidsdk.phone.Phone; +import com.ciscowebex.androidsdk.utils.Lists; +import com.github.benoitdion.ln.Ln; +import com.webex.wme.MediaConfig; +import com.webex.wme.MediaConnection; +import me.helloworld.utils.Checker; + +import java.io.File; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; + +public class MediaCapability { + + private static final String DEFAULT_HW_VIDEO_SETTING = "{\"hw-whitelist\": { " + + "\"android\": { " + + "\"defaults\": { " + + "\"mediaCodec\":true," + + "\"yv12Capture\":false" + + "}}}}"; + + private static final List DEFAULT_AE_MODLES = Lists.asList("SM-G93", "SM-G95", "SM-G96", "SM-G97", "SM-N95", "SM-N96", "GM19"); + + private static final int DEFAULT_MAX_STREAMS = 4; + + private int audioMaxBandwidth = Phone.DefaultBandwidth.MAX_BANDWIDTH_AUDIO.getValue() ; + + private int videoMaxBandwidth = Phone.DefaultBandwidth.MAX_BANDWIDTH_720P.getValue() ; + + private int sharingMaxBandwidth = Phone.DefaultBandwidth.MAX_BANDWIDTH_SESSION.getValue() ; + + private String hardwareVideoSetting = DEFAULT_HW_VIDEO_SETTING; + + private boolean hardwareCodecEnable = false; + + private boolean isAudioEnhancement = false; + + private String audioPlaybackFile = ""; + + private String videoPlaybackFile = ""; + + private String deviceSettings = null; + + private int maxNumberStreams = DEFAULT_MAX_STREAMS; + + private boolean multistream = true; + + private WMEngine.Camera camera = WMEngine.Camera.FRONT; + + private EnumSet constraints = EnumSet.noneOf(MediaConstraint.class); + + public MediaCapability() { + setAudioEnhancementModels(null); + } + + public void setAudioMaxBandwidth(int bandwidth) { + if (bandwidth > 0) { + this.audioMaxBandwidth = bandwidth; + } + } + + public void setVideoMaxBandwidth(int bandwidth) { + if (bandwidth > 0) { + this.videoMaxBandwidth = bandwidth; + } + } + + public void setSharingMaxBandwidth(int bandwidth) { + if (bandwidth > 0) { + this.sharingMaxBandwidth = bandwidth; + } + } + + public void setHardwareVideoSetting(String hardwareVideoSetting) { + if (!Checker.isEmpty(hardwareVideoSetting)) { + this.hardwareVideoSetting = hardwareVideoSetting; + } + } + + public boolean isHardwareCodecEnable() { + return hardwareCodecEnable; + } + + public void setHardwareCodecEnable(boolean hardwareCodecEnable) { + this.hardwareCodecEnable = hardwareCodecEnable; + } + + public boolean isAudioEnhancement() { + return isAudioEnhancement; + } + + public void setAudioEnhancementModels(List models) { + List audioEnhancementModels = models == null ? DEFAULT_AE_MODLES : models; + String currentModel = Build.MODEL; + if (currentModel != null) { + for (String model : audioEnhancementModels) { + if (currentModel.equalsIgnoreCase(model) || currentModel.startsWith(model)) { + Ln.d("Enable audio enhancement for " + currentModel); + isAudioEnhancement = true; + return; + } + } + } + isAudioEnhancement = false; + } + + public void setDeviceSettings(String deviceSettings) { + this.deviceSettings = deviceSettings; + } + + public WMEngine.Camera getDefaultCamera() { + return camera; + } + + public void setDefaultCamera(WMEngine.Camera camera) { + this.camera = camera; + } + + public void setAudioPlaybackFile(String audioPlaybackFile) { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + File directory = Environment.getExternalStorageDirectory(); + File file = new File(directory + "/" + audioPlaybackFile); + if (file.exists()) { + this.audioPlaybackFile = file.getAbsolutePath(); + } + } + } + + public void setVideoPlaybackFile(String videoPlaybackFile) { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + File directory = Environment.getExternalStorageDirectory(); + File file = new File(directory + "/" + videoPlaybackFile); + if (file.exists()) { + this.videoPlaybackFile = file.getAbsolutePath(); + } + } + } + + public void setMultistream(boolean multistream) { + this.multistream = multistream; + } + + public int getMaxNumberStreams() { + return maxNumberStreams; + } + + public void addConstraints(MediaConstraint... constraints) { + if (!Checker.isEmpty(constraints)) { + this.constraints.addAll(Arrays.asList(constraints)); + } + } + + public boolean hasAudio() { + return constraints != null && (constraints.contains(MediaConstraint.SendAudio) || constraints.contains(MediaConstraint.ReceiveAudio)); + } + + public boolean hasVideo() { + return constraints != null && (constraints.contains(MediaConstraint.SendVideo) || constraints.contains(MediaConstraint.ReceiveVideo)); + } + + public boolean hasSharing() { + return constraints != null && (constraints.contains(MediaConstraint.SendSharing) || constraints.contains(MediaConstraint.ReceiveSharing)); + } + + public boolean hasSupport(MediaConstraint... constraints) { + if (constraints == null || Checker.isEmpty(constraints)) { + return false; + } + for (MediaConstraint constraint : constraints) { + if (!this.constraints.contains(constraint)) { + return false; + } + } + return true; + } + + public void setupConnection(MediaConnection connection) { + applyConfig(connection.GetGlobalConfig()); + applyConfig(connection.GetAudioConfig(WMEngine.Media.Audio.mid())); + applyConfig(connection.GetVideoConfig(WMEngine.Media.Video.mid())); + applyConfig(connection.GetShareConfig(WMEngine.Media.Sharing.mid())); + } + + private void applyConfig(MediaConfig.GlobalConfig config) { + config.EnableICE(true); + config.EnableSRTP(true); + config.EnableQos(true); + config.EnableMultiStream(multistream); + config.EnablePerformanceTraceDump(MediaConfig.WmePerformanceDumpType.WmePerformanceDumpNone); + config.SetNetworkNotificationParam(MediaConfig.WmeNetworkStatus.WmeNetwork_bad, MediaConfig.WmeNetworkDirection.DIRECTION_BOTHLINK, 5000); + config.SetNetworkNotificationParam(MediaConfig.WmeNetworkStatus.WmeNetwork_video_off, MediaConfig.WmeNetworkDirection.DIRECTION_BOTHLINK, 7000); + config.SetNetworkNotificationParam(MediaConfig.WmeNetworkStatus.WmeNetwork_recovered, MediaConfig.WmeNetworkDirection.DIRECTION_BOTHLINK, 10000); + config.SetICETimeoutParams(10 * 1000, 10 * 1000, 10 * 1000); + config.SetQoSMaxLossRatio(0.08f); + if (isHardwareCodecEnable()) { + config.SetDeviceMediaSettings(hardwareVideoSetting); + } + if (!Checker.isEmpty(deviceSettings)) { + config.SetDeviceMediaSettings(deviceSettings); + } + // config.enableTCAEC(false); + // config.SetShowStunTraceIP(true); + config.EnableFixAudioProcessingArch(true); + } + + private void applyConfig(MediaConfig.AudioConfig config) { + config.SetSelectedCodec(MediaConfig.WmeCodecType.WmeCodecType_OPUS); + config.SetPreferedCodec(MediaConfig.WmeCodecType.WmeCodecType_OPUS); + config.EnableFec(true); + config.EnableRecordLossData(false); + config.EnableClientMix(1); + config.SetMaxBandwidth(audioMaxBandwidth); + if (!Checker.isEmpty(audioPlaybackFile)) { + config.EnableFileCapture(audioPlaybackFile, true); + } + } + + private void applyConfig(MediaConfig.ShareConfig config) { + config.SetMaxBandwidth(sharingMaxBandwidth); + } + + private void applyConfig(MediaConfig.VideoConfig config) { + config.EnableFec(true); + config.EnableRecordLossData(false); + config.SetPreferedCodec(MediaConfig.WmeCodecType.WmeCodecType_AVC); + config.SetSelectedCodec(MediaConfig.WmeCodecType.WmeCodecType_AVC); + config.SetPacketizationMode(MediaConfig.WmePacketizationMode.WmePacketizationMode_1); + config.SetMaxBandwidth(videoMaxBandwidth); + boolean hw = isHardwareCodecEnable(); + long hardwareEncoderEnabled = config.EnableHWAcceleration(hw, MediaConfig.WmeHWAccelerationConfig.WmeHWAcceleration_Encoder); + long hardwareDecoderEnabled = config.EnableHWAcceleration(hw, MediaConfig.WmeHWAccelerationConfig.WmeHWAcceleration_Decoder); + String profileID; + int maxMbps, maxFs, maxBr; + if (hw && MediaError.succeeded(hardwareEncoderEnabled) && MediaError.succeeded(hardwareDecoderEnabled)) { + profileID = "420014"; + maxMbps = 108000; + maxFs = 3600; + maxBr = 1500; + } + else { // 360p + profileID = "42000D"; + maxMbps = 27600; + maxFs = 920; + maxBr = 1000; + } + int maxFps = 3000; + MediaConfig.WmeVideoCodecCapability videoEncoderCodecCapability = new MediaConfig.WmeVideoCodecCapability(); + videoEncoderCodecCapability.uProfileLevelID = Long.parseLong(profileID, 16); + videoEncoderCodecCapability.max_mbps = maxMbps; + videoEncoderCodecCapability.max_fs = maxFs; + videoEncoderCodecCapability.max_br = maxBr; + videoEncoderCodecCapability.max_fps = maxFps; + config.SetEncodeParams(MediaConfig.WmeCodecType.WmeCodecType_AVC, videoEncoderCodecCapability); + MediaConfig.WmeVideoCodecCapability videoDecoderCodecCapability = new MediaConfig.WmeVideoCodecCapability(); + videoDecoderCodecCapability.uProfileLevelID = Long.parseLong(profileID, 16); + videoDecoderCodecCapability.max_mbps = maxMbps; + videoDecoderCodecCapability.max_fs = 8160; + videoDecoderCodecCapability.max_br = maxBr; + videoDecoderCodecCapability.max_fps = maxFps; + config.SetDecodeParams(MediaConfig.WmeCodecType.WmeCodecType_AVC, videoDecoderCodecCapability); + config.Disable90PVideo(true); + config.EnableAVCSimulcast(true); + config.EnableSelfPreviewHorizontalMirror(true); + //config.SetInitSubscribeCount(maxNumberStreams); + if (!Checker.isEmpty(videoPlaybackFile)) { + config.EnableFileCapture(videoPlaybackFile, true); + } + config.SetPacketizationMode(MediaConfig.WmePacketizationMode.WmePacketizationMode_0); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaConstraint.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaConstraint.java new file mode 100644 index 00000000..2a04a468 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaConstraint.java @@ -0,0 +1,27 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media; + +public enum MediaConstraint { + SendAudio, ReceiveAudio, SendVideo, ReceiveVideo, SendSharing, ReceiveSharing; +} \ No newline at end of file diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaError.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaError.java new file mode 100644 index 00000000..aae9f5d8 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaError.java @@ -0,0 +1,87 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media; + +import com.webex.wme.WmeError; + +public class MediaError { + + private String description; + + private String serverity; + + private String errorCode; + + public static boolean succeeded(long result) { + return result == 0; + } + + public static MediaError of(long result) { + if (result == 0) { + return null; + } + String serverity = toSeverity(result); + if (serverity == null) { + // We can ignore these error codes (below warning level) + return null; + } + String description; + if (result == WmeError.E_VIDEO_CAMERA_FAIL) { + description = "Camera Fail"; + } + else if (result == WmeError.E_VIDEO_CAMERA_NOT_AUTHORIZED) { + description = "Camera Not Authorized"; + } + else if (result == WmeError.E_VIDEO_CAMERA_NO_DEVICE) { + description = "Camera No Device"; + } + else if (result == WmeError.E_VIDEO_CAMERA_RUNTIME_DIE) { + description = "Camera Runtime Die"; + } + else { + description = "Error returned from WME"; + } + return new MediaError(String.valueOf(result), serverity, description); + } + + private static String toSeverity(long result) { + long code = (result) & 0x0000F000; + if (code == 0x00002000) { + return "LOW"; + } + else if (code == 0x00004000) { + return "MID"; + } + else if (code == 0x00008000) { + return "HIGH"; + } + return null; + } + + private MediaError(String errorCode, String serverity, String description) { + this.errorCode = errorCode; + this.serverity = serverity; + this.description = description; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaHelper.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaHelper.java new file mode 100644 index 00000000..333c32af --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaHelper.java @@ -0,0 +1,64 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media; + +import android.view.View; +import com.webex.wme.MediaTrack; + +import java.util.Arrays; + +public class MediaHelper { + + private MediaHelper() { + } + + public static String getVideoStreamString(int vid) { + return isActiveSpeaker(vid) ? "ActiveSpeaker" : "Other"; + } + + public static boolean isActiveSpeaker(int videoId) { + return videoId == WMEngine.MAIN_VID; + } + + public static void requestSCR(MediaTrack track, MediaSCR p) { + track.RequestVideo(p.maxFs, p.maxFps, p.maxBr, p.maxDpb, p.maxMbps, p.priority, p.grouping, p.duplicate); + } + + public static MediaTrack.ScalingMode getRenderMode(MediaTrack track, View view) { + if (view == null || track == null) { + return MediaTrack.ScalingMode.CropFill; + } + long decodedHeight = track.getVideoTrackStatistics().uHeight; + long decodedWidth = track.getVideoTrackStatistics().uWidth; + boolean receivingPortrait = decodedHeight > decodedWidth; + long containerWidth = view.getWidth(); + long containerHeight = view.getHeight(); + boolean containerPortrait = containerHeight > containerWidth; + if ((containerPortrait && receivingPortrait) || (!containerPortrait && !receivingPortrait)) { + return MediaTrack.ScalingMode.CropFill; + } + return MediaTrack.ScalingMode.LetterBox; + + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaSCR.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaSCR.java new file mode 100644 index 00000000..cc17fb35 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/MediaSCR.java @@ -0,0 +1,53 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media; + +public class MediaSCR { + + public static final MediaSCR p90 = new MediaSCR(240, 3000, 150000, 891, 7200, 254, 0, false); + public static final MediaSCR p180 = new MediaSCR(396, 3000, 256000, 0, 7200, 255, 0, false); + public static final MediaSCR p360 = new MediaSCR(920, 3000, 640000, 0, 27600, 255, 0, false); + public static final MediaSCR p720 = new MediaSCR(3600, 3000, 1792000, 0, 108000, 255, 0, false); + public static final MediaSCR p1080 = new MediaSCR(8160, 1500, 1500000, 891, 108000, 255, 0, false); + + public int maxFs; + public int maxFps; + public int maxBr; + public int maxDpb; + public int maxMbps; + public int priority; + public int grouping; + public boolean duplicate; + + private MediaSCR(int fs, int fps, int br, int dpb, int mbps, int priority, int grouping, boolean duplicate) { + this.maxFs = fs; + this.maxFps = fps; + this.maxBr = br; + this.maxDpb = dpb; + this.maxMbps = mbps; + this.priority = priority; + this.grouping = grouping; + this.duplicate = duplicate; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WMEngine.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WMEngine.java new file mode 100644 index 00000000..41b047f8 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WMEngine.java @@ -0,0 +1,209 @@ +package com.ciscowebex.androidsdk.internal.media; + +import android.content.Context; +import android.view.View; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.model.MediaEngineReachabilityModel; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.utils.Json; +import com.ciscowebex.androidsdk.internal.media.device.MediaDeviceMananger; +import com.ciscowebex.androidsdk.phone.MediaOption; +import com.ciscowebex.androidsdk.phone.Phone; +import com.github.benoitdion.ln.Ln; +import com.webex.wme.*; +import com.webex.wseclient.WseEngine; +import me.helloworld.utils.Checker; + +import java.util.List; +import java.util.Map; + +public class WMEngine implements StunTraceSink { + + public enum Camera { + FRONT, BACK; + + public DeviceManager.CameraType toDeviceCamera() { + if (this == FRONT) { + return DeviceManager.CameraType.Front; + } + return DeviceManager.CameraType.Back; + } + + public Phone.FacingMode toFaceMode() { + if (this == WMEngine.Camera.BACK) { + return Phone.FacingMode.ENVIROMENT; + } + return Phone.FacingMode.USER; + } + + public static Camera fromFaceMode(Phone.FacingMode mode) { + if (mode == Phone.FacingMode.ENVIROMENT) { + return WMEngine.Camera.BACK; + } + return WMEngine.Camera.FRONT; + } + } + + public enum Media { + Audio, Video, Sharing, Unknown; + + int mid() { + if (this == Audio) { return 1; } + else if (this == Video) { return 2; } + else if (this == Sharing) { return 3; } + return -1; + } + + MediaConnection.MediaType type() { + if (this == Audio) { return MediaConnection.MediaType.Audio; } + else if (this == Video) { return MediaConnection.MediaType.Video; } + else if (this == Sharing) { return MediaConnection.MediaType.Sharing; } + return MediaConnection.MediaType.Unknown; + } + + static Media from(long mid) { + if (mid == 1) { return Audio; } + else if (mid == 2) { return Video; } + else if (mid == 3) { return Sharing; } + return Unknown; + } + } + + public static final long MAIN_VID = 0L; + + private Context context; + private MediaDeviceMananger devManager; + private MediaEngineReachabilityModel reachabilityResult; + private Closure reachabilityHandler; + private WmeSession session; + + public WMEngine(Context context, MediaSessionAPI.TraceLevelMask level) { + this.context = context; + this.devManager = new MediaDeviceMananger(context, this); + NativeMediaSession.initWME(); + MediaSessionAPI.init(context); + StunTrace.INSTANCE.setStunTraceSink(this); + MediaSessionAPI.INSTANCE.setTraceMask(level); + + TraceServer.INSTANCE.setTraceServerSink(new TraceServerSink() { + @Override + public void OnTraceServerResult(WmeStunTraceResult wmeStunTraceResult, String s) { + Ln.d("OnTraceServerResult :Received reachability result: " + s); + Queue.main.run(() -> { + if (Checker.isEmpty(s)) { + WMEngine.this.reachabilityResult = null; + if (WMEngine.this.reachabilityHandler != null) { + WMEngine.this.reachabilityHandler.invoke(null); + WMEngine.this.reachabilityHandler = null; + } + } + else { + WMEngine.this.reachabilityResult = Json.fromJson("{\"reachability\":" + s + "}", MediaEngineReachabilityModel.class); + if (WMEngine.this.reachabilityHandler != null) { + WMEngine.this.reachabilityHandler.invoke(WMEngine.this.reachabilityResult); + WMEngine.this.reachabilityHandler = null; + } + } + }); + } + + @Override + public void OnTraceServerEarlyResult(WmeStunTraceResult wmeStunTraceResult, String s) { + Ln.d("OnTraceServerEarlyResult :Received reachability early result: " + s); + if (!Checker.isEmpty(s)) { + Queue.main.run(() -> { + WMEngine.this.reachabilityResult = Json.fromJson("{\"reachability\":" + s + "}", MediaEngineReachabilityModel.class); + if (WMEngine.this.reachabilityHandler != null) { + WMEngine.this.reachabilityHandler.invoke(WMEngine.this.reachabilityResult); + } + }); + } + } + }); + } + + + public void release() { + Ln.i("MediaEngine released"); + if (session != null && session.getState() != WmeSession.State.DESTROYED) { + session.destroy(); + } + session = null; + devManager = null; + StunTrace.INSTANCE.setStunTraceSink(null); + TraceServer.INSTANCE.setTraceServerSink(null); + NativeMediaSession.unInitWME(); + } + + public String getVersion() { + return MediaSessionAPI.INSTANCE.version() + " (MediaSession)"; + } + + public void setLoggingLevel(MediaSessionAPI.TraceLevelMask level) { + Ln.d("MediaSessionEngine.setLoggingLevel(%d)", level.value()); + MediaSessionAPI.INSTANCE.setTraceMask(level); + } + + public WmeSession createSession(MediaCapability capability, MediaOption option) { + session = new WmeSession(context, devManager, capability); + session.getCapability().addConstraints(MediaConstraint.SendAudio, MediaConstraint.ReceiveAudio); + if (option.hasVideo()) { + session.getCapability().addConstraints(MediaConstraint.SendVideo, MediaConstraint.ReceiveVideo); + session.addRenderView(option.getLocalView(), WmeTrack.Type.LocalVideo); + session.addRenderView(option.getRemoteView(), WmeTrack.Type.RemoteVideo); + } + if (option.hasSharing()) { + session.getCapability().addConstraints(MediaConstraint.SendSharing, MediaConstraint.ReceiveSharing); + session.addRenderView(option.getSharingView(), WmeTrack.Type.RemoteSharing); + } + session.setup(); + return session; + } + + public WmeSession createPreviveSession(MediaCapability capability, View view) { + capability.setDefaultCamera(Camera.FRONT); + WmeSession session = new WmeSession(context, devManager, capability); + session.getCapability().addConstraints(MediaConstraint.SendAudio, MediaConstraint.ReceiveAudio); + session.getCapability().addConstraints(MediaConstraint.SendVideo, MediaConstraint.ReceiveVideo); + session.addRenderView(view, WmeTrack.Type.Preview); + session.setup(); + return session; + } + + public WmeSession getSession() { + return session; + } + + public void performStunReachabilityCheck(Map>> clusterInfo, Closure callback) { + Ln.d("In performStunReachabilityCheck,cluster info is " + clusterInfo); + reachabilityResult = null; + if (reachabilityHandler != null) { + Ln.d("Already started reachability check"); + callback.invoke(null); + return; + } + if (Checker.isEmpty(clusterInfo)) { + Ln.d("Input empty"); + callback.invoke(null); + return; + } + String json = Json.get().toJson(clusterInfo); + reachabilityHandler = callback; + TraceServer.INSTANCE.startTraceServer(json, json.length()); + } + + public void clearReachabilityData() { + reachabilityResult = null; + TraceServer.INSTANCE.stopTraceServer(); + } + + public void setDisplayRotation(int rotation) { + WseEngine.setDisplayRotation(rotation); + } + + @Override + public void OnResult(WmeStunTraceResult wmeStunTraceResult, String detail, long callId) { + Ln.d("Stun Trace result, detail = " + detail + ", callId = " + callId); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeObserver.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeObserver.java new file mode 100644 index 00000000..dd8b7dad --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeObserver.java @@ -0,0 +1,44 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media; + +import android.util.Size; + +public interface WmeObserver { + + void onRemoteVideoAvailable(boolean available); + void onAuxVideoAvailable(int vid, boolean available); + void onRemoteSharingAvailable(boolean available); + + void onActiveSpeakerChanged(long[] oldCSIs, long[] newCSIs); + void onCSIChanged(long vid, long[] oldCSIs, long[] newCSIs); + void onAvailableMediaChanged(int count); + + void onMediaDecodeSizeChanged(WMEngine.Media media, long vid, Size size); + void onMediaRenderSizeChanged(WMEngine.Media media, long vid, Size size); + + void onTrackMuted(WmeTrack.Type track, long vid, boolean mute); + void onCameraSwitched(); + + void onError(MediaError error); +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeSession.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeSession.java new file mode 100644 index 00000000..df6e14ec --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeSession.java @@ -0,0 +1,1026 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media; + +import android.content.Context; +import android.util.Size; +import android.view.View; +import com.cisco.wme.appshare.ScreenShareContext; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.internal.media.device.MediaDeviceMananger; +import com.github.benoitdion.ln.Ln; +import com.webex.wme.*; +import com.webex.wseclient.WseEngine; +import me.helloworld.utils.Checker; + +import java.util.*; + +public class WmeSession implements ScreenShareContext.OnShareStoppedListener, MediaConnection.MediaConnectionListener { + + public enum State { + INITIAL, READY, CONNECTED, DESTROYED; + } + + private final MediaDeviceMananger deviceManager; + private final Context context; + private final MediaCapability capability; + private State state = State.INITIAL; + + private WmeObserver observer; + private Closure sdpCallback; + private String localSdp; + private WmeSdpParsedInfo[] remoteSdp; + private MediaConnection connection; + + private WmeTrack localAudioTrack = new WmeTrack(WmeTrack.Type.LocalAudio); + private WmeTrack localVideoTrack = new WmeTrack(WmeTrack.Type.LocalVideo); + private WmeTrack localSharingTrack = new WmeTrack(WmeTrack.Type.LocalSharing); + private WmeTrack remoteAudioTrack = new WmeTrack(WmeTrack.Type.RemoteAudio); + private WmeTrack remoteVideoTrack = new WmeTrack(WmeTrack.Type.RemoteVideo); + private WmeTrack remoteSharingTrack = new WmeTrack(WmeTrack.Type.RemoteSharing); + private List auxVideoTracks = new ArrayList<>(); + + private String sharingId = ""; + private int auxStreamCount = 0; + private WMEngine.Camera camera; + + WmeSession(Context context, MediaDeviceMananger devManager, MediaCapability capability) { + this.deviceManager = devManager; + this.context = context; + this.capability = capability; + this.camera = capability.getDefaultCamera(); + } + + void setup() { + Ln.d("Setup wme media session"); + if (connection != null || state != State.INITIAL) { + Ln.w("Media Connection has already been created"); + return; + } + connection = new MediaConnection(); + connection.setListener(this); + if (capability.hasAudio()) { + connection.addMedia(WMEngine.Media.Audio.type(), getDirection(WMEngine.Media.Audio), WMEngine.Media.Audio.mid(), ""); + } + if (capability.hasVideo()) { + connection.addMedia(WMEngine.Media.Video.type(), getDirection(WMEngine.Media.Video), WMEngine.Media.Video.mid(), ""); + } + if (capability.hasSharing()) { + connection.addMedia(WMEngine.Media.Sharing.type(), getDirection(WMEngine.Media.Sharing), WMEngine.Media.Sharing.mid(), ""); + ScreenShareContext.getInstance().registerCallback(this); + } + capability.setupConnection(connection); + for (int i = 0; i < capability.getMaxNumberStreams(); i++) { + WmeTrack track = new WmeTrack(WmeTrack.Type.AuxVideo); + auxVideoTracks.add(track); + } + state = State.READY; + } + + public void launch(WmeObserver observer) { + Queue.main.run(() -> { + Ln.d("Launch wme media session: " + state); + if (state != State.READY) { + return; + } + this.observer = observer; + deviceManager.register(); + localAudioTrack.start(); + remoteAudioTrack.start(); + localVideoTrack.start(); + remoteVideoTrack.start(); + if (!localSharingTrack.isSending()) { + remoteSharingTrack.start(); + } + state = State.CONNECTED; + + }); + } + + public void destroy() { + Ln.d("Destroy wme media session"); + state = State.DESTROYED; + if (connection != null && this.isMutedByLocal(WmeTrack.Type.LocalAudio)) { + // Workaround for SPARK-93618, to reset the mute status of WME internal audio engine. + unmute(WmeTrack.Type.LocalVideo); + } + if (localAudioTrack.isReady()) { + localAudioTrack.stop(true); + localAudioTrack.release(); + } + if (remoteAudioTrack.isReady()) { + remoteAudioTrack.stop(true); + remoteAudioTrack.release(); + } + if (localVideoTrack.isReady()) { + localVideoTrack.stop(true); + localVideoTrack.release(); + } + if (remoteVideoTrack.isReady()) { + remoteVideoTrack.stop(true); + remoteVideoTrack.release(); + } + if (localSharingTrack.isReady()) { + localSharingTrack.stop(true); + localSharingTrack.release(); + } + if (remoteSharingTrack.isReady()) { + remoteSharingTrack.stop(true); + remoteSharingTrack.release(); + } + if (getCapability().hasSharing()) { + ScreenShareContext.getInstance().unregisterCallback(this); + } + if (connection != null) { + connection.stopMediaLogging(); + connection.setListener(null); + connection.stop(); + connection.destroy(); + connection = null; + } + localSdp = null; + remoteSdp = null; + localAudioTrack.clear(); + localVideoTrack.clear(); + localSharingTrack.clear(); + remoteAudioTrack.clear(); + remoteVideoTrack.clear(); + remoteSharingTrack.clear(); + deviceManager.unregister(); + } + + public State getState() { + return state; + } + + public String getLocalSdpOffer() { + return localSdp; + } + + public void createLocalSdpOffer(Closure callback) { + Ln.d("createLocalSdpOffer on: " + connection); + if (connection != null) { + localSdp = null; + sdpCallback = callback; + long result = connection.createOffer(); + Ln.d("createLocalSdpOffer result = " + result); + } + } + + public void receiveRemoteAnswer(String sdp) { + Ln.d("receiveRemoteAnswer: " + sdp); + if (!Checker.isEmpty(sdp)) { + if (connection != null) { + WmeSdpParsedInfo[] sdpInfos = connection.setReceivedSDP(MediaConnection.SDPType.Answer, sdp); + updateTracksAddressPort(); + for (WmeSdpParsedInfo sdpInfo : sdpInfos) { + if (sdpInfo.mediaType == com.webex.wme.MediaConnection.MediaType.Video) { + Ln.d("Remote SDP for video is multistream? " + sdpInfo.isMultistream); + //this.isCompositedVideoStream = !sdpInfo.isMultistream; + } + compareAndUpdateTracks(sdpInfo); + } + remoteSdp = sdpInfos; + connection.startMediaLogging(1000); + } + } + } + + private void compareAndUpdateTracks(WmeSdpParsedInfo sdp) { + Ln.d("compareAndUpdateTracks with remote SDP"); + MediaConnection.MediaType type = sdp.mediaType; + MediaConnection.MediaDirection direction = sdp.remoteNegotiatedDirection; + if (!Checker.isEmpty(remoteSdp)) { + for (WmeSdpParsedInfo info : remoteSdp) { + if (info.mediaType == type && info.remoteNegotiatedDirection == direction) { + return; + } + } + } + Ln.d("compareAndUpdateTracks with remote SDP: %s, %s", type, direction); + if (type == MediaConnection.MediaType.Audio) { + localAudioTrack.setRemoteSDPDirection(direction); + remoteAudioTrack.setRemoteSDPDirection(direction); + if (localAudioTrack.isReady()) { + if (localAudioTrack.isSdpAllowSending()) { + localAudioTrack.start(); + } + else { + localAudioTrack.stop(false); + } + } + if (remoteAudioTrack.isReady()) { + if (remoteAudioTrack.isSdpAllowReceiving()) { + remoteAudioTrack.start(); + } + else { + remoteAudioTrack.stop(false); + } + } + } + else if (type == MediaConnection.MediaType.Video) { + localVideoTrack.setRemoteSDPDirection(direction); + remoteVideoTrack.setRemoteSDPDirection(direction); + if (localVideoTrack.isReady()) { + if (localVideoTrack.isSdpAllowSending()) { + localVideoTrack.start(); + } + else { + localVideoTrack.stop(false); + } + } + if (remoteVideoTrack.isReady()) { + if (remoteVideoTrack.isSdpAllowReceiving()) { + remoteVideoTrack.start(); + } + else { + remoteVideoTrack.stop(false); + } + } + } + else if (type == MediaConnection.MediaType.Sharing) { + localSharingTrack.setRemoteSDPDirection(direction); + remoteSharingTrack.setRemoteSDPDirection(direction); + if (capability.hasSharing() && remoteSharingTrack.isReady()) { + if (remoteSharingTrack.isSdpAllowReceiving()) { + if (localSharingTrack.isSending()) { + Ln.d("Skipped - local screen share has already started"); + return; + } + remoteSharingTrack.start(); + } + else { + remoteSharingTrack.stop(false); + } + } + } + } + + public MediaCapability getCapability() { + return capability; + } + + private boolean hasMedia(WmeTrack.Type type) { + if (type == WmeTrack.Type.LocalAudio || type == WmeTrack.Type.RemoteAudio) { + return capability.hasAudio(); + } + else if (type == WmeTrack.Type.LocalVideo || type == WmeTrack.Type.RemoteVideo || type == WmeTrack.Type.Preview || type == WmeTrack.Type.AuxVideo) { + return capability.hasVideo(); + } + else if (type == WmeTrack.Type.LocalSharing || type == WmeTrack.Type.RemoteSharing) { + return capability.hasSharing(); + } + return false; + } + + private MediaConnection.MediaDirection getDirection(WMEngine.Media type) { + if (type == WMEngine.Media.Audio) { + return MediaConnection.MediaDirection.SendRecv; + } + else if (type == WMEngine.Media.Video) { + if (localVideoTrack.getRenderView() != null || remoteVideoTrack.getRenderView() != null) { + return MediaConnection.MediaDirection.SendRecv; + } + return MediaConnection.MediaDirection.Inactive; + } + else if (type == WMEngine.Media.Sharing) { + if (remoteSharingTrack.getRenderView() != null) { + return MediaConnection.MediaDirection.SendRecv; + } + else if (capability.hasSharing()) { + return MediaConnection.MediaDirection.SendOnly; + } + return MediaConnection.MediaDirection.Inactive; + } + return MediaConnection.MediaDirection.SendRecv; + } + + public void addRenderView(View view, WmeTrack.Type type) { + addRenderView(view, type, WMEngine.MAIN_VID); + } + + public void addRenderView(View view, WmeTrack.Type type, long vid) { + Ln.d("addRenderView %s, %s, %s", view, type, vid); + if (view == null) { + Ln.d("Skipped - render view is not ready"); + return; + } + WmeTrack track = getTrack(type, vid); + if (track == null) { + Ln.d("Video track is not ready"); + return; + } + track.addView(view); + } + + public void removeRenderView(View view, WmeTrack.Type type) { + removeRenderView(view, type, WMEngine.MAIN_VID); + } + + public void removeRenderView(View view, WmeTrack.Type type, long vid) { + Ln.d("removeRenderView %s, %s, %s", view, type, vid); + if (view == null) { + Ln.d("Skipped - render view or video track are not ready"); + return; + } + WmeTrack track = getTrack(type, vid); + if (track == null) { + Ln.d("Video track is not ready"); + return; + } + track.removeView(view); + } + + public void removeAllRenderViews(WmeTrack.Type type) { + Ln.d("removeAllRenderViews %s", type); + WmeTrack track = getTrack(type, WMEngine.MAIN_VID); + if (track == null) { + Ln.d("Video track is not ready"); + return; + } + track.removeAllViews(); + } + + public Size getRenderViewSize(WmeTrack.Type type) { + return getRenderViewSize(type, WMEngine.MAIN_VID); + } + + public Size getRenderViewSize(WmeTrack.Type type, long vid) { + WmeTrack track = getTrack(type, vid); + return track == null ? new Size(0, 0) : new Size(track.getVideoWidth(), track.getVideoHeight()); + } + + public View getRenderView(WmeTrack.Type type) { + WmeTrack track = getTrack(type, WMEngine.MAIN_VID); + return track == null ? null : track.getRenderView(); + } + + public WmeTrack getTrack(WmeTrack.Type type, long vid) { + if (type == WmeTrack.Type.LocalAudio) { + return localAudioTrack; + } + else if (type == WmeTrack.Type.LocalVideo || type == WmeTrack.Type.Preview) { + return localVideoTrack; + } + else if (type == WmeTrack.Type.LocalSharing) { + return localSharingTrack; + } + else if (type == WmeTrack.Type.RemoteAudio) { + return remoteAudioTrack; + } + else if (type == WmeTrack.Type.RemoteVideo) { + if (vid == WMEngine.MAIN_VID) { + return remoteVideoTrack; + } + return getAuxVideoTrack(vid); + } + else if (type == WmeTrack.Type.RemoteSharing) { + return remoteSharingTrack; + } + else if (type == WmeTrack.Type.AuxVideo) { + return getAuxVideoTrack(vid); + } + else { + return null; + } + } + + private void setMediaTrackMuted(WmeTrack track, boolean mute) { + Ln.d("setMediaTrackMuted track: " + track + ", mute: " + mute); + if (track == null || !track.isReady()) { + return; + } + long result = mute ? track.getTrack().Mute() : track.getTrack().Unmute(); + if (result != 0) { + MediaError error = MediaError.of(result); + if (observer != null && error != null) { + observer.onError(error); + } + } + else { + if (track.isLocalTrack()) { + track.setSending(!mute); + } + else { + track.setReceiving(!mute); + } + if (observer != null) { + observer.onTrackMuted(track.getType(), track.getVid(), mute); + } + } + } + + public void mute(WmeTrack.Type type) { + mute(type, WMEngine.MAIN_VID); + } + + public void mute(WmeTrack.Type type, long vid) { + if (!hasMedia(type)) { + Ln.d("Media is not presented"); + return; + } + WmeTrack track = getTrack(type, vid); + setMediaTrackMuted(track, true); + } + + public void unmute(WmeTrack.Type type) { + unmute(type, WMEngine.MAIN_VID); + } + + public void unmute(WmeTrack.Type type, long vid) { + if (!hasMedia(type)) { + Ln.d("Media is not presented"); + return; + } + WmeTrack track = getTrack(type, vid); + setMediaTrackMuted(track, false); + } + + public boolean isMutedByLocal(WmeTrack.Type type) { + return isMutedByLocal(type, WMEngine.MAIN_VID); + } + + public boolean isMutedByLocal(WmeTrack.Type type, long vid) { + if (!hasMedia(type)) { + Ln.d("Media is not presented"); + return false; + } + WmeTrack track = getTrack(type, vid); + if (track == null) { + return false; + } + return track.isLocalTrack() ? !track.isSending() : !track.isReceiving(); + } + + public boolean isMutedByRemote(WmeTrack.Type type) { + return isMutedByRemote(type, WMEngine.MAIN_VID); + } + + public boolean isMutedByRemote(WmeTrack.Type type, long vid) { + if (!hasMedia(type)) { + Ln.d("Media is not presented"); + return false; + } + WmeTrack track = getTrack(type, vid); + if (track == null) { + return false; + } + return !track.isLocalTrack() && !track.isSending(); + } + + public void setCamera(WMEngine.Camera camera) { + Ln.d("setCamera: " + camera); + if (!capability.hasSupport(MediaConstraint.SendVideo)) { + Ln.d("Media is not presented"); + return; + } + if (localVideoTrack == null || !localVideoTrack.isReady()) { + Ln.d("Video track is not ready"); + return; + } + if (camera == null || camera == this.camera) { + return; + } + this.camera = camera; + if (applyCamera() && observer != null) { + observer.onCameraSwitched(); + } + } + + public WMEngine.Camera getCamera() { + return camera; + } + + private boolean applyCamera() { + Ln.d("applyCamera %s to %s", camera, localVideoTrack); + if (localVideoTrack == null) { + Ln.d("Video track is not ready"); + return false; + } + if (deviceManager != null) { + DeviceManager.MediaDevice dev = deviceManager.getCamera(camera); + if (dev != null) { + MediaError error = MediaError.of(localVideoTrack.getTrack().SetCaptureDevice(dev)); + if (error != null && observer != null) { + observer.onError(error); + return false; + } + } + } + return true; + } + + public void setAudioVolume(int volume) { + Ln.d("setAudioVolume(), volume = %d", volume); + if (remoteAudioTrack != null && remoteAudioTrack.getTrack() != null) { + remoteAudioTrack.getTrack().setTrackVolume(volume); + } + } + + public int getAudioVolume() { + int volume = 0; + if (remoteAudioTrack != null && remoteAudioTrack.getTrack() != null) { + volume = remoteAudioTrack.getTrack().getTrackVolume(); + } + return volume; + } + + public void headsetPluggedIn() { + Ln.d("headsetPluggedIn"); + if (localAudioTrack != null && localAudioTrack.getTrack() != null) { + localAudioTrack.getTrack().AudioDeviceNotification("WmeAudioAndroid_HeadsetPlugin", 0, 0); + } + } + + public void headsetPluggedOut() { + Ln.d("headsetPluggedOut"); + if (localAudioTrack != null && localAudioTrack.getTrack() != null) { + localAudioTrack.getTrack().AudioDeviceNotification("WmeAudioAndroid_HeadsetPlugout", 0, 0); + } + } + + public AudioPlaybackStreamType getAudioPlaybackStreamType() { + AudioPlaybackStreamType result = null; + if (connection != null) { + MediaConfig.AudioConfig audioConfig = connection.GetAudioConfig(WMEngine.Media.Audio.mid()); + result = AudioPlaybackStreamType.from((int) audioConfig.GetPlaybackStreamMode()); + Ln.i("getAudioPlaybackStreamType() result: %s", result); + } else { + Ln.i("getAudioPlaybackStreamType() defaulting to result: %s (as mediaConnection is null)", result); + } + return result == null ? AudioPlaybackStreamType.VOICE_CALL : result; + } + + public void updateVideoTracks(View local, View remote) { + Ln.d("updateVideoTrack local=%s, remote=%s", local, remote); + if (connection == null) { + Ln.d("Media Connection has not been created"); + return; + } + if (capability.hasVideo()) { + if (local != null && remote != null) { + if (local != localVideoTrack.getRenderView()) { + localVideoTrack.stop(true); + localVideoTrack.removeAllViews(); + localVideoTrack.addView(local); + } + if (remote != remoteVideoTrack.getRenderView()) { + remoteVideoTrack.stop(true); + remoteVideoTrack.removeAllViews(); + remoteVideoTrack.addView(remote); + } + MediaConnection.MediaDirection direction = getDirection(WMEngine.Media.Video); + localVideoTrack.setRemoteSDPDirection(direction); + remoteVideoTrack.setRemoteSDPDirection(direction); + connection.addMedia(WMEngine.Media.Video.type(), direction, WMEngine.Media.Video.mid(), ""); + localVideoTrack.start(); + remoteVideoTrack.start(); + } + else { + localVideoTrack.stop(true); + localVideoTrack.removeAllViews(); + remoteVideoTrack.stop(true); + remoteVideoTrack.removeAllViews(); + MediaConnection.MediaDirection direction = getDirection(WMEngine.Media.Video); + localVideoTrack.setRemoteSDPDirection(direction); + remoteVideoTrack.setRemoteSDPDirection(direction); + connection.updateMedia(direction, WMEngine.Media.Video.mid()); + } + } + } + + public void updateSharingTracks(View view) { + Ln.d("updateSharingTracks view=%s", view); + if (connection == null) { + Ln.d("Media Connection has not been created"); + return; + } + if (capability.hasSharing()) { + if (view == null) { + remoteSharingTrack.stop(true); + remoteSharingTrack.removeAllViews(); + MediaConnection.MediaDirection direction = getDirection(WMEngine.Media.Video); + remoteSharingTrack.setRemoteSDPDirection(direction); + connection.updateMedia(direction, WMEngine.Media.Sharing.mid()); + } + else { + if (view != remoteSharingTrack.getRenderView()) { + remoteSharingTrack.stop(true); + remoteSharingTrack.removeAllViews(); + remoteSharingTrack.addView(view); + } + MediaConnection.MediaDirection direction = getDirection(WMEngine.Media.Video); + remoteSharingTrack.setRemoteSDPDirection(direction); + connection.addMedia(WMEngine.Media.Sharing.type(), direction, WMEngine.Media.Sharing.mid(), ""); + remoteSharingTrack.start(); + } + } + } + + private void updateTracksAddressPort() { + if (connection == null) { + Ln.d("Media Connection has not been created"); + return; + } + MediaStatistics.AudioStatistics audioStatistics = connection.getAudioStatistics(WMEngine.Media.Audio.mid()); + if (audioStatistics != null) { + if (localAudioTrack != null && localAudioTrack.getTrack() != null) { + localAudioTrack.setIpAddress(audioStatistics.mConnection.localIp); + localAudioTrack.setPort((int) audioStatistics.mConnection.uLocalPort); + } + if (remoteAudioTrack != null && remoteAudioTrack.getTrack() != null) { + remoteAudioTrack.setIpAddress(audioStatistics.mConnection.remoteIp); + remoteAudioTrack.setPort((int) audioStatistics.mConnection.uRemotePort); + } + } + if (capability.hasVideo()) { + MediaStatistics.VideoStatistics videoStatistics = connection.getVideoStatistics(WMEngine.Media.Video.mid()); + if (videoStatistics != null) { + if (localVideoTrack != null && localVideoTrack.getTrack() != null) { + localVideoTrack.setIpAddress(videoStatistics.mConnection.localIp); + localVideoTrack.setPort((int) videoStatistics.mConnection.uLocalPort); + } + if (remoteVideoTrack != null && remoteVideoTrack.getTrack() != null) { + remoteVideoTrack.setIpAddress(videoStatistics.mConnection.remoteIp); + remoteVideoTrack.setPort((int) videoStatistics.mConnection.uRemotePort); + } + } + } + if (capability.hasSharing()) { + MediaStatistics.SharingStatistics sharingStatistics = connection.getSharingStatistics(WMEngine.Media.Sharing.mid()); + if (sharingStatistics != null) { + if (localSharingTrack != null && localSharingTrack.getTrack() != null) { + localSharingTrack.setIpAddress(sharingStatistics.mConnection.localIp); + localSharingTrack.setPort((int) sharingStatistics.mConnection.uLocalPort); + } + if (remoteSharingTrack != null && remoteSharingTrack.getTrack() != null) { + remoteSharingTrack.setIpAddress(sharingStatistics.mConnection.remoteIp); + remoteSharingTrack.setPort((int) sharingStatistics.mConnection.uRemotePort); + } + } + } + } + + public void joinSharing(String sharingId, boolean send) { + Ln.d("joinSharing with " + sharingId + ", send: " + send); + if (sharingId != null) { + this.sharingId = sharingId; + if (send && localSharingTrack != null && localSharingTrack.isReady()) { + localSharingTrack.getTrack().SetScreenSharingID(this.sharingId); + if (!localSharingTrack.isSending()) { + localSharingTrack.getTrack().Start(false); + localSharingTrack.setSending(true); + } + } + else if (remoteSharingTrack != null && remoteSharingTrack.isReady() && !send) { + remoteSharingTrack.getTrack().SetScreenSharingID(this.sharingId); + remoteSharingTrack.start(); + } + } + } + + public void leaveSharing(boolean send) { + Ln.d("leaveSharing with " + send); + this.sharingId = ""; + if (send && localSharingTrack != null && localSharingTrack.isReady()) { + localSharingTrack.getTrack().Stop(); + localSharingTrack.setSending(false); + ScreenShareContext.getInstance().finit(); + localSharingTrack.getTrack().SetScreenSharingID(this.sharingId); + } + else if (remoteSharingTrack != null && remoteSharingTrack.isReady() && !send) { + remoteSharingTrack.getTrack().SetScreenSharingID(this.sharingId); + remoteSharingTrack.stop(true); + } + } + + public int getAuxStreamCount() { + return auxStreamCount; + } + + public int subscribeAuxVideo(View view) { + Ln.d("subscribeAuxVideo for " + view); + int vid = -1; + if (connection == null) { + Ln.d("Media Connection has not been created"); + return vid; + } + for (WmeTrack track : auxVideoTracks) { + if (track.getRenderView() == null || track.getVid() <= 0) { + MediaSCR p = MediaSCR.p90; + try { + vid = connection.subscribe(WMEngine.Media.Video.mid(), MediaConfig.WmeSubscribePolicy.ActiveSpeaker, p.maxFs, p.maxFps, p.maxBr, p.maxDpb, p.maxMbps, p.priority, p.grouping, p.duplicate, 0); + } catch (IllegalArgumentException e) { + Ln.e(e, "error calling MediaConnection subscribe"); + } + Ln.d("MediaConnection.subscribe: " + vid); + track.addView(view); + track.setVid(vid); + return vid; + } + } + return vid; + } + + public void unsubscribeAuxVideo(int vid) { + Ln.d("unsubscribeAuxVideo: " + vid); + if (connection == null) { + Ln.d("Media Connection has not been created"); + return; + } + WmeTrack track = getAuxVideoTrack(vid); + if (track != null && track.getRenderView() != null && track.getVid() >= 1) { + track.stop(true); + track.release(); + track.clear(); + connection.unsubscribe(WMEngine.Media.Video.mid(), vid); + } + } + + private WmeTrack getAuxVideoTrack(long vid) { + for (WmeTrack auxTrack : auxVideoTracks) { + if (auxTrack.getVid() == vid) { + return auxTrack; + } + } + return null; + } + + public void onSDPReady(MediaConnection.SDPType type, String sdp) { + Ln.d("Media.onSDPReady, typ=" + type + ", sdp=" + sdp); + localSdp = sdp; + if (sdpCallback != null) { + sdpCallback.invoke(sdp); + } + } + + @Override + public void onMediaReady(int mid, MediaConnection.MediaDirection direction, MediaConnection.MediaType type, MediaTrack track) { + Ln.d("Media.onMediaReady, track=" + track + ", mConn=" + connection + ", mid=" + mid + ", dir=" + direction + ", type=" + type); + if (type == MediaConnection.MediaType.Video) { + if (direction == MediaConnection.MediaDirection.SendOnly) { + localVideoTrack.init(track); + applyCamera(); + WseEngine.EnableCamera2(context); + localVideoTrack.start(); + } + else if (direction == MediaConnection.MediaDirection.RecvOnly) { + long vid = track.getVID(); + Ln.d("onMediaReady track: " + vid); + if (vid == WMEngine.MAIN_VID) { + remoteVideoTrack.init(track); + // TODO start track ? + if (getCapability().isHardwareCodecEnable()) { + MediaHelper.requestSCR(remoteVideoTrack.getTrack(), MediaSCR.p720); + } else { + MediaHelper.requestSCR(remoteVideoTrack.getTrack(), MediaSCR.p360); + } + } + else { + WmeTrack auxTrack = getAuxVideoTrack(vid); + if (auxTrack != null) { + auxTrack.init(track); + auxTrack.start(); + } + } + } + } + else if (type == MediaConnection.MediaType.Audio) { + WmeTrack audioTrack = direction == MediaConnection.MediaDirection.SendOnly ? localAudioTrack : remoteAudioTrack; + audioTrack.init(track); + audioTrack.start(); + } + else if (type == MediaConnection.MediaType.Sharing) { + if (direction == MediaConnection.MediaDirection.RecvOnly) { + remoteSharingTrack.init(track); + MediaHelper.requestSCR(remoteSharingTrack.getTrack(), MediaSCR.p1080); + if (!Checker.isEmpty(sharingId)) { + remoteSharingTrack.getTrack().SetScreenSharingID(sharingId); + remoteSharingTrack.start(); + } + } + else if (direction == MediaConnection.MediaDirection.SendOnly) { + localSharingTrack.init(track); + if (!Checker.isEmpty(sharingId)) { + localSharingTrack.getTrack().SetScreenSharingID(sharingId); + } + } + } + } + + public void onSessionStatus(int mid, MediaConnection.MediaType mediaType, MediaConnection.ConnectionStatus status) { + Ln.d("Media.onSessionStatus: mid=" + mid + ", mediaType=" + mediaType + ", ConnectionStatus=" + status); + if (status == MediaConnection.ConnectionStatus.Connected) { + updateTracksAddressPort(); + } + } + + @Override + public void onMediaBlocked(int mid, int vid, boolean blocked) { + Ln.d("Media.onMediaBlocked, mid=" + mid + ", vid = " + vid + ", blocked=" + blocked); + if (!blocked) { + WMEngine.Media type = WMEngine.Media.from(mid); + if (type == WMEngine.Media.Video) { + if (vid == WMEngine.MAIN_VID) { + if (!remoteVideoTrack.isSending()) { + remoteVideoTrack.setSending(true); + if (observer != null) { + observer.onRemoteVideoAvailable(true); + } + } + } + else { + WmeTrack auxTrack = getAuxVideoTrack(vid); + if (auxTrack != null && !auxTrack.isSending()) { + auxTrack.setSending(true); + if (observer != null) { + observer.onAuxVideoAvailable(vid, true); + } + } + } + } + else if (type == WMEngine.Media.Sharing) { + if (!remoteSharingTrack.isSending()) { + remoteSharingTrack.setSending(true); + if (observer != null) { + observer.onRemoteSharingAvailable(true); + } + } + } + } + } + + /** + * References: + * 1. https://wiki.cisco.com/display/WMEAPI/ActiveVideo + * 2. https://wiki.cisco.com/display/WMEAPI/IWmeMediaConnectionSink#IWmeMediaConnectionSink-onmediastatus + */ + @Override + public synchronized void onMediaStatus(int mid, int vid, MediaConnection.MediaStatus status, boolean hasCSI, long csi) { + WMEngine.Media type = WMEngine.Media.from(mid); + Ln.d("Media.onMediaStatus, mid = %s (%d) vid = %d (%s) status = %s hasCsi = %s csi = %d", type, mid, vid, MediaHelper.getVideoStreamString(vid), status, hasCSI, csi); + if (status != MediaConnection.MediaStatus.Available) { + if (type == WMEngine.Media.Video) { + if (vid == WMEngine.MAIN_VID) { + if (remoteVideoTrack.isSending()) { + remoteVideoTrack.setSending(false); + if (observer != null) { + observer.onRemoteVideoAvailable(false); + } + } + } + else { + WmeTrack track = getAuxVideoTrack(vid); + if (track != null && track.isSending()) { + track.setSending(false); + if (observer != null) { + observer.onAuxVideoAvailable(vid, false); + } + } + } + } + else if (type == WMEngine.Media.Sharing) { + if (remoteSharingTrack.isSending()) { + remoteSharingTrack.setSending(false); + if (observer != null) { + observer.onRemoteSharingAvailable(false); + } + } + } + } + if (type == WMEngine.Media.Video && hasCSI) { + this.OnCSIsChanged(mid, vid, new long[0], new long[]{csi}); + } + + } + + public void onAvailableMediaChanged(int mid, int count) { + Ln.d("Media.onAvailableMediaChanged, mid = " + mid + ", count = " + count); + WMEngine.Media type = WMEngine.Media.from(mid); + if (type == WMEngine.Media.Video) { + auxStreamCount = count; + if (observer != null) { + observer.onAvailableMediaChanged(count); + } + } + } + + public void OnCSIsChanged(long mid, long vid, long[] oldCSIs, long[] newCSIs) { + Ln.d("Media.OnCSIsChanged, mid = " + mid + ", vid = " + vid + ", oldCSIs = " + Arrays.toString(oldCSIs) + ", newCSIs = " + Arrays.toString(newCSIs)); + WMEngine.Media type = WMEngine.Media.from(mid); + if (type == WMEngine.Media.Video && observer != null) { + if (vid == WMEngine.MAIN_VID) { + observer.onActiveSpeakerChanged(oldCSIs, newCSIs); + } + else { + observer.onCSIChanged(vid, oldCSIs, newCSIs); + } + } + } + + public void onDecodeSizeChanged(int mid, int vid, int width, int height) { + Ln.d("Media.onDecodeSizeChanged, mid = " + mid + ", vid = " + vid + ", width = " + width + ", height = " + height); + if (mid == WMEngine.Media.Video.mid()) { + WmeTrack track = vid == WMEngine.MAIN_VID ? remoteVideoTrack : getAuxVideoTrack(vid); + if (track != null) { + track.setVideoWidth(width); + track.setVideoHeight(height); + track.updateRenderMode(); + } + } + else if (mid == WMEngine.Media.Sharing.mid()) { + remoteSharingTrack.setVideoWidth(width); + remoteSharingTrack.setVideoHeight(height); + } + if (observer != null) { + observer.onMediaDecodeSizeChanged(WMEngine.Media.from(mid), vid, new Size(width, height)); + } + } + + public void onRenderSizeChanged(int mid, int vid, MediaConnection.MediaDirection direction, MediaConnection.WmeVideoSizeInfo size) { + Ln.d("Media.onRenderSizeChanged, mid = " + mid + ", vid = " + vid + ", direction = " + direction); + WmeTrack track = null; + WMEngine.Media media = WMEngine.Media.from(mid); + if (media == WMEngine.Media.Video) { + if (direction == MediaConnection.MediaDirection.SendOnly) { + track = localVideoTrack; + } + } + else if (media == WMEngine.Media.Sharing) { + track = localSharingTrack; + } + if (track != null) { + int width = size.GetRealWidth(); + int height = size.GetRealHeight(); + track.setVideoWidth(width); + track.setVideoHeight(height); + if (observer != null) { + observer.onMediaRenderSizeChanged(media, vid, new Size(width, height)); + } + } + } + + public void onShareStopped() { + Ln.d("MediaSessionImpl.onShareStopped"); + } + + public void OnRequestAvatarForMute(boolean mute) { + Ln.d("MediaSessionImpl.OnRequestAvatarForMute(), mute = " + mute); + } + + public int onPerformanceStatus(MediaConnection.PerformanceStatus status, MediaConnection.PerformanceReason reason) { + Ln.i("MediaSessionImpl.onPerformanceStatus: status=" + status.value() + ", reason=" + reason.value()); + return status.value(); + } + + public void OnEventReportReady(MediaConnection.EventMetricsType eventMetricsType, String eventMetric) { + Ln.d("OnEventReportReady, type: '%s', metric: '%s'", eventMetricsType.toString(), eventMetric); + } + + public void onNetworkStatus(MediaConnection.NetworkStatus networkStatus, MediaConnection.NetworkDirection networkDirection) { + Ln.d("MediaSessionImpl.onNetworkStatus, status = " + networkStatus.toString()); + } + + public void onError(int errorCode) { + Ln.d("MediaSession.onError, code = " + errorCode); + } + + public void onMediaError(int mid, int vid, int errorCode) { + Ln.d("MediaSessionImpl.onMediaError, vid = " + vid + ", mid = " + mid + ", errorCode = " + errorCode); + } + + public void onEncodeSizeChanged(int mid, int width, int height) { + Ln.d("MediaSessionImpl.onEncodeSizeChanged, mid = " + mid + ", width = " + width + ", height = ", height); + } + + + + + + + + + + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeTrack.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeTrack.java new file mode 100644 index 00000000..d26fdcac --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/WmeTrack.java @@ -0,0 +1,304 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media; + +import android.view.View; +import com.github.benoitdion.ln.Ln; +import com.webex.wme.MediaConnection; +import com.webex.wme.MediaTrack; +import me.helloworld.utils.Objects; +import me.helloworld.utils.annotation.StringPart; + +public class WmeTrack { + + public enum Type { + LocalAudio, RemoteAudio, LocalSharing, RemoteSharing, + LocalVideo, RemoteVideo, AuxVideo, Preview + } + + @StringPart + private final WmeTrack.Type type; + + private MediaTrack track; + + @StringPart + private long vid = -1; + + @StringPart + private MediaConnection.MediaDirection remoteSDPDirection = MediaConnection.MediaDirection.Inactive; + + private View renderView; + + @StringPart + private boolean receiving = true; + + @StringPart + private boolean sending = true; + + private int videoHeight = 0; + + private int videoWidth = 0; + + private int port; + + private String ipAddress; + + @StringPart + private boolean ready; + + @StringPart + private boolean viewAdded; + + public WmeTrack(Type type) { + this.type = type; + if (type == Type.LocalSharing || type == Type.AuxVideo) { + this.sending = false; + } + } + + public void init(MediaTrack track) { + Ln.d("Track init: " + this + " with " + track); + this.track = track; + this.ready = true; + } + + public void start() { + if (!isReady()) { + Ln.d("Track is not ready, " + this); + return; + } + if (isLocalTrack()) { + if (type != Type.Preview && !isSdpAllowSending()) { + Ln.d("Skipped - not sending media, " + this); + return; + } + } + else { + if (type != Type.AuxVideo && !isSdpAllowReceiving()) { + Ln.d("Skipped - not receiving media, " + this); + return; + } + } + if (type == Type.LocalAudio || type == Type.RemoteAudio) { + if (port == 0) { + Ln.d("Skipped - port is 0, " + this); + return; + } + } + else { + attachView(getRenderView()); + if (type == Type.LocalVideo || type == Type.Preview) { + track.SetRenderMode(MediaTrack.ScalingMode.CropFill); + } + } + if (isLocalTrack()) { + track.Start(!isSending()); + } + else { + track.Start(!isReceiving()); + } + Ln.d("Track start: " + this); + } + + public void stop(boolean removeView) { + if (!isReady()) { + Ln.d("Track is not ready, " + this); + return; + } + track.Stop(); + if (removeView && (type == Type.LocalVideo || type == Type.RemoteVideo + || type == Type.AuxVideo || type == Type.Preview + || type == Type.LocalSharing || type == Type.RemoteSharing)) { + detachView(getRenderView()); + } + Ln.d("Track stopped: " + this); + } + + public void release() { + setReady(false); + detachView(getRenderView()); + if (this.track != null) { + this.track.destroy(); + this.track = null; + } + Ln.d("Track released: " + this); + } + + public void clear() { + renderView = null; + vid = -1; + videoWidth = 0; + videoHeight = 0; + port = 0; + ipAddress = ""; + remoteSDPDirection = MediaConnection.MediaDirection.Inactive; + receiving = true; + sending = true; + if (type == Type.LocalSharing || type == Type.AuxVideo) { + this.sending = false; + } + } + + public void updateRenderMode() { + MediaTrack track = getTrack(); + View view = getRenderView(); + if (track != null && view != null) { + track.SetRenderMode(MediaHelper.getRenderMode(track, view)); + } + } + + public Type getType() { + return type; + } + + public MediaTrack getTrack() { + return track; + } + + public long getVid() { + return vid; + } + + public void setVid(long vid) { + this.vid = vid; + } + + public void setRemoteSDPDirection(MediaConnection.MediaDirection remoteSDPDirection) { + this.remoteSDPDirection = remoteSDPDirection; + } + + public View getRenderView() { + return renderView; + } + + public void addView(View view) { + if (view != null && renderView != view) { + renderView = view; + if (type == Type.AuxVideo && isReady() && track != null) { + attachView(view); + } + } + } + + public void removeView(View view) { + if (view != null && renderView == view) { + renderView = null; + if (type == Type.AuxVideo && isReady() && track != null) { + detachView(view); + } + } + } + + public void removeAllViews() { + renderView = null; + } + + public boolean isReceiving() { + return receiving; + } + + public void setReceiving(boolean receiving) { + this.receiving = receiving; + } + + public boolean isSending() { + return sending; + } + + public void setSending(boolean sending) { + this.sending = sending; + } + + public int getVideoHeight() { + return videoHeight; + } + + public void setVideoHeight(int videoHeight) { + this.videoHeight = videoHeight; + } + + public int getVideoWidth() { + return videoWidth; + } + + public void setVideoWidth(int videoWidth) { + this.videoWidth = videoWidth; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public boolean isReady() { + return ready; + } + + public void setReady(boolean ready) { + this.ready = ready; + } + + public boolean isLocalTrack() { + return type == Type.LocalAudio || type == Type.LocalVideo || type == Type.LocalSharing || type == Type.Preview; + } + + public boolean isSdpAllowSending() { + return remoteSDPDirection != MediaConnection.MediaDirection.Inactive && remoteSDPDirection != MediaConnection.MediaDirection.SendOnly; + } + + public boolean isSdpAllowReceiving() { + return remoteSDPDirection != MediaConnection.MediaDirection.Inactive && remoteSDPDirection != MediaConnection.MediaDirection.RecvOnly; + } + + private void attachView(View view) { + if (view != null && !viewAdded) { + if (track.addRenderWindow(view) == 0) { + viewAdded = true; + } + } + } + + private void detachView(View view) { + if (view != null && viewAdded) { + if (track.removeRenderWindow(view) == 0) { + viewAdded = false; + } + } + } + + @Override + public String toString() { + return Objects.toStringByAnnotation(this, "WmeTrack[" + System.identityHashCode(this) + "]"); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/AudioDeviceConnectionManager.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/AudioDeviceConnectionManager.java new file mode 100644 index 00000000..37d0dbc0 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/AudioDeviceConnectionManager.java @@ -0,0 +1,247 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media.device; + +import android.bluetooth.*; +import android.content.Context; +import android.media.AudioManager; +import com.ciscowebex.androidsdk.internal.media.*; +import com.github.benoitdion.ln.Ln; +import com.webex.wme.MediaSessionAPI; + +import java.util.List; + +public class AudioDeviceConnectionManager { + + enum ConnectionStatus { + INITIALIZE, NONE, WIRED_HEADSET, BLUETOOTH + } + + enum DevicePref { + SPEAKER, EARPIECE + } + + public static final int STREAM_BLUETOOTH_SCO = 6; + + protected AudioManagerDelegate audioManager; + protected WMEngine mediaEngine; + + private ConnectionStatus status = ConnectionStatus.NONE; + private ConnectionStatus previousStatus = ConnectionStatus.INITIALIZE; + private DevicePref devicePreference = DevicePref.SPEAKER; + + private BluetoothHeadset bluetoothHeadset = null; + private BluetoothA2dp bluetoothA2dp = null; + + public AudioDeviceConnectionManager(Context context, WMEngine engine) { + this.audioManager = new AudioManagerDelegate(context); + this.mediaEngine = engine; + } + + public void initialize() { + status = ConnectionStatus.NONE; + previousStatus = ConnectionStatus.INITIALIZE; + bluetoothHeadset = null; + bluetoothA2dp = null; + } + + public void uninitialize() { + status = ConnectionStatus.NONE; + previousStatus = ConnectionStatus.INITIALIZE; + BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (bluetoothAdapter != null) { + bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, bluetoothHeadset); + bluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, bluetoothA2dp); + } + bluetoothHeadset = null; + bluetoothA2dp = null; + } + + public AudioManagerDelegate getAudioManager() { + return audioManager; + } + + public void requestAudioFocus() { + WmeSession session = mediaEngine.getSession(); + boolean audioOnly = session != null && !session.getCapability().hasVideo() && !session.getCapability().hasSharing(); + try { + if (session != null && session.getCapability().hasAudio()) { + if (!audioManager.isWiredHeadsetOrBluetoothConnected()) { + if (audioOnly) { + Ln.d("requestAudioFocus: play through earpiece"); + devicePreference = DevicePref.EARPIECE; + playThroughEarpiece(); + } else { + Ln.d("requestAudioFocus: play through speaker"); + devicePreference = DevicePref.SPEAKER; + playThroughSpeakerPhone(); + } + } + } + if (isAudioEnhancement()) { + MediaSessionAPI.enableAudioEnhancement(true); + } + int playbackStreamType = session == null ? AudioManager.STREAM_VOICE_CALL : session.getAudioPlaybackStreamType().getValue(); + Ln.i("requestAudioFocus playbackStreamType(%s)", playbackStreamType); + audioManager.requestAudioFocus(null, playbackStreamType, android.media.AudioManager.AUDIOFOCUS_GAIN); + } catch (Throwable t) { + Ln.e(t); + } + } + + public void abandonAudioFocus() { + if (audioManager.isBluetoothScoOn()) { + audioManager.stopBluetoothSco(); + } + audioManager.setMode(android.media.AudioManager.MODE_NORMAL); + audioManager.abandonAudioFocus(null); + } + + void setBluetoothHeadset(BluetoothHeadset bluetoothHeadset) { + this.bluetoothHeadset = bluetoothHeadset; + doUpdate(); + } + + void setBluetoothA2dp(BluetoothA2dp bluetoothA2dp) { + this.bluetoothA2dp = bluetoothA2dp; + doUpdate(); + } + + void onWiredHeadsetStateUpdated(boolean connected) { + WmeSession session = mediaEngine == null ? null : mediaEngine.getSession(); + if (session != null) { + if (connected) { + session.headsetPluggedIn(); + } + else { + session.headsetPluggedOut(); + } + } + doUpdate(); + } + + void onBluetoothStateUpdated() { + doUpdate(); + } + + private void doUpdate() { + if (audioManager.isWiredHeadsetOn()) { + status = ConnectionStatus.WIRED_HEADSET; + } + else if (audioManager.isBluetoothScoAvailableOffCall() && (isBTHeadsetConnected() || isBTA2dpConnected())) { + status = ConnectionStatus.BLUETOOTH; + } + else { + status = ConnectionStatus.NONE; + } + Ln.d("status: " + status + "; previousStatus: " + previousStatus + "; devicePreference: " + devicePreference); + if (status != previousStatus) { + previousStatus = status; + if (status == ConnectionStatus.WIRED_HEADSET) { + Ln.d("playThroughWiredHeadset"); + audioManager.stopBluetoothSco(); + audioManager.setSpeakerphoneOn(false); + audioManager.setMode(isAudioEnhancement() ? android.media.AudioManager.MODE_IN_COMMUNICATION : android.media.AudioManager.MODE_NORMAL); + } + else if (status == ConnectionStatus.BLUETOOTH) { + Ln.d("playThroughBluetooth"); + audioManager.setMode(android.media.AudioManager.MODE_IN_COMMUNICATION); + audioManager.setSpeakerphoneOn(false); + audioManager.startBluetoothSco(); + } + else { + if (devicePreference == DevicePref.EARPIECE) { + playThroughEarpiece(); + } + else { + playThroughSpeakerPhone(); + } + } + updateAudioVolume(); + } + } + + public void updateAudioVolume() { + int streamType; + if (audioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) { + if (audioManager.isBluetoothScoOn()) { + streamType = STREAM_BLUETOOTH_SCO; + } else { + streamType = AudioManager.STREAM_VOICE_CALL; + } + } else { + streamType = AudioManager.STREAM_MUSIC; + } + + int currentVol = audioManager.getStreamVolume(streamType); + int maxVol = audioManager.getStreamMaxVolume(streamType); + int volSetting = (65535 * currentVol) / maxVol; + Ln.d("updateAudioVolume: streamType=%s; set volume to=%s(%s/%s)", streamType, volSetting, currentVol, maxVol); + WmeSession session = mediaEngine == null ? null : mediaEngine.getSession(); + if (session != null) { + session.setAudioVolume(volSetting); + } + } + + private boolean isBTHeadsetConnected() { + if (bluetoothHeadset == null) { + return false; + } + List connectedDevices = bluetoothHeadset.getConnectedDevices(); + return connectedDevices != null && !connectedDevices.isEmpty(); + } + + public boolean isBTA2dpConnected() { + if (bluetoothA2dp == null) { + return false; + } + List connectedDevices = bluetoothA2dp.getConnectedDevices(); + return connectedDevices != null && !connectedDevices.isEmpty(); + } + + private boolean isAudioEnhancement() { + WmeSession session = mediaEngine == null ? null : mediaEngine.getSession(); + if (session != null) { + MediaCapability capability = session.getCapability(); + return capability != null && capability.isAudioEnhancement(); + } + return false; + } + + private void playThroughSpeakerPhone() { + Ln.d("playThroughSpeakerPhone"); + audioManager.stopBluetoothSco(); + audioManager.setSpeakerphoneOn(true); + int mode = isAudioEnhancement() ? android.media.AudioManager.MODE_IN_COMMUNICATION : android.media.AudioManager.MODE_NORMAL; + audioManager.setMode(mode); + } + + private void playThroughEarpiece() { + Ln.d("playThroughEarpiece"); + audioManager.stopBluetoothSco(); + audioManager.setSpeakerphoneOn(false); + audioManager.setMode(android.media.AudioManager.MODE_IN_COMMUNICATION); + } + + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/AudioManagerDelegate.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/AudioManagerDelegate.java new file mode 100644 index 00000000..647dd619 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/AudioManagerDelegate.java @@ -0,0 +1,134 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media.device; + +import android.content.Context; +import android.media.AudioManager; +import android.os.Handler; +import com.github.benoitdion.ln.Ln; + +public class AudioManagerDelegate { + + private AudioManager delegate; + private boolean hasAudioFocus; + + public AudioManagerDelegate(Context context) { + delegate = (android.media.AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + } + + public void setSpeakerphoneOn(boolean on) { + Ln.i("AudioManager.setSpeakerphoneOn(%b)", on); + delegate.setSpeakerphoneOn(on); + } + + public boolean isSpeakerphoneOn() { + return delegate.isSpeakerphoneOn(); + } + + public void setMode(int mode) { + Ln.i("AudioManager.setMode(%d) from (%d)", mode, delegate.getMode()); + delegate.setMode(mode); + } + + public int getMode() { + return delegate.getMode(); + } + + public boolean isMusicActive() { + return delegate.isMusicActive(); + } + + public boolean isWiredHeadsetOn() { + boolean isWiredHeadsetOn = delegate.isWiredHeadsetOn(); + Ln.i("AudioManager.isWiredHeadsetOn() = %b", isWiredHeadsetOn); + return isWiredHeadsetOn; + } + + public boolean isBluetoothScoOn() { + boolean isBluetoothScoOn = delegate.isBluetoothScoOn(); + Ln.i("AudioManager.isBluetoothScoOn() = %b", isBluetoothScoOn); + return isBluetoothScoOn; + } + + public boolean isWiredHeadsetOrBluetoothConnected() { + boolean isWiredHeadsetOrBluetoothConnected = isBluetoothScoOn() || isWiredHeadsetOn(); + Ln.i("AudioManager.isWiredHeadsetOrBluetoothConnected() = %b", isWiredHeadsetOrBluetoothConnected); + return isWiredHeadsetOrBluetoothConnected; + } + + public boolean isBluetoothScoAvailableOffCall() { + boolean isBluetoothScoAvailableOffCall = delegate.isBluetoothScoAvailableOffCall(); + Ln.i("AudioManager.isBluetoothScoAvailableOffCall() = %b", isBluetoothScoAvailableOffCall); + return isBluetoothScoAvailableOffCall; + } + + public int getStreamVolume(int streamType) { + int volume = delegate.getStreamVolume(streamType); + Ln.i("AudioManager.getStreamVolume() type = %d, volume = %d", streamType, volume); + return volume; + } + + public int getStreamMaxVolume(int streamType) { + int maxVolume = delegate.getStreamMaxVolume(streamType); + Ln.i("AudioManager.getStreamMaxVolume() type = %d, volume = %d", streamType, maxVolume); + return maxVolume; + } + + public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener l, int streamType, int durationHint) { + Ln.i("AudioManager.requestAudioFocus() streamType = %d", streamType); + hasAudioFocus = true; + return delegate.requestAudioFocus(l, streamType, durationHint); + } + + public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener l) { + Ln.i("AudioManager.abandonAudioFocus()"); + hasAudioFocus = false; + return delegate.abandonAudioFocus(l); + } + + public boolean hasAudioFocus() { + return hasAudioFocus; + } + + public void startBluetoothSco() { + Ln.i("AudioManager.startBluetoothSco()"); + // sleep 1 second to wait BT device is completely initialized. + new Handler().postDelayed(() -> { + Ln.i("AudioManager.startBluetoothSco() executes after 1 second"); + delegate.startBluetoothSco(); + }, 1000); + } + + public void stopBluetoothSco() { + Ln.i("AudioManager.stopBluetoothSco()"); + if (isBluetoothScoOn()) { + delegate.setBluetoothScoOn(false); + delegate.stopBluetoothSco(); + } + } + + public void setBluetoothScoAvailableOffCall(boolean bluetoothScoAvailableOffCall) { + Ln.d("AudioManager.setBluetoothScoAvailableOffCall() Wrong call! This is for test use."); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/BluetoothBroadcastReceiver.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/BluetoothBroadcastReceiver.java new file mode 100644 index 00000000..70d8a09c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/BluetoothBroadcastReceiver.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media.device; + +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothHeadset; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.media.AudioManager; +import com.github.benoitdion.ln.Ln; + +public class BluetoothBroadcastReceiver extends BroadcastReceiver { + + AudioDeviceConnectionManager audioDeviceConnectionManager; + + public BluetoothBroadcastReceiver(AudioDeviceConnectionManager manager) { + audioDeviceConnectionManager = manager; + } + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { + int extraState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, -1); + Ln.i("BluetoothBroadcastReceiver, action: " + action + "; extraState: " + extraState); + if (BluetoothHeadset.STATE_CONNECTED == extraState) { + audioDeviceConnectionManager.onBluetoothStateUpdated(); + } + else if (BluetoothHeadset.STATE_DISCONNECTED == extraState) { + audioDeviceConnectionManager.onBluetoothStateUpdated(); + } + } + else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { + int extraState = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, -1); + Ln.i("BluetoothBroadcastReceiver, action: " + action + "; extraState: " + extraState); + if (BluetoothA2dp.STATE_CONNECTED == extraState) { + audioDeviceConnectionManager.onBluetoothStateUpdated(); + } + else if (BluetoothA2dp.STATE_DISCONNECTED == extraState) { + audioDeviceConnectionManager.onBluetoothStateUpdated(); + } + } + else if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(action)) { + int scoState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + Ln.i("BluetoothBroadcastReceiver, sco state: " + scoState); + if (AudioManager.SCO_AUDIO_STATE_CONNECTED == scoState) { + audioDeviceConnectionManager.updateAudioVolume(); + } + } + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/BluetoothServiceListener.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/BluetoothServiceListener.java new file mode 100644 index 00000000..00391024 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/BluetoothServiceListener.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media.device; + +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothProfile; +import com.github.benoitdion.ln.Ln; + +public class BluetoothServiceListener implements BluetoothProfile.ServiceListener { + + private AudioDeviceConnectionManager audioDeviceConnectionManager; + + public BluetoothServiceListener(AudioDeviceConnectionManager audioDeviceConnectionManager) { + this.audioDeviceConnectionManager = audioDeviceConnectionManager; + } + + public void onServiceConnected(int profile, BluetoothProfile proxy) { + Ln.d("BluetoothServiceListener.onServiceConnected, profile = " + (profile == BluetoothProfile.HEADSET ? "HEADSET" : "A2DP")); + if (BluetoothProfile.HEADSET == profile) { + audioDeviceConnectionManager.setBluetoothHeadset((BluetoothHeadset) proxy); + } + else if (BluetoothProfile.A2DP == profile) { + audioDeviceConnectionManager.setBluetoothA2dp((BluetoothA2dp) proxy); + } + } + + public void onServiceDisconnected(int profile) { + Ln.d("BluetoothServiceListener.onServiceDisconnected, profile = " + (profile == BluetoothProfile.HEADSET ? "HEADSET" : "A2DP")); + if (BluetoothProfile.HEADSET == profile) { + audioDeviceConnectionManager.setBluetoothHeadset(null); + } + else if (BluetoothProfile.A2DP == profile) { + audioDeviceConnectionManager.setBluetoothA2dp(null); + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/HeadsetIntentReceiver.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/HeadsetIntentReceiver.java new file mode 100644 index 00000000..100a5ac3 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/HeadsetIntentReceiver.java @@ -0,0 +1,55 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media.device; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import com.github.benoitdion.ln.Ln; + +import java.util.Objects; + +public class HeadsetIntentReceiver extends BroadcastReceiver { + + private AudioDeviceConnectionManager audioDeviceConnectionManager; + + public HeadsetIntentReceiver(AudioDeviceConnectionManager manager) { + this.audioDeviceConnectionManager = manager; + } + + public void onReceive(Context context, Intent intent) { + if (Objects.equals(intent.getAction(), Intent.ACTION_HEADSET_PLUG)) { + if (intent.hasExtra("state")) { + int state = intent.getIntExtra("state", 0); + if (state == 0) { + Ln.i("HeadsetIntentReceiver.onReceive(), headset plugged out"); + audioDeviceConnectionManager.onWiredHeadsetStateUpdated(false); + } + else if (state == 1) { + Ln.i("HeadsetIntentReceiver.onReceive(), headset plugged in"); + audioDeviceConnectionManager.onWiredHeadsetStateUpdated(true); + } + } + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/MediaDeviceMananger.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/MediaDeviceMananger.java new file mode 100644 index 00000000..45f2bc00 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/MediaDeviceMananger.java @@ -0,0 +1,149 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media.device; + +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.internal.media.WMEngine; +import com.ciscowebex.androidsdk.internal.media.WmeSession; +import com.ciscowebex.androidsdk.internal.media.WmeTrack; +import com.github.benoitdion.ln.Ln; +import com.webex.wme.DeviceManager; + +public class MediaDeviceMananger { + + private final Context context; + private final DeviceManager deviceManager; + private AudioDeviceConnectionManager audioDeviceConnectionManager; + private BluetoothBroadcastReceiver bluetoothBroadcastReceiver; + private BluetoothServiceListener bluetoothServiceListener; + private HeadsetIntentReceiver headsetIntentReceiver; + private VolumeSettingChangedListener volumeSettingChangedListener; + private ProximitySensor proximitySensor; + private boolean videoMutedByProximity = false; + private boolean speakerOnBeforeProximity = false; + + public MediaDeviceMananger(Context context, WMEngine engine) { + this.context = context; + this.deviceManager = new DeviceManager(); + this.audioDeviceConnectionManager = new AudioDeviceConnectionManager(context, engine); + this.bluetoothBroadcastReceiver = new BluetoothBroadcastReceiver(audioDeviceConnectionManager); + this.proximitySensor = new ProximitySensor(context, event -> Queue.main.run(() -> { + AudioManagerDelegate delegate = audioDeviceConnectionManager.getAudioManager(); + Ln.d("ProximitySensor.onEvent: " + event + ", " + delegate.isWiredHeadsetOn()); + if (!delegate.isWiredHeadsetOn()) { + if (event == ProximitySensor.Listener.ProximityEvent.NEAR) { + speakerOnBeforeProximity = delegate.isSpeakerphoneOn(); + if (speakerOnBeforeProximity) { + delegate.setMode(android.media.AudioManager.MODE_IN_COMMUNICATION); + delegate.setSpeakerphoneOn(false); + audioDeviceConnectionManager.updateAudioVolume(); + } + WmeSession session = engine.getSession(); + if (session != null && session.getState() == WmeSession.State.CONNECTED) { + session.mute(WmeTrack.Type.LocalVideo); + videoMutedByProximity = true; + proximitySensor.disableScreen(); + } + } + else if (event == ProximitySensor.Listener.ProximityEvent.FAR) { + if (speakerOnBeforeProximity) { + delegate.setMode(android.media.AudioManager.MODE_NORMAL); + delegate.setSpeakerphoneOn(speakerOnBeforeProximity); + audioDeviceConnectionManager.updateAudioVolume(); + speakerOnBeforeProximity = false; + } + WmeSession session = engine.getSession(); + if (session != null && session.getState() == WmeSession.State.CONNECTED + && session.isMutedByLocal(WmeTrack.Type.LocalVideo) && videoMutedByProximity) { + session.unmute(WmeTrack.Type.LocalVideo); + videoMutedByProximity = false; + proximitySensor.enableScreen(); + } + } + } + })); + } + + public void register() { + Ln.d("registerMediaDevice"); + audioDeviceConnectionManager.requestAudioFocus(); + try { + audioDeviceConnectionManager.initialize(); + headsetIntentReceiver = new HeadsetIntentReceiver(audioDeviceConnectionManager); + context.registerReceiver(headsetIntentReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); + proximitySensor.onResume(); + + bluetoothServiceListener = new BluetoothServiceListener(audioDeviceConnectionManager); + BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (bluetoothAdapter != null) { + bluetoothAdapter.getProfileProxy(context, bluetoothServiceListener, BluetoothProfile.HEADSET); + bluetoothAdapter.getProfileProxy(context, bluetoothServiceListener, BluetoothProfile.A2DP); + context.registerReceiver(bluetoothBroadcastReceiver, new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)); + context.registerReceiver(bluetoothBroadcastReceiver, new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)); + context.registerReceiver(bluetoothBroadcastReceiver, new IntentFilter(android.media.AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)); + } + + volumeSettingChangedListener = new VolumeSettingChangedListener(new Handler(), audioDeviceConnectionManager); + context.getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, volumeSettingChangedListener); + } catch (Throwable t) { + Ln.e(t); + } + } + + public void unregister() { + Ln.d("unregisterMediaDevice"); + audioDeviceConnectionManager.abandonAudioFocus(); + proximitySensor.onPause(); + + // unregister for headset notifications + if (headsetIntentReceiver != null) { + context.unregisterReceiver(headsetIntentReceiver); + headsetIntentReceiver = null; + } + + bluetoothServiceListener = null; + try { + context.unregisterReceiver(bluetoothBroadcastReceiver); + } catch (IllegalArgumentException ignored) { + } + if (volumeSettingChangedListener != null) { + context.getContentResolver().unregisterContentObserver(volumeSettingChangedListener); + volumeSettingChangedListener = null; + } + if (audioDeviceConnectionManager != null) { + audioDeviceConnectionManager.uninitialize(); + } + } + + public DeviceManager.MediaDevice getCamera(WMEngine.Camera camera) { + return deviceManager.getCamera(camera.toDeviceCamera()); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/ProximitySensor.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/ProximitySensor.java new file mode 100644 index 00000000..b256d310 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/ProximitySensor.java @@ -0,0 +1,250 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media.device; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.os.PowerManager; +import android.os.SystemClock; +import com.github.benoitdion.ln.Ln; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicBoolean; + +public class ProximitySensor implements SensorEventListener { + + public interface Listener { + + enum ProximityEvent { + NEAR, FAR + } + + void onEvent(ProximityEvent event); + + } + + private static final String WAKELOCK_TAG = "androidsdk:ProximitySensorLock"; + private static final String EVENT_TIMER_TAG = "Proximity event timer"; + private static final long DEFAULT_SENSITIVITY_MSEC = 1500; + private static final long SENSITIVITY_TIMER_MINIMUM = 10; + private static int wakeLockType = PowerManager.PARTIAL_WAKE_LOCK; + + private Sensor proximitySensor; + private PowerManager powerManager; + private PowerManager.WakeLock wakeLock; + private boolean hasProximitySensor; + private final Context context; + private SensorManagerDelegate sensorManager; + private long sensitivity; + private Timer sensitivityTimer; + private TimerTask sensitivityTimerTask; + private AtomicBoolean nearEventScheduled = new AtomicBoolean(false); + private long firstProximityChangedEvent; + private Listener listener; + + public ProximitySensor(Context context, Listener listener) { + this(context, DEFAULT_SENSITIVITY_MSEC, listener); + } + + public ProximitySensor(Context context, long sensitivity, Listener listener) { + this.context = context; + this.sensorManager = new SensorManagerDelegate(context); + this.listener = listener; + setSensitivity(sensitivity); + firstProximityChangedEvent = 0; + powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + hasProximitySensor = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_PROXIMITY); + Ln.d("System reports %s a proximity sensor", hasProximitySensor ? "having" : "not having"); + if (hasProximitySensor) { + if (sensorManager != null) { + proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); + if (proximitySensor == null) { + Ln.w("Failed to get ProximitySensor"); + } + } + else { + Ln.w("Failed to get SensorManager"); + } + + try { + // Documentation says PARTIAL_WAKE_LOCK level 'should' give us a WakeLock that controls the screen, but doesn't. + // So using the previously exposed, but now hidden level of PROXIMITY_SCREEN_OFF_WAKE_LOCK, which works well. + wakeLockType = PowerManager.class.getField("PROXIMITY_SCREEN_OFF_WAKE_LOCK").getInt(null); + } catch (Throwable ignored) { + Ln.w("Unable to get PROXIMITY_SCREEN_OFF_WAKE_LOCK level for newWakeLock. Using default: PARTIAL_WAKE_LOCK"); + } + } + } + + public boolean isProximityAvailable() { + return hasProximitySensor; + } + + public void setSensitivity(long value) { + sensitivity = value > 0 ? value : 0; + // if sensitivity is below minimum, then timers won't be used and 'scheduled' should always be true + if (sensitivity < SENSITIVITY_TIMER_MINIMUM) + nearEventScheduled.set(true); + } + + public void onResume() { + Ln.d("ProximitySensor.onResume, sensorManager = " + sensorManager + ", proximitySensor = " + proximitySensor); + if (hasProximitySensor && sensorManager != null && proximitySensor != null) { + Ln.d("Registering listener for proximity sensor with sensitivity=%d", sensitivity); + sensorManager.registerListener(this, proximitySensor, android.hardware.SensorManager.SENSOR_DELAY_NORMAL); + acquireScreenLock(); + } + } + + public void onPause() { + if (hasProximitySensor && sensorManager != null && proximitySensor != null) { + Ln.d("Un-registering listener for proximity sensor"); + sensorManager.unregisterListener(this); + releaseScreenLock(); + } + } + + public void disableScreen() { + // There's a small window where a NEAR event can get posted on the bus, before a canceling + // FAR event can catch and remove it. The synchronized check of nearEventScheduled closes that. + if (wakeLock != null && !wakeLock.isHeld() && nearEventScheduled.get()) { + Ln.i("Disabling screen!"); + wakeLock.acquire(); + } + } + + public void enableScreen() { + if (wakeLock != null && wakeLock.isHeld()) { + Ln.i("Enabling screen"); + wakeLock.release(); + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + Ln.d("onAccuracyChanged: sensor=%s, accuracy=%d", sensor.getName(), accuracy); + } + + @Override + public void onSensorChanged(SensorEvent event) { + float eventValue = event.values[0]; + Ln.i("onSensorChanged: type=%d, value[0]=%f", event.sensor.getType(), eventValue); + + /* + * Work around defective proximity sensors by ignoring a proximity sensor that + * immediately reports that an object is close and never reports that it goes + * away. + */ + long time = SystemClock.currentThreadTimeMillis(); + if (firstProximityChangedEvent == 0) { + firstProximityChangedEvent = time; + } + else if (eventValue == 0 && time - firstProximityChangedEvent < 500) { + Ln.w("Ignoring an immediate NEAR proximity event, which often indicates a faulty sensor!"); + return; + } + if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) { + if (eventValue < proximitySensor.getMaximumRange()) { + handleNearEvent(); + } + else { + handleFarEvent(); + } + } + } + + private void acquireScreenLock() { + wakeLock = powerManager.newWakeLock(wakeLockType, WAKELOCK_TAG); + if (wakeLock == null) { + Ln.w("Failed to get WakeLock for screen control"); + } + } + + private void releaseScreenLock() { + enableScreen(); + wakeLock = null; + } + + public boolean isWakeLockHeld() { + Ln.d("isWakeLockHeld: %s", wakeLock.isHeld() ? "true" : "false"); + return wakeLock.isHeld(); + } + + private void handleNearEvent() { + if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + Ln.i("ignore proximity sensor (NEAR event) while in landscape mode"); + return; + } + else if (isTablet(context)) { + Ln.i("ignore proximity sensor (NEAR event) on non-phone (tablet) device"); + return; + } + + if (sensitivity >= SENSITIVITY_TIMER_MINIMUM) { + // if a sensitivity is configure and we don't have a pending event, post a delayed event + if (!nearEventScheduled.get()) { + sensitivityTimer = new Timer(EVENT_TIMER_TAG); + sensitivityTimerTask = new TimerTask() { + @Override + public void run() { + Ln.d("posting proximity NEAR event"); + listener.onEvent(Listener.ProximityEvent.NEAR); + nearEventScheduled.set(false); + } + }; + sensitivityTimer.schedule(sensitivityTimerTask, sensitivity); + nearEventScheduled.set(true); + } + return; + } + Ln.d("posting proximity NEAR event"); + listener.onEvent(Listener.ProximityEvent.NEAR); + } + + private void handleFarEvent() { + if (isTablet(context)) { + Ln.i("ignore proximity sensor (FAR event) on non-phone (tablet) device"); + return; + } + + if (sensitivity >= SENSITIVITY_TIMER_MINIMUM) { + if (nearEventScheduled.getAndSet(false)) { + Ln.d("FAR event occurred before NEAR timer task executed--cancelling NEAR event"); + sensitivityTimerTask.cancel(); + sensitivityTimer.cancel(); + return; + } + } + Ln.d("posting proximity FAR event"); + listener.onEvent(Listener.ProximityEvent.FAR); + } + + private static boolean isTablet(Context context) { + return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/SensorManagerDelegate.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/SensorManagerDelegate.java new file mode 100644 index 00000000..7c26d7e3 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/SensorManagerDelegate.java @@ -0,0 +1,50 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media.device; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; + +public class SensorManagerDelegate { + + private final SensorManager delegate; + + public SensorManagerDelegate(Context context) { + delegate = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + } + + public Sensor getDefaultSensor(int type) { + return delegate.getDefaultSensor(type); + } + + public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) { + return delegate.registerListener(listener, sensor, rate); + } + + public void unregisterListener(SensorEventListener listener) { + delegate.unregisterListener(listener); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/VolumeSettingChangedListener.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/VolumeSettingChangedListener.java new file mode 100644 index 00000000..4ca92397 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/media/device/VolumeSettingChangedListener.java @@ -0,0 +1,53 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.media.device; + +import android.database.ContentObserver; +import android.os.Handler; +import com.github.benoitdion.ln.Ln; + +public class VolumeSettingChangedListener extends ContentObserver { + + private AudioDeviceConnectionManager audioDeviceConnectionManager; + + public VolumeSettingChangedListener(Handler handler, AudioDeviceConnectionManager manager) { + super(handler); + this.audioDeviceConnectionManager = manager; + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + logCurrentVolumeInfo("VolumeChange", audioDeviceConnectionManager.getAudioManager()); + audioDeviceConnectionManager.updateAudioVolume(); + } + + private static void logCurrentVolumeInfo(String tag, AudioManagerDelegate audioManager) { + if (audioManager != null) { + Ln.d(String.format("%s.VoiceCall Volume : %s(%s)", tag, audioManager.getStreamVolume(android.media.AudioManager.STREAM_VOICE_CALL), audioManager.getStreamMaxVolume(android.media.AudioManager.STREAM_VOICE_CALL))); + Ln.d(String.format("%s.System Volume : %s(%s)", tag, audioManager.getStreamVolume(android.media.AudioManager.STREAM_SYSTEM), audioManager.getStreamMaxVolume(android.media.AudioManager.STREAM_SYSTEM))); + Ln.d(String.format("%s.Music Volume : %s(%s)", tag, audioManager.getStreamVolume(android.media.AudioManager.STREAM_MUSIC), audioManager.getStreamMaxVolume(android.media.AudioManager.STREAM_MUSIC))); + Ln.d(String.format("%s.Bluetooth Volume : %s(%s)", tag, audioManager.getStreamVolume(AudioDeviceConnectionManager.STREAM_BLUETOOTH_SCO), audioManager.getStreamMaxVolume(AudioDeviceConnectionManager.STREAM_BLUETOOTH_SCO))); + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryActivityEvent.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryActivityEvent.java new file mode 100644 index 00000000..347b10a6 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryActivityEvent.java @@ -0,0 +1,56 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.mercury; + +import com.ciscowebex.androidsdk.internal.model.ActivityModel; +import com.ciscowebex.androidsdk.internal.model.ConversationModel; + +public class MercuryActivityEvent extends MercuryEvent { + + private ActivityModel activity; + + public ActivityModel getActivity() { + return this.activity; + } + + public String toString() { + return "Event: " + this.activity.toString(); + } + + public void patch(MercuryEnvelope.Headers headers) { + if (this.activity.getTarget() != null && this.activity.getTarget() instanceof ConversationModel) { + ConversationModel target = (ConversationModel) this.activity.getTarget(); + if (headers != null) { + target.setLastReadableActivityDate(headers.getLastReadableActivityDate()); + target.setLastRelevantActivityDate(headers.getLastRelevantActivityDate()); + target.setLastSeenActivityDate(headers.getLastSeenActivityDate()); + } else { + target.setLastReadableActivityDate(null); + target.setLastRelevantActivityDate(null); + target.setLastSeenActivityDate(null); + } + + } + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryEnvelope.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryEnvelope.java new file mode 100644 index 00000000..32e0402e --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryEnvelope.java @@ -0,0 +1,120 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.mercury; + +import android.text.TextUtils; +import com.google.gson.annotations.SerializedName; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class MercuryEnvelope { + + public static class Recipient { + + private String alertType; + private String route; + + public String getRoute() { + return route; + } + } + + private static final String ROUTE_PREFIX = "board."; + + private String id; + private String type; + private MercuryEvent data; + private Boolean isDeliveryEscalation; + private Headers headers; + private boolean filterMessage; + private List recipients; + + public MercuryEnvelope() { + recipients = new ArrayList<>(); + } + + public String getId() { + return id; + } + + public String getType() { + return type; + } + + public MercuryEvent getData() { + return data; + } + + public boolean isDeliveryEscalation() { + return isDeliveryEscalation == null ? false : isDeliveryEscalation; + } + + public Headers getHeaders() { + return headers; + } + + public List getRecipients() { + return recipients; + } + + public static class Headers { + + @SerializedName("data.activity.target.lastReadableActivityDate") + private Date lastReadableActivityDate; + + @SerializedName("data.activity.target.getLastSeenActivityDate") + private Date lastSeenActivityDate; + + @SerializedName("data.activity.target.lastRelevantActivityDate") + private Date lastRelevantActivityDate; + + private String route; + + public String getChannelId() { + return getChannelIdFromRoute(route); + } + + private String getChannelIdFromRoute(String route) { + if (!TextUtils.isEmpty(this.route) && this.route.startsWith(ROUTE_PREFIX)) { + route = this.route.substring(ROUTE_PREFIX.length()); + if (!TextUtils.isEmpty(route)) { + route = route.replace(".", "-"); + } + } + return route; + } + + public Date getLastReadableActivityDate() { + return lastReadableActivityDate; + } + + public Date getLastSeenActivityDate() { + return lastSeenActivityDate; + } + public Date getLastRelevantActivityDate() { + return lastRelevantActivityDate; + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryEvent.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryEvent.java new file mode 100644 index 00000000..11a4222d --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryEvent.java @@ -0,0 +1,119 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.mercury; + +public abstract class MercuryEvent { + + public enum Type { + CONVERSATION_ACTIVITY("conversation.activity"), + KEY_PUSH("encryption.client_encrypt_keys"), + KMS_ACK("encryption.kms_ack"), + KMS_MESSAGE("encryption.kms_message"), + CONVERSATION_BADGE_COUNT("conversation.badge_count"), + LOCUS_PARTICIPANT_JOINED("locus.participant_joined"), + LOCUS_PARTICIPANT_LEFT("locus.participant_left"), + LOCUS_PARTICIPANT_DECLINED("locus.participant_declined"), + LOCUS_PARTICIPANT_ALERTED("locus.participant_alerted"), + LOCUS_PARTICIPANT_AUDIO_MUTED("locus.participant_audio_muted"), + LOCUS_PARTICIPANT_AUDIO_UNMUTED("locus.participant_audio_unmuted"), + LOCUS_PARTICIPANT_VIDEO_MUTED("locus.participant_video_muted"), + LOCUS_PARTICIPANT_VIDEO_UNMUTED("locus.participant_video_unmuted"), + LOCUS_PARTICIPANT_UPDATED("locus.participant_updated"), + LOCUS_SELF_CHANGED("locus.self_changed"), + LOCUS_FLOOR_GRANTED("locus.floor_granted"), + LOCUS_FLOOR_RELEASED("locus.floor_released"), + LOCUS_PARTICIPANT_BROADCAST("locus.participant_broadcast"), + LOCUS_PARTICIPANT_CONTROLS_UPDATED("locus.participant_controls_updated"), + LOCUS_UPDATED("locus.updated"), + LOCUS_CONTROLS_UPDATED("locus.controls_updated"), + LOCUS_DIFFERENCE("locus.difference"), + LOCUS_ROAP_MESSAGE("locus.message.roap"), + LOCUS_PARTICIPANT_ROLES_UPDATED("locus.participant_roles_updated"), + LYRA_COMMAND("lyra.command_invoke"), + PONG("pong"), + START_TYPING("status.start_typing"), + STOP_TYPING("status.stop_typing"), + BOARD_ACTIVITY("board.activity"), + ROOM_UPDATED_EVENT("room.room_updated"), + ROOM_DEVICE_ENTERED_EVENT("room.device_entered"), + LYRA_SPACE_AUDIO_VOLUME_CHANGE("lyra.space_audio_volume_change_action"), + LYRA_SPACE_AUDIO_VOLUME_SET("lyra.space_audio_volume_set_action"), + LYRA_SPACE_AUDIO_MICROPHONES_MUTE("lyra.space_audio_microphones_mute_action"), + ROOM_DEVICE_EXITED_EVENT("room.device_exited"), + ROOM_CONTROL("room.control"), + ROOM_BRING_ROOM_INTO_CALL("room.bring_room_into_call"), + ROOM_REQUEST_LOGS("room.request_logs"), + ROOM_SET_UPGRADE_CHANNEL("room.setUpgradeChannel"), + ROOM_RENEW_RSU("room.renewRSU"), + ROOM_SET_ROOM_CONTROL_USER("room.set_room_control_user"), + ROOM_IDENTITY_CHANGED("room.identityDataChanged"), + ROOM_IDENTITY_DELETED("room.identityDeleted"), + ROOM_PSTN_CHANGED("room.pstnChanged"), + JANUS_USER_SESSIONS("janus.user_sessions"), + PRESENCE_SUBSCRIPTION_UPDATE("apheleia.subscription_update"), + USER_APP_ITEM("user.app_item"), + LYRA_SPACE_UPDATE_EVENT("lyra.space_updated"), + MERCURY_REGISTRATION_STATUS("mercury.registration_status"), + VOICEMAIL_INFO("voicemail.info"), + CALENDAR_MEETING_CREATE("calendar.meeting.create"), + CALENDAR_MEETING_CREATE_MINIMAL("calendar.meeting.create.minimal"), + CALENDAR_MEETING_UPDATE("calendar.meeting.update"), + CALENDAR_MEETING_UPDATE_MINIMAL("calendar.meeting.update.minimal"), + CALENDAR_MEETING_DELETE("calendar.meeting.delete"), + FEATURE_TOGGLE_UPDATE("featureToggle_update"); + + private final String phrase; + + Type(String phrase) { + this.phrase = phrase; + } + + public static Type fromString(String type) { + if (type != null) { + for (Type eventType : Type.values()) { + if (type.equalsIgnoreCase(eventType.phrase)) { + return eventType; + } + } + } + return null; + } + + public String phrase() { + return this.phrase; + } + + @Override + public String toString() { + return phrase; + } + } + + private Type eventType; + + public Type getEventType() { + return eventType; + } + + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsAckEvent.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsAckEvent.java new file mode 100644 index 00000000..686ab636 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsAckEvent.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.mercury; + +public class MercuryKmsAckEvent extends MercuryEvent { + + private String requestId = null; + private int statusCode = 0; + private String failureReason = ""; + + public String getRequestId() { + return requestId; + } + + public int getStatusCode() { + return statusCode; + } + + public String getFailureReason() { + return failureReason; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsMessageEvent.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsMessageEvent.java new file mode 100644 index 00000000..f7b131a3 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsMessageEvent.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.mercury; + +import com.ciscowebex.androidsdk.internal.model.KmsMessageModel; + +public class MercuryKmsMessageEvent extends MercuryEvent { + + private int statusCode; + private KmsMessageModel encryption; + + public int getStatusCode() { + return statusCode; + } + + public KmsMessageModel getEncryptionKmsMessage() { + return encryption; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsPushEvent.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsPushEvent.java new file mode 100644 index 00000000..7af9734a --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryKmsPushEvent.java @@ -0,0 +1,51 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.mercury; + +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; + +import java.util.List; + +public class MercuryKmsPushEvent extends MercuryEvent { + + private String requestId; + private List keys = null; + private int statusCode = 0; + private String failureReason = null; + + public String getRequestId() { + return requestId; + } + + public List getKeys() { + return this.keys; + } + + public int getStatusCode() { + return this.statusCode; + } + + public String getFailureReason() { + return this.failureReason; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryLocusEvent.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryLocusEvent.java new file mode 100644 index 00000000..1b6f604f --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryLocusEvent.java @@ -0,0 +1,49 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.mercury; + +import com.ciscowebex.androidsdk.internal.model.LocusKeyModel; +import com.ciscowebex.androidsdk.internal.model.LocusModel; +import com.google.gson.annotations.SerializedName; + +import java.util.UUID; + +public class MercuryLocusEvent extends MercuryEvent { + + private UUID id; + @SerializedName("locusUrl") + private LocusKeyModel locusKey; + private LocusModel locus; + + public UUID getId() { + return id; + } + + public LocusKeyModel getLocusKey() { + return locusKey; + } + + public LocusModel getLocus() { + return locus; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryService.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryService.java new file mode 100644 index 00000000..4e30c367 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryService.java @@ -0,0 +1,310 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.mercury; + +import android.os.Handler; +import android.os.Looper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.ciscowebex.androidsdk.WebexError; +import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.queue.BackgroundQueue; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.utils.Json; +import com.ciscowebex.androidsdk.utils.Utils; +import com.ciscowebex.androidsdk.utils.http.HttpClient; +import com.github.benoitdion.ln.Ln; +import com.google.gson.*; +import me.helloworld.utils.Checker; +import okhttp3.*; +import okio.ByteString; + +import java.util.Locale; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; + +public class MercuryService { + + public interface MecuryListener { + void onConnected(@Nullable WebexError error); + void onDisconnected(@Nullable WebexError error); + void onEvent(@NonNull MercuryEvent event); + } + + private static final int[] RETRY_DELAY = new int[] { 1, 4, 16, 60, 120 }; + private AtomicInteger failureCount = new AtomicInteger(0); + + private Queue queue = new BackgroundQueue(); + + private String url; + private WebSocket websocket; + private boolean connected = false; + + private Authenticator authenticator; + private OkHttpClient client = HttpClient.makeClient(); + private MercuryWebsocketListener websocketListener = new MercuryWebsocketListener(); + private MecuryListener mecuryListener; + private Closure onConnected; + + private Handler worker = new Handler(Looper.getMainLooper()); + private Runnable reconnectWork = () -> queue.run(new Runnable() { + @Override + public void run() { + Ln.d("Mercury try to re-connect."); + if (url != null && !connected) { + authenticator.getToken( token -> { + Ln.d("Websocket reconnecting: " + url); + Request request = new Request.Builder().url(url).header("Authorization", "Bearer " + token.getData()).build(); + client.dispatcher().cancelAll(); + websocket = client.newWebSocket(request, websocketListener); + }); + } + } + }); + + public MercuryService(Authenticator authenticator, MecuryListener listener) { + this.authenticator = authenticator; + this.mecuryListener = listener; + } + + public void connect(String url, Closure closure) { + queue.run(() -> { + if (websocket != null && connected) { + Ln.w("Web socket has already connected"); + closure.invoke(null); + return; + } + websocket = null; + this.url = url; + authenticator.getToken (token -> { + Ln.d("Websocket connecting: " + url); + Request request = new Request.Builder().url(url).header("Authorization", "Bearer " + token.getData()).build(); + client.dispatcher().cancelAll(); + onConnected = closure; + websocket = client.newWebSocket(request, websocketListener); + }); + }); + } + + public void disconnect() { + queue.run(() -> { + connected = false; + resetReconnect(); + if (client != null) { + client.dispatcher().cancelAll(); + } + if (websocket != null) { + if (!websocket.close(WebSocketStatusCodes.CLOSE_NORMAL.getCode(), "Websocket Stopping")) { + Ln.d("Stop mecury websocket abnormal"); + } + websocket = null; + } + }); + } + + public void tryReconnect() { + queue.run(reconnectWork); + } + + private void onMercuryDisconnected(WebexError error) { + queue.run(() -> { + connected = false; + if (onConnected != null) { + WebexError e = error == null ? WebexError.from("Websocket cannot connect") : error; + Ln.d("Websocket cannot connect: " + e); + onConnected.invoke(e); + if (mecuryListener != null) { + mecuryListener.onConnected(e); + } + onConnected = null; + } + else if (error != null) { + Ln.d("Websocket is disconnected: " + error); + if (websocket == null || error.getErrorCode() == WebSocketStatusCodes.CLOSE_NORMAL.getCode()) { + Ln.d("Websocket is disconnected on purpose"); + if (mecuryListener != null) { + mecuryListener.onDisconnected(null); + } + } + else { + int failureCount = this.failureCount.getAndAdd(1); + int retryIndex = failureCount < RETRY_DELAY.length ? failureCount : RETRY_DELAY.length - 1; + int delay = RETRY_DELAY[retryIndex] + new Random().nextInt(10); + Ln.d("Connection closed, reset to try again in %d seconds", delay); + worker.postDelayed(reconnectWork, delay * 1000); + } + } + }); + } + + private void resetReconnect() { + worker.removeCallbacks(reconnectWork); + failureCount.set(0); + } + + private class MercuryWebsocketListener extends WebSocketListener { + + private String trackingId; + + @Override + public void onOpen(WebSocket webSocket, Response response) { + trackingId = response.header("TrackingID"); + Ln.i("Mercury connection opened. handshake: %s - %s TrackingId: %s", response.code(), response.message(), trackingId); + queue.run(() -> { + connected = true; + if (onConnected != null) { + onConnected.invoke(null); + onConnected = null; + } + if (mecuryListener != null) { + mecuryListener.onConnected(null); + } + resetReconnect(); + }); + } + + @Override + public void onClosing(WebSocket webSocket, int code, String reason) { + Ln.i("Connection closing. Reason: \"%s\", code: %d (%s), TrackingId: %s", reason, code, WebSocketStatusCodes.valueForCode(code).name(), trackingId); + } + + @Override + public void onClosed(WebSocket webSocket, int rawCode, String reason) { + WebSocketStatusCodes code = WebSocketStatusCodes.valueForCode(rawCode); + Ln.i("Connection closed. Reason: \"%s\", code: %d (%s), TrackingId: %s", reason, rawCode, code.name(), trackingId); + onMercuryDisconnected(new WebexError(rawCode, reason)); + } + + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + Ln.e("Connection failure. Reason: %s, code: %s, Tracking ID: %s", t.getMessage(), response != null ? response.code() : null, trackingId); + onMercuryDisconnected(WebexError.from(t)); + } + + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + onMessage(webSocket, new String(bytes.toByteArray())); + } + + @Override + public void onMessage(WebSocket webSocket, String message) { + if (Ln.isDebugEnabled()) { + if (message != null && message.length() > 4000) { + String[] chunks = Utils.chunk(message, 1024); + for (String chunk : chunks) { + Ln.d("[WS]" + chunk); + } + } else { + Ln.d("[WS]" + message); + } + } + failureCount.set(0); + if (!ackMessage(webSocket, message)) { + return; + } + MercuryEnvelope envelope = Json.fromJson(message, MercuryEnvelope.class); + if (envelope == null) { + Ln.w("Message parse error: %s", message); + return; + } + MercuryEvent event = envelope.getData(); + if (event != null && !Checker.isEmpty(event.getEventType().toString())) { + if (event instanceof MercuryActivityEvent) { + ((MercuryActivityEvent) event).patch(envelope.getHeaders()); + } + if (mecuryListener != null) { + mecuryListener.onEvent(event); + } + } else { + Ln.w("Invalid message envelope."); + } + } + + private boolean ackMessage(final WebSocket socket, final String message) { + try { + final JsonObject envelopeObj = new JsonParser().parse(message).getAsJsonObject(); + final JsonElement idElem = envelopeObj.get("id"); + if (idElem == null) { + Ln.w("Incoming Mercury message didn't have id, ignoring"); + return false; + } + final String id = idElem.getAsString(); + socket.send(Json.get().toJson(new AckMessage(id))); + } catch (final JsonParseException | IllegalStateException | ClassCastException e) { + Ln.w("Unable to parse id from Mercury message, ignoring: %s", e.getMessage()); + return false; + } + return true; + } + } + + public enum WebSocketStatusCodes { + CLOSE_NORMAL(1000), + CLOSE_GOING_AWAY(1001), + CLOSE_PROTOCOL_ERROR(1002), + CLOSE_UNSUPORTED(1003), + CLOSE_NO_STATUS(1005), + CLOSE_ABNORMAL(1006), + CLOSE_INCONSISTANT_DATA(1007), + CLOSE_POLICY_VIOLATED(1008), + CLOSE_TO_LARGE(1009), + CLOSE_EXTENSION_NEGOTIATION(1010), + CLOSE_REQUEST_UNFULLABLE(1011), + CLOSE_UNKNOWN(0), + CLOSE_LOCAL_ERROR(-1), + CLOSE_REPLACED(4000); + + private int code; + + WebSocketStatusCodes(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + + public static WebSocketStatusCodes valueForCode(int code) { + for (WebSocketStatusCodes value : WebSocketStatusCodes.values()) { + if (value.getCode() == code) { + return value; + } + } + return CLOSE_UNKNOWN; + } + } + + public static class AckMessage { + private final String type; + private final String messageId; + + public AckMessage(String messageId) { + this.type = "ack"; + this.messageId = messageId; + } + public String toString() { + return String.format(Locale.US, "{ \"type\": \"%s\", \"messageId\": \"%s\" }", type, messageId); + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryTypingEvent.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryTypingEvent.java new file mode 100644 index 00000000..b9d106f3 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryTypingEvent.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.mercury; + +import com.ciscowebex.androidsdk.internal.model.PersonModel; + +public class MercuryTypingEvent extends MercuryEvent { + + private String conversationId; + private PersonModel actor; + + public String getConversationId() { + return conversationId; + } + + public PersonModel getActor() { + return actor; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ActivityModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ActivityModel.java new file mode 100644 index 00000000..881853c6 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ActivityModel.java @@ -0,0 +1,319 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.support.annotation.NonNull; +import com.ciscowebex.androidsdk.internal.Credentials; +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; +import me.helloworld.utils.Checker; + +import java.util.Comparator; + +public class ActivityModel extends ObjectModel { + + public enum Verb { + create, add, remove, post, acknowledge, update, updateKey, leave, + mute, unmute, favorite, unfavorite, share, start, join, decline, reject, + cancel, terminate, schedule, hide, unhide, lock, unlock, assignModerator, unassignModerator, + delete, tombstone, archive, unarchive, + tag, untag, assign, unassign, noops, + addMicroappInstance, deleteMicroappInstance, set, unset + } + + private ObjectModel target; + private ObjectModel object; + private PersonModel actor; + private ProviderModel provider; + private Verb verb; + private PlaceModel location; + private String encryptionKeyUrl; + private ParentModel parent; + + private transient boolean isEncrypted; + + public static final Comparator ASCENDING_PUBLISH_TIME_COMPARATOR = (rhs, lhs) -> { + int result = rhs.getPublished().compareTo(lhs.getPublished()); + if (result == 0 && lhs.getVerb() == Verb.acknowledge) { + return -1; + } else if (result == 0 && rhs.getVerb() == Verb.acknowledge) { + return 1; + } + return result; + }; + + public static final Comparator DESCENDING_PUBLISH_TIME_COMPARATOR = (rhs, lhs) -> ASCENDING_PUBLISH_TIME_COMPARATOR.compare(lhs, rhs); + + public ActivityModel(String type) { + super(Type.activity); + } + + public ParentModel getParent() { + return parent; + } + + public boolean isReply() { + return parent != null && parent.isReply(); + } + + public ObjectModel getTarget() { + return target; + } + + public ObjectModel getObject() { + return object; + } + + public PersonModel getActor() { + return actor; + } + + public Verb getVerb() { + return verb; + } + + public ProviderModel getProvider() { + return provider; + } + + public PlaceModel getLocation() { + return location; + } + + public String getEncryptionKeyUrl() { + return encryptionKeyUrl; + } + + public boolean isFromSelf(@NonNull String personId) { + PersonModel person = getActor(); + return person != null && personId.equals(person.getId()); + } + + public boolean isAddParticipant() { + return verb == Verb.add && object != null && object.isPerson() && target != null && target.isConversation(); + } + + public boolean isCreateConversation() { + return verb == Verb.create && object != null && object.isConversation(); + } + + public boolean isTag() { + return verb == Verb.tag && object != null && object.isConversation(); + } + + public boolean isUnTag() { + return verb == Verb.untag && object != null && object.isConversation(); + } + + public boolean isPostOrAddComment() { + return (verb == Verb.post || verb == Verb.add) + && object != null && object.isComment() + && target != null && target.isConversation(); + } + + public boolean isPostOrShareContent() { + return (verb == Verb.post || verb == Verb.share) + && object != null && object.isContent() + && target != null && target.isConversation(); + } + + public boolean isShareFile() { + return verb == Verb.share && object instanceof ContentModel && (((ContentModel) object).isFile() || ((ContentModel) object).isVideo()); + } + + public boolean isShareImage() { + return verb == Verb.share && object instanceof ContentModel && ((ContentModel) object).isImage(); + } + + public boolean isUpdateTitleAndSummaryActivity() { + return verb == Verb.update && object != null && object.isConversation(); + } + + public boolean isSetTeamColor() { + return verb == Verb.update && object != null && object.isTeamObject(); + } + + public boolean isMoveRoomToTeam() { + return verb == Verb.add && object != null && object.isConversation(); + } + + public boolean isRemoveRoomFromTeam() { + return verb == Verb.remove && object != null && object.isConversation(); + } + + public boolean isLocusActivity() { + return object != null && object.isLocus(); + } + + public boolean isLeaveActivity() { + return verb == Verb.leave && (object == null || object.isPerson()) && target != null && target.isConversation(); + } + + public boolean isUpdateContent() { + return verb == Verb.update && object != null && object.isContent(); + } + + public boolean isUpdateKeyActivity() { + return verb == Verb.updateKey && object != null && object.isConversation(); + } + + public boolean isSetAnnouncement() { + return verb == Verb.set && object != null && object.isSpaceProperty() && ((SpacePropertyModel) object).containsTag(SpacePropertyModel.Tag.ANNOUNCEMENT); + } + + public boolean isUnsetAnnouncement() { + return verb == Verb.unset && object != null && object.isSpaceProperty() && ((SpacePropertyModel) object).containsTag(SpacePropertyModel.Tag.ANNOUNCEMENT); + } + + public boolean isAssignRoomAvatar() { + return verb == Verb.assign && object != null && object.isContent(); + } + + public boolean isUnassignRoomAvatar() { + return verb == Verb.unassign && object != null && object.isContent(); + } + + public boolean isLocusSessionSummary() { + return verb == Verb.update + && object != null + && object.isLocusSessionSummary() + && target.getId() != null; + } + + public boolean isAddNewTeamConversation() { + return verb == Verb.add + && object != null && object.isConversation() + && target != null && (target.isConversation() || target.isTeamObject()); + } + + public String getContentDataId() { + if (object != null && object.isContent()) { + return getObject().getId(); + } + return null; + } + + public String getSparkMeetingId() { + if (object != null && object.isEvent()) { + return getObject().getId(); + } + return null; + } + + public String getConversationId() { + ObjectModel target = getTarget(); + ObjectModel object = getObject(); + if (target != null && ObjectModel.Type.conversation.equals(target.getObjectType())) { + return target.getId(); + } else if (target != null && ObjectModel.Type.team.equals(target.getObjectType())) { + return ((TeamModel) target).getGeneralConversationUuid(); + } else if (object != null && ObjectModel.Type.conversation.equals(object.getObjectType())) { + return object.getId(); + } else if (object != null && ObjectModel.Type.team.equals(object.getObjectType())) { + return ((TeamModel) object).getGeneralConversationUuid(); + } else { + return null; + } + } + + @Override + public String toString() { + return "Activity " + getId() + " " + getVerb() + + " target{" + getTarget() + + "} object{" + getObject() + + "} actor:" + getActor() + + " published:" + (getPublished() == null ? "0" : String.valueOf(getPublished().getTime())); + } + + @Override + public void encrypt(KeyObject key) { + if (key == null) { + return; + } + super.encrypt(key); + if (getObject() != null) { + getObject().encrypt(key); + } + if (getTarget() != null) { + getTarget().setDisplayName(null); + } + } + + @Override + public void decrypt(KeyObject key) { + if (key == null) { + return; + } + super.decrypt(key); + if (getObject() != null) { + getObject().decrypt(key); + } + } + + // Returns the publish time of the activity, or of the acknowledged activity if this is an ack + public long getAckTime() { + long ret = getPublished().getTime(); + if (verb == Verb.acknowledge && getObject() != null && getObject().getPublished().getTime() != 0) { + ret = getObject().getPublished().getTime(); + } + return ret; + } + + public boolean isSelfMention(@NonNull Credentials credentials, long lastJoinedDate) { + return isPersonallyMentioned(credentials) || isIncludedInGroupMention(credentials, lastJoinedDate); + } + + private boolean isPersonallyMentioned(@NonNull Credentials user) { + if (!(getObject() instanceof MentionableModel)) { + return false; + } + MentionableModel object = (MentionableModel) getObject(); + if (object.getMentions() == null) { + return false; + } + for (PersonModel mention : object.getMentions().getItems()) { + if (Checker.isEqual(mention.getId(), user.getUserId())) { + return true; + } + } + return false; + } + + private boolean isIncludedInGroupMention(@NonNull Credentials credentials, long lastJoinedDate) { + if (!(getObject() instanceof MentionableModel)) { + return false; + } + MentionableModel object = (MentionableModel) getObject(); + if (object.getGroupMentions() == null || object.getGroupMentions().size() == 0) { + return false; + } + for (GroupMentionModel mention : object.getGroupMentions().getItems()) { + // @All and @Here mentions apply to a user if the publish time on the activity is after the lastJoinedDate for the conversation + if ((mention.getGroupType() == GroupMentionModel.Type.ALL || mention.getGroupType() == GroupMentionModel.Type.HERE) && + !isFromSelf(credentials.getUserId()) && + getPublished().getTime() >= lastJoinedDate) { + return true; + } + } + return false; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/AlertTypeModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/AlertTypeModel.java new file mode 100644 index 00000000..6dd5fdc2 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/AlertTypeModel.java @@ -0,0 +1,45 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.Date; + +public class AlertTypeModel { + public final static String ALERT_NONE = "NONE"; // No Alert or stop alerting + public final static String ALERT_FULL = "FULL"; // Audible and visual alert + public final static String ALERT_VISUAL = "VISUAL"; // Visual only alert + + private String action; + private Date expiration; + + public AlertTypeModel() { } + + public String getAction() { + return action; + } + + public Date getExpiration() { + return expiration; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/CalliopeClusterModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/CalliopeClusterModel.java new file mode 100644 index 00000000..12b54033 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/CalliopeClusterModel.java @@ -0,0 +1,14 @@ +package com.ciscowebex.androidsdk.internal.model; + +import java.util.List; +import java.util.Map; + +public class CalliopeClusterModel { + + private Map>> clusters; + + public Map>> getClusterInfo() { + return clusters; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/CommentModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/CommentModel.java new file mode 100644 index 00000000..a3baee12 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/CommentModel.java @@ -0,0 +1,95 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.ciscowebex.androidsdk.internal.crypto.CryptoUtils; +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; +import me.helloworld.utils.Checker; + +public class CommentModel extends ObjectModel implements MentionableModel, MarkdownableModel { + + private ItemsModel mentions; + private ItemsModel groupMentions; + private String markdown; + + public CommentModel() { + super(ObjectModel.Type.comment); + } + + public CommentModel(String message) { + this(); + setDisplayName(message); + } + + public String getMarkdown() { + return markdown; + } + + public void setMarkdown(String markdown) { + this.markdown = markdown; + } + + @Override + public void encrypt(KeyObject key) { + if (key == null) { + return; + } + super.encrypt(key); + if (!Checker.isEmpty(getDisplayName())) { + setDisplayName(CryptoUtils.encryptToJwe(key, getDisplayName())); + } + if (!Checker.isEmpty(getMarkdown())) { + setMarkdown(CryptoUtils.encryptToJwe(key, getMarkdown())); + } + } + + @Override + public void decrypt(KeyObject key) { + if (key == null) { + return; + } + super.decrypt(key); + if (!Checker.isEmpty(getDisplayName())) { + setDisplayName(CryptoUtils.decryptFromJwe(key, getDisplayName())); + } + if (!Checker.isEmpty(getMarkdown())) { + setMarkdown(CryptoUtils.decryptFromJwe(key, getMarkdown())); + } + } + + public ItemsModel getMentions() { + return mentions; + } + + public ItemsModel getGroupMentions() { + return groupMentions; + } + + public void setMentions(ItemsModel mentions) { + this.mentions = mentions; + } + + public void setGroupMentions(ItemsModel groupMentions) { + this.groupMentions = groupMentions; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ContentModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ContentModel.java new file mode 100644 index 00000000..4e6e0885 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ContentModel.java @@ -0,0 +1,156 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.ciscowebex.androidsdk.internal.crypto.CryptoUtils; +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; +import me.helloworld.utils.Checker; + +import java.util.ArrayList; + +public class ContentModel extends ObjectModel implements MentionableModel, MarkdownableModel { + + public static class Category { + public static final String IMAGES = "images"; + public static final String DOCUMENTS = "documents"; + public static final String VIDEOS = "videos"; + public static final String LINKS = "links"; + } + + private ItemsModel files; + private String contentCategory; + private ItemsModel mentions; + private ItemsModel groupMentions; + // TODO private ItemsModel links; + private ArrayList contentOrder; + private String markdown; + + public ContentModel(String category) { + super(ObjectModel.Type.content); + this.contentCategory = category; + } + + public ItemsModel getFiles() { + return files; + } + + public String getContentCategory() { + return contentCategory; + } + + public boolean isImage() { + return (ContentModel.Category.IMAGES.equals(contentCategory)); + } + + public boolean isFile() { + return (ContentModel.Category.DOCUMENTS.equals(contentCategory)); + } + + public boolean isVideo() { + return ContentModel.Category.VIDEOS.equals(contentCategory); + } + + public boolean isLink() { + return ContentModel.Category.LINKS.equals(contentCategory); + } + + public void setFiles(ItemsModel files) { + this.files = files; + } + + public ItemsModel getContentFiles() { + return files; + } + + public ItemsModel getMentions() { + return mentions; + } + + public ItemsModel getGroupMentions() { + return groupMentions; + } + + public void setMentions(ItemsModel mentions) { + this.mentions = mentions; + } + + public ArrayList getContentOrder() { + return contentOrder; + } + + public void setContentOrder(ArrayList contentOrder) { + this.contentOrder = contentOrder; + } + + public String getMarkdown() { + return markdown; + } + + public void setMarkdown(String markdown) { + this.markdown = markdown; + } + + @Override + public String toString() { + return "contentCategory:" + contentCategory; + } + + @Override + public void encrypt(KeyObject key) { + if (key == null) { + return; + } + super.encrypt(key); + if (!Checker.isEmpty(getDisplayName())) { + setDisplayName(CryptoUtils.encryptToJwe(key, getDisplayName())); + } + if (!Checker.isEmpty(getMarkdown())) { + setMarkdown(CryptoUtils.encryptToJwe(key, getMarkdown())); + } + if (getFiles() != null) { + for (FileModel file : getFiles().getItems()) { + file.encrypt(key); + } + } + } + + @Override + public void decrypt(KeyObject key) { + if (key == null) { + return; + } + super.decrypt(key); + if (!Checker.isEmpty(getDisplayName())) { + setDisplayName(CryptoUtils.decryptFromJwe(key, getDisplayName())); + } + if (!Checker.isEmpty(getMarkdown())) { + setMarkdown(CryptoUtils.decryptFromJwe(key, getMarkdown())); + } + if (getFiles() != null) { + for (FileModel file : getFiles().getItems()) { + file.decrypt(key); + } + } + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ConversationModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ConversationModel.java new file mode 100644 index 00000000..5254f824 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ConversationModel.java @@ -0,0 +1,432 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.support.annotation.Nullable; +import android.text.TextUtils; +import com.ciscowebex.androidsdk.internal.crypto.CryptoUtils; +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; +import com.ciscowebex.androidsdk.internal.crypto.KmsResourceObject; +import com.google.gson.annotations.SerializedName; +import me.helloworld.utils.Checker; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class ConversationModel extends ObjectModel { + + public enum Tag { + MUTED, + ONE_ON_ONE, + FAVORITE, + HIDDEN, + LOCKED, + TEAM, // If a conversation has the TEAM tag it is the primary conversation for a team. This + // means that the participant list is the list of members of the team, and the + // conversation is the 'general' team conversation + OPEN, // If a conversation has the OPEN tag it is a conversation that is open to all members + // of a team that it is associated with, but is not the primary conversation + NOT_JOINED, // This means the conversation is a team room that the self user hasn't joined + ARCHIVED, + MESSAGE_NOTIFICATIONS_ON, + MESSAGE_NOTIFICATIONS_OFF, + MENTION_NOTIFICATIONS_ON, + MENTION_NOTIFICATIONS_OFF, + ANNOUNCEMENT; + + public static Tag safeValueOf(String name) { + try { + return valueOf(name); + } catch (IllegalArgumentException e) { + // no such thing + return null; + } + } + } + + private ItemsModel participants = new ItemsModel<>(); + private ItemsModel activities = new ItemsModel<>(); + @SerializedName("tags") + private List tagNames = new ArrayList<>(); + private String locusUrl; + private String summary; + private String creatorUUID; + private Date lastRelevantActivityDate; + private TeamModel team; + private Boolean isTeamGuestMember; + private ContentModel avatar; + private String avatarEncryptionKeyUrl; + private int shareCount; + private String aclUrl; + + private String defaultActivityEncryptionKeyUrl; + private transient boolean isEncrypted; + private String encryptionKeyUrl; + private String kmsResourceObjectUrl; + private String encryptedKmsMessage; + + private Date lastReadableActivityDate; + private Date lastSeenActivityDate; + private Date lastJoinedDate; + + private String retentionUrl; + private OrganizationModel custodianOrg; + private ItemsModel organizationPolicies = new ItemsModel<>(); + private transient boolean hasTags = true; + + public String getDefaultActivityEncryptionKeyUrl() { + return defaultActivityEncryptionKeyUrl; + } + + public void setDefaultActivityEncryptionKeyUrl(String defaultActivityEncryptionKeyUrl) { + this.defaultActivityEncryptionKeyUrl = defaultActivityEncryptionKeyUrl; + } + + public ConversationModel() { + super(ObjectModel.Type.conversation); + } + + public ConversationModel(String id) { + this(); + setId(id); + } + + public ItemsModel getParticipants() { + return participants; + } + + public void setParticipants(ItemsModel participants) { + this.participants = participants; + } + + public ItemsModel getActivities() { + return activities; + } + + public void setActivities(ItemsModel activities) { + this.activities = activities; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public String getSummary() { + return summary; + } + + public boolean isMuted() { + return containsTag(ConversationModel.Tag.MUTED); + } + + public boolean isFavorite() { + return containsTag(ConversationModel.Tag.FAVORITE); + } + + public boolean isHidden() { + return containsTag(ConversationModel.Tag.HIDDEN); + } + + public boolean isArchived() { + return containsTag(ConversationModel.Tag.ARCHIVED); + } + + public boolean isLocked() { + return containsTag(ConversationModel.Tag.LOCKED); + } + + public boolean isInAnnouncementMode() { + return containsTag(ConversationModel.Tag.ANNOUNCEMENT); + } + + public boolean isTeam() { + return containsTag(ConversationModel.Tag.TEAM); + } + + public boolean isTeamGuestMember() { + return (isTeamGuestMember == null) ? false : isTeamGuestMember; + } + + public boolean isOpen() { + return containsTag(ConversationModel.Tag.OPEN); + } + + public boolean isJoined() { + return !containsTag(ConversationModel.Tag.NOT_JOINED); + } + + public void setIsOpen(boolean isOpen) { + setTag(ConversationModel.Tag.OPEN, isOpen); + } + + public void setIsTeam(boolean isTeam) { + setTag(ConversationModel.Tag.TEAM, isTeam); + } + + public void setIsMuted(boolean isMuted) { + setTag(ConversationModel.Tag.MUTED, isMuted); + } + + public Boolean isMessageNotificationsOn() { + return getNotificationTagTristate(ConversationModel.Tag.MESSAGE_NOTIFICATIONS_ON, ConversationModel.Tag.MESSAGE_NOTIFICATIONS_OFF); + } + + public Boolean isMentionNotificationsOn() { + return getNotificationTagTristate(ConversationModel.Tag.MENTION_NOTIFICATIONS_ON, ConversationModel.Tag.MENTION_NOTIFICATIONS_OFF); + } + + + @Nullable + private Boolean getNotificationTagTristate(ConversationModel.Tag notificationOnTag, ConversationModel.Tag notificationOffTag) { + final boolean onSet = containsTag(notificationOnTag); + final boolean offSet = containsTag(notificationOffTag); + + if (onSet) { + return true; + } else if (offSet) { + return false; + } else { + return null; + } + } + + public boolean containsTag(ConversationModel.Tag tag) { + return tagNames.contains(tag.name()); + } + + public void setTag(ConversationModel.Tag tag, boolean shouldExist) { + if (shouldExist) { + if (!tagNames.contains(tag.name())) + tagNames.add(tag.name()); + } else { + tagNames.remove(tag.name()); + } + } + + public List getTags() { + if (tagNames == null) + return null; + + List ret = new ArrayList<>(); + for (String name : tagNames) { + ConversationModel.Tag tag = ConversationModel.Tag.safeValueOf(name); + if (tag != null) + ret.add(tag); + } + return ret; + } + + public boolean isOneOnOne() { + return containsTag(ConversationModel.Tag.ONE_ON_ONE); + } + + public boolean isEncrypted() { + return isEncrypted; + } + + public void setIsEncrypted(boolean isEncrypted) { + this.isEncrypted = isEncrypted; + } + + public String getLocusUrl() { + return locusUrl; + } + + public void setLocusUrl(String locusUrl) { + this.locusUrl = locusUrl; + } + + public String getCreatorUUID() { + return creatorUUID; + } + + public String getTitleEncryptionKeyUrl() { + return encryptionKeyUrl; + } + + public Date getLastRelevantActivityTimestamp() { + return lastRelevantActivityDate; + } + + public TeamModel getTeam() { + return team; + } + + public void setTeam(TeamModel team) { + this.team = team; + } + + public String getAvatarEncryptionKeyUrl() { + return avatarEncryptionKeyUrl; + } + + public ContentModel getAvatar() { + return avatar; + } + + public KmsResourceObject getKmsResourceObject() { + if (kmsResourceObjectUrl == null) { + return null; + } + return new KmsResourceObject(kmsResourceObjectUrl); + } + + public void setKmsResourceObjectUrl(String kmsResourceObjectUrl) { + this.kmsResourceObjectUrl = kmsResourceObjectUrl; + } + + public Date getLastReadableActivityDate() { + return lastReadableActivityDate; + } + + public Date getLastSeenActivityDate() { + return lastSeenActivityDate; + } + + public Date getLastJoinedDate() { + return lastJoinedDate; + } + + public void setLastReadableActivityDate(Date lastReadableActivityDate) { + this.lastReadableActivityDate = lastReadableActivityDate; + } + + public void setLastRelevantActivityDate(Date lastRelevantActivityDate) { + this.lastRelevantActivityDate = lastRelevantActivityDate; + } + + public void setLastSeenActivityDate(Date lastSeenActivityDate) { + this.lastSeenActivityDate = lastSeenActivityDate; + } + + public void setLastJoinedDate(Date lastJoinedDate) { + this.lastJoinedDate = lastJoinedDate; + } + + public OrganizationModel getCustodianOrg() { + return custodianOrg; + } + + public void setCustodianOrg(OrganizationModel custodianOrg) { + this.custodianOrg = custodianOrg; + } + + public String getRetentionUrl() { + return retentionUrl; + } + + public void setRetentionUrl(String retentionUrl) { + this.retentionUrl = retentionUrl; + } + + public ItemsModel getOrganizationPolicies() { + return organizationPolicies; + } + + public void setOrganizationPolicies(ItemsModel organizationPolicies) { + this.organizationPolicies = organizationPolicies; + } + + public void updateWithHeadersFrom(ConversationModel conversation) { + if (conversation == null) { + return; + } + if (getLastReadableActivityDate() == null) { + setLastReadableActivityDate(conversation.getLastReadableActivityDate()); + } else if (conversation.getLastReadableActivityDate() != null && getLastReadableActivityDate().before(conversation.getLastReadableActivityDate())) { + setLastReadableActivityDate(conversation.getLastReadableActivityDate()); + } + } + + public String getAclUrl() { + return aclUrl; + } + + public void setAclUrl(String aclUrl) { + this.aclUrl = aclUrl; + } + + public void setHasTags(boolean hasTags) { + this.hasTags = hasTags; + } + + public boolean hasTags() { + return hasTags; + } + + @Override + public void encrypt(KeyObject key){ + if (key == null) { + return; + } + super.encrypt(key); + if (!Checker.isEmpty(getDisplayName())) { + setDisplayName(CryptoUtils.encryptToJwe(key, getDisplayName())); + encryptionKeyUrl = key.getKeyUrl(); + } + if (!Checker.isEmpty(getSummary())) { + setSummary(CryptoUtils.encryptToJwe(key, getSummary())); + encryptionKeyUrl = key.getKeyUrl(); + } + if (avatar != null) { + avatar.encrypt(key); + avatarEncryptionKeyUrl = key.getKeyUrl(); + } + } + + @Override + public void decrypt(KeyObject key) { + if (key == null) { + return; + } + super.decrypt(key); + if (!TextUtils.isEmpty(getDisplayName())) { + String plainText = CryptoUtils.decryptFromJwe(key, getDisplayName()); + if (!TextUtils.isEmpty(plainText)) { + setDisplayName(plainText); + encryptionKeyUrl = key.getKeyUrl(); + } + } + if (!TextUtils.isEmpty(getSummary())) { + String plainText = CryptoUtils.decryptFromJwe(key, getSummary()); + if (!TextUtils.isEmpty(plainText)) { + setSummary(plainText); + encryptionKeyUrl = key.getKeyUrl(); + } + } + if (avatar != null) { + avatar.decrypt(key); + avatarEncryptionKeyUrl = key.getKeyUrl(); + } + } + + @Override + public String toString() { + if (isOneOnOne()) { + return getId() + " (1-1)"; + } + return getId() + " (group)"; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/DeviceModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/DeviceModel.java new file mode 100644 index 00000000..aab66c38 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/DeviceModel.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.HashMap; +import java.util.Map; + +public class DeviceModel { + + private String url; + + private String webSocketUrl; + + private String deviceSettingsString; + + private Map services = new HashMap<>(); + + public String getDeviceUrl() { + return url; + } + + public String getWebSocketUrl() { + return webSocketUrl; + } + + public String getDeviceSettings() { + return deviceSettingsString; + } + + public String getServiceUrl(String key) { + return services.get(key); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/DisplayHintsModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/DisplayHintsModel.java new file mode 100644 index 00000000..54ffef15 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/DisplayHintsModel.java @@ -0,0 +1,76 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.ArrayList; +import java.util.List; + +public class DisplayHintsModel { + + public enum LocalRecordingStatus { + LOCAL_RECORDING_STATUS_STOPPED, + LOCAL_RECORDING_STATUS_PAUSED, + LOCAL_RECORDING_STATUS_STARTED + } + + public enum JoinedDisplayHint { + WAITING_FOR_OTHERS, + RECORDING_STATUS_STARTED, + RECORDING_STATUS_PAUSED, + RECORDING_STATUS_STOPPED, + LOCK_STATUS_LOCKED, + LOCK_STATUS_UNLOCKED; + } + + public enum LobbyDisplayHint { + WAIT_FOR_HOST_TO_JOIN, + HOST_HAS_BEEN_NOTIFIED, + OTHERS_HAVE_BEEN_NOTIFIED; + + static public LobbyDisplayHint fromString(String value) { + try { + value = value.toUpperCase().trim(); + return LobbyDisplayHint.valueOf(value); + } catch (IllegalArgumentException e) { + // unknown enum + return null; + } + } + } + + private List joined = new ArrayList<>(); + private List lobby = new ArrayList<>(); + private List moderator = new ArrayList<>(); + + public List getJoinedHints() { + return joined; + } + + public List getLobbyHints() { + return lobby; + } + + public List getModeratorHints() { + return moderator; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/FileModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/FileModel.java new file mode 100644 index 00000000..ea2644ad --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/FileModel.java @@ -0,0 +1,274 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.ciscowebex.androidsdk.internal.crypto.CryptoUtils; +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; +import com.ciscowebex.androidsdk.internal.crypto.SecureContentReference; +import com.ciscowebex.androidsdk.utils.GiphyUtils; +import com.github.benoitdion.ln.Ln; +import com.nimbusds.jose.JOSEException; +import me.helloworld.utils.Checker; + +import java.util.Date; + +public class FileModel extends ObjectModel { + + public enum DownloadProgressState { + PROGRESS_DEFAULT, + UPLOAD_IN_PROGRESS, + UPLOAD_COMPLETE, + UPLOAD_FAILED + } + + private String contentId; + private long fileSize; + private String version; + private PersonModel author; + private String mimeType; + private Date updated; + private ImageModel image; + private String scr; + private String scrLocReference; + private SecureContentReference secureContentReference; + private boolean hidden; + private DownloadProgressState progressState; + private boolean isGiphyFromSearchCategory; + + public FileModel() { + super(ObjectModel.Type.file); + } + + public FileModel(String uri) { + this(); + setUrl(uri); + } + + public FileModel(String contentId, String version, String displayName, SecureContentReference scr, + String uri, String loc, long fileSize, String mimeType, ImageModel image) { + this(); + super.setDisplayName(displayName); + setSecureContentReference(scr); + if (uri != null) { + setUrl(uri); + } + setScrLocReference(loc); + this.contentId = contentId; + this.fileSize = fileSize; + this.version = version; + this.progressState = DownloadProgressState.PROGRESS_DEFAULT; + this.mimeType = mimeType; + this.image = image; + } + + @Override + public String getId() { + return contentId; + } + + public ObjectModel setId(String contentId) { + this.contentId = contentId; + return this; + } + + public long getFileSize() { + return fileSize; + } + + public void setFileSize(long fileSize) { + this.fileSize = fileSize; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public PersonModel getAuthor() { + return author; + } + + public void setAuthor(PersonModel author) { + this.author = author; + } + + public String getMimeType() { + return mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + public ImageModel getImage() { + return image; + } + + public void setImage(ImageModel image) { + this.image = image; + } + + public boolean isGiphyFromSearchCategory() { + return isGiphyFromSearchCategory; + } + + public void setGiphyFromSearchCategory(boolean giphyFromSearchCategory) { + isGiphyFromSearchCategory = giphyFromSearchCategory; + } + + public void setProgressState(DownloadProgressState progressState) { + this.progressState = progressState; + } + + public DownloadProgressState getProgressState() { + return progressState; + } + + public String getScrLocReference() { + return scrLocReference; + } + + public void setScrLocReference(String scrLocReference) { + this.scrLocReference = scrLocReference; + } + + public String getScr() { + return scr; + } + + public void setScr(String scr) { + this.scr = scr; + } + + public String getUrlOrSecureLocation() { + if (isSecureContentReference()) { + return secureContentReference.getLoc(); + } else { + return getUrl(); + } + } + + public void setSecureContentReference(SecureContentReference secureContentReference) { + this.secureContentReference = secureContentReference; + if (secureContentReference != null) { + setUrl(secureContentReference.getLoc()); + } + } + + public boolean isSecureContentReference() { + return secureContentReference != null; + } + + public SecureContentReference getSecureContentReference() { + return secureContentReference; + } + + public boolean isHidden() { + return hidden; + } + + public void setHidden(boolean hidden) { + this.hidden = hidden; + } + + @Override + public String toString() { + return "File{" + + "fileSize=" + fileSize + + ", version='" + version + '\'' + + ", author=" + author + + ", mimeType='" + mimeType + '\'' + + ", updated=" + updated + '\'' + + ", contentId=" + contentId + '\'' + + ", image=" + ((image != null) ? image.toString() : "") + '\'' + + ", isHidden=" + hidden + + '}'; + } + + @Override + public void encrypt(KeyObject key) { + if (key == null) { + return; + } + super.encrypt(key); + if (!Checker.isEmpty(getDisplayName())) { + setDisplayName(CryptoUtils.encryptToJwe(key, getDisplayName())); + } + if (secureContentReference != null) { + try { + secureContentReference.setIsGiphy(isFileGiphy()); + if (getScrLocReference() != null) { + secureContentReference.setLoc(getScrLocReference()); + setScrLocReference(null); + } else { + secureContentReference.setLoc(getUrl()); + } + setScr(secureContentReference.toJWE(key.getKeyBytes())); + setSecureContentReference(null); + } catch (JOSEException e) { + Ln.d(e); + } + } + if (getImage() != null) { + getImage().encrypt(key); + } + } + + @Override + public void decrypt(KeyObject key) { + if (key == null) { + return; + } + super.decrypt(key); + if (!Checker.isEmpty(getDisplayName())) { + setDisplayName(CryptoUtils.decryptFromJwe(key, getDisplayName())); + } + if (getScr() != null) { + try { + if (isFileGiphy()) { + setSecureContentReference(SecureContentReference.fromJWEForGiphy(key.getKeyBytes(), getScr())); + } else { + setSecureContentReference(SecureContentReference.fromJWE(key.getKeyBytes(), getScr())); + } + } catch (Throwable e) { + Ln.d(e); + } + } + if (getImage() != null) { + getImage().decrypt(key); + } + } + + private boolean isFileGiphy() { + if (ObjectModel.Type.giphy.equalsIgnoreCase(getObjectType())) { + return true; + } else { + // This check is does since the backend systems cannot support an objectType of 'Giphy" presently. + // Once it is supported this return can be refactored. + return GiphyUtils.isMimeTypeGiphy(mimeType) && GiphyUtils.isImageGiphy(image); + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/FloorModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/FloorModel.java new file mode 100644 index 00000000..50ecdfb5 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/FloorModel.java @@ -0,0 +1,107 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +/** + * A Floor for a MediaShare is a "temporary permission to access or manipulate" a MediaShare. From a ReST perspective, + * a Floor is a sub-resource of a MediaShare. The Benificiary of a Floor is the Locus Participant that currently has + * permission to control the MediaShare. A Requester of a Floor is a Locus Participant that wishes to obtain the floor + * for itself or for another Participant (the beneficiary). + */ +public class FloorModel { + + public enum Disposition { + ACCEPTED, GRANTED, RELEASED + } + + public FloorModel(LocusParticipantModel beneficiary, LocusParticipantModel requester, Disposition disposition) { + this.disposition = disposition; + this.beneficiary = beneficiary; + this.requester = requester; + } + + private Disposition disposition; + + private String requested; + + private String granted; + + private String released; + + private LocusParticipantModel requester; + + private LocusParticipantModel beneficiary; + + public Disposition getDisposition() { + return disposition; + } + + public void setDisposition(Disposition disposition) { + this.disposition = disposition; + } + + public String getRequested() { + return requested; + } + + public void setRequested(String requested) { + this.requested = requested; + } + + public String getGranted() { + return granted; + } + + public void setGranted(String granted) { + this.granted = granted; + } + + public String getReleased() { + return released; + } + + public void setReleased(String released) { + this.released = released; + } + + public LocusParticipantModel getRequester() { + return requester; + } + + public void setRequester(LocusParticipantModel requester) { + this.requester = requester; + } + + public LocusParticipantModel getBeneficiary() { + return beneficiary; + } + + public void setBeneficiary(LocusParticipantModel beneficiary) { + this.beneficiary = beneficiary; + } + + public boolean isValid() { + return granted != null && disposition != null && beneficiary != null; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/GroupMentionModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/GroupMentionModel.java new file mode 100644 index 00000000..4eb1828a --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/GroupMentionModel.java @@ -0,0 +1,85 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.support.annotation.Nullable; +import com.google.gson.annotations.SerializedName; + +public class GroupMentionModel extends ObjectModel { + + public enum Type { + @SerializedName("all") + ALL("all"), + @SerializedName("here") + HERE("here"); + + String value; + + Type(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static @Nullable GroupMentionModel.Type convertStringToType(String value) { + if (value != null) { + for (GroupMentionModel.Type type : GroupMentionModel.Type.values()) { + if (value.equalsIgnoreCase(type.getValue())) { + return type; + } + } + } + return null; + } + } + + private GroupMentionModel.Type groupType; + + public GroupMentionModel() { + super(ObjectModel.Type.groupMention); + } + + public GroupMentionModel(GroupMentionModel.Type groupType) { + this(); + this.groupType = groupType; + } + + public GroupMentionModel.Type getGroupType() { + return groupType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof GroupMentionModel)) return false; + GroupMentionModel that = (GroupMentionModel) o; + return groupType == that.groupType; + } + + @Override + public int hashCode() { + return groupType.hashCode(); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ImageModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ImageModel.java new file mode 100644 index 00000000..c4d7bef3 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ImageModel.java @@ -0,0 +1,149 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; +import com.ciscowebex.androidsdk.internal.crypto.SecureContentReference; +import com.ciscowebex.androidsdk.utils.GiphyUtils; +import com.ciscowebex.androidsdk.utils.UriUtils; +import com.github.benoitdion.ln.Ln; +import com.nimbusds.jose.JOSEException; +import me.helloworld.utils.Checker; + +public class ImageModel { + + private String url; + private int width; + private int height; + private String scr; + private SecureContentReference secureContentReference; + private boolean thumbnail; + + public ImageModel() { + } + + public ImageModel(String url, int width, int height, SecureContentReference secureContentReference, boolean thumbnail) { + this.url = url; + this.width = width; + this.height = height; + this.secureContentReference = secureContentReference; + this.thumbnail = thumbnail; + } + + public String getUrl() { + return url; + } + + public int getHeight() { + return height; + } + + public int getWidth() { + return width; + } + + public String toString() { + return "Image{" + + "url=" + url + + ", width=" + width + + ", height=" + height + + '}'; + } + + public void setUrl(String url) { + this.url = url; + } + + public boolean isThumbnail() { + return thumbnail; + } + + public String getScr() { + return scr; + } + + public void setScr(String scr) { + this.scr = scr; + } + + public String getUrlOrSecureLocation() { + if (isSecureContentReference()) { + return secureContentReference.getLoc(); + } else { + return getUrl(); + } + } + + public void setSecureContentReference(SecureContentReference secureContentReference) { + this.secureContentReference = secureContentReference; + if (secureContentReference != null) { + setUrl(secureContentReference.getLoc()); + } + } + + public boolean isSecureContentReference() { + return secureContentReference != null; + } + + public SecureContentReference getSecureContentReference() { + return secureContentReference; + } + + public void encrypt(KeyObject key) { + if (secureContentReference != null) { + secureContentReference.setIsGiphy(GiphyUtils.isUriGiphy(getUrl())); + try { + setScr(secureContentReference.toJWE(key.getKeyBytes())); + setSecureContentReference(null); + } catch (JOSEException e) { + Ln.d(e); + } + } + } + + public void decrypt(KeyObject key) { + String scr = getScr(); + if (Checker.isEmpty(scr) && getUrl() != null && getUrl().startsWith("secureContentReference")) { + scr = UriUtils.parseIfNotNull(getUrl()).getSchemeSpecificPart(); + } + + if (!Checker.isEmpty(scr)) { + try { + if (GiphyUtils.isUriGiphy(getUrl())) { + setSecureContentReference(SecureContentReference.fromJWEForGiphy(key.getKeyBytes(), scr)); + } else { + setSecureContentReference(SecureContentReference.fromJWE(key.getKeyBytes(), scr)); + } + } catch (Throwable t) { + Ln.e(t); + } + } + } + + public void copyFromFile(FileModel file) { + this.scr = file.getScr(); + this.url = file.getUrl(); + this.secureContentReference = file.getSecureContentReference(); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/IntentModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/IntentModel.java new file mode 100644 index 00000000..7cdbadf6 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/IntentModel.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class IntentModel { + private String id; + private LocusParticipantModel.IntentType type; + private String associatedWith; + + public IntentModel(String id, LocusParticipantModel.IntentType type, String associatedWith) { + this.id = id; + this.type = type; + this.associatedWith = associatedWith; + } + + public String getId() { + return id; + } + + public LocusParticipantModel.IntentType getType() { + return type; + } + + public String getAssociatedWith() { + return associatedWith; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ItemsModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ItemsModel.java new file mode 100644 index 00000000..8b10616b --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ItemsModel.java @@ -0,0 +1,65 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +public class ItemsModel { + + @SerializedName("items") + private List items = new ArrayList(); + + public ItemsModel() { + } + + public ItemsModel(List items) { + setItems(items); + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public void addItem(T item) { + items.add(item); + } + + public void addItems(List items) { + this.items.addAll(items); + } + + public int size() { + return items.size(); + } + + public void clear() { + items.clear(); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/JWTLoginModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/JWTLoginModel.java new file mode 100644 index 00000000..3a814c52 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/JWTLoginModel.java @@ -0,0 +1,48 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.google.gson.annotations.SerializedName; +import me.helloworld.utils.Checker; + +public class JWTLoginModel { + + @SerializedName("expiresIn") + private long expiresIn; + + @SerializedName("token") + private String accessToken; + + public long getExpiresIn() { + return this.expiresIn; + } + + public String getAccessToken() { + return this.accessToken; + } + + public TokenModel toToken(String jwt) { + return new TokenModel(getAccessToken(), this.getExpiresIn() + (System.currentTimeMillis() / 1000), jwt); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/KmsInfoModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/KmsInfoModel.java new file mode 100644 index 00000000..196632da --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/KmsInfoModel.java @@ -0,0 +1,44 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.net.Uri; + +public class KmsInfoModel { + + private String kmsMachineAccountId; + private String rsaPublicKey; + private Uri kmsCluster; + + public String getKmsId() { + return kmsMachineAccountId; + } + + public String getRsaPublicKey() { + return rsaPublicKey; + } + + public Uri getKmsCluster() { + return kmsCluster; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/KmsMessageModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/KmsMessageModel.java new file mode 100644 index 00000000..c16ec2de --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/KmsMessageModel.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.ArrayList; +import java.util.List; + +public class KmsMessageModel { + + private List kmsMessages = new ArrayList<>(); + private String destination; + private boolean success; + private boolean synchronous; + + public List getKmsMessages() { + return kmsMessages; + } + + public void addKmsMessages(List kmsMessages) { + this.kmsMessages.addAll(kmsMessages); + } + + public void addKmsMessage(String kmsMessage) { + this.kmsMessages.add(kmsMessage); + } + + public String getDestination() { + return destination; + } + + public void setDestination(String destination) { + this.destination = destination; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public boolean isSynchronous() { + return synchronous; + } + + public void setSynchronous(boolean synchronous) { + this.synchronous = synchronous; + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusControlMetaModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusControlMetaModel.java new file mode 100644 index 00000000..37215ab1 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusControlMetaModel.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.Date; + +public class LocusControlMetaModel { + private String modifiedBy; + private Date lastModified; + private boolean readOnly; + + public String getModifiedBy() { + return modifiedBy; + } + + public Date getLastModified() { + return lastModified; + } + + public boolean isReadOnly() { + return readOnly; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusControlModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusControlModel.java new file mode 100644 index 00000000..628c31cb --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusControlModel.java @@ -0,0 +1,56 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.List; + +public class LocusControlModel { + + private String url; + private LocusLockControlModel lock; + private LocusRecordControlModel record; + private List links; + + public LocusControlModel(String url, LocusLockControlModel lock, LocusRecordControlModel record, List links) { + this.url = url; + this.lock = lock; + this.record = record; + this.links = links; + } + + public String getUrl() { + return url; + } + + public LocusLockControlModel getLock() { + return lock; + } + + public LocusRecordControlModel getRecord() { + return record; + } + + public List getLinks() { + return links; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusDescriptionModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusDescriptionModel.java new file mode 100644 index 00000000..503c9104 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusDescriptionModel.java @@ -0,0 +1,120 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.HashSet; +import java.util.Set; + +public class LocusDescriptionModel { + + // Fields set by gson + private Set locusTags; + private String owner; + private String sipUri; + private boolean isPmr; + private DisplayHintsModel displayHints; + private String webExMeetingId; + private String webExMeetingName; + private String callInTollNumber; + private String callInTollFreeNumber; + private boolean isSparkPstnEnabled; + private boolean isCallInEnabled; + private boolean isGlobalCallInEnabled; + private boolean isCallOutEnabled; + private boolean isInternalCallOutEnabled; + private boolean isGlobalCallOutEnabled; + private String conversationUrl; + private String webExSite; + + public Set getLocusTags() { + if (locusTags != null) { + return locusTags; + } else { + return new HashSet<>(); + } + } + + public String getOwner() { + return owner; + } + + public String getSipUri() { + return sipUri; + } + + public boolean isPmr() { + return isPmr; + } + + public DisplayHintsModel getLocusDisplayHints() { + return displayHints; + } + + public String getWebExMeetingId() { + return webExMeetingId; + } + + public String getWebExMeetingName() { + return webExMeetingName; + } + + public String getCallInTollNumber() { + return callInTollNumber; + } + + public String getCallInTollFreeNumber() { + return callInTollFreeNumber; + } + + public boolean isSparkPstnEnabled() { + return isSparkPstnEnabled; + } + + public boolean isCallInEnabled() { + return isCallInEnabled; + } + + public boolean isGlobalCallInEnabled() { + return isGlobalCallInEnabled; + } + + public boolean isCallOutEnabled() { + return isCallOutEnabled; + } + + public boolean isInternalCallOutEnabled() { + return isInternalCallOutEnabled; + } + + public boolean isGlobalCallOutEnabled() { + return isGlobalCallOutEnabled; + } + + public String getConversationUrl() { + return conversationUrl; + } + + public String getWebExSite() { + return webExSite; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusKeyModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusKeyModel.java new file mode 100644 index 00000000..2e457672 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusKeyModel.java @@ -0,0 +1,66 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class LocusKeyModel { + + private String url; + + public LocusKeyModel(String locusUrl) { + this.url = locusUrl; + } + + public String getUrl() { + return url; + } + + public String getLocusId() { + if (url == null) { + return ""; + } + String[] parts = url.split("/"); + if (parts.length == 0) { + return ""; + } else { + return parts[parts.length - 1]; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { return true; } + if (o == null || getClass() != o.getClass()) { return false; } + LocusKeyModel locusKey = (LocusKeyModel) o; + return url.equals(locusKey.url); + } + + @Override + public int hashCode() { + return url.hashCode(); + } + + @Override + public String toString() { + return url; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusLinkModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusLinkModel.java new file mode 100644 index 00000000..26015042 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusLinkModel.java @@ -0,0 +1,64 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.google.gson.JsonObject; + +public class LocusLinkModel { + private String rel; + private String href; + private String method; + private JsonObject body; + + public String getRel() { + return rel; + } + + public String getHref() { + return href; + } + + public String getMethod() { + return method; + } + + public JsonObject getBody() { + return body; + } + + public void setRel(String rel) { + this.rel = rel; + } + + public void setHref(String href) { + this.href = href; + } + + public void setMethod(String method) { + this.method = method; + } + + public void setBody(JsonObject body) { + this.body = body; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusListResponseModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusListResponseModel.java new file mode 100644 index 00000000..8cc88610 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusListResponseModel.java @@ -0,0 +1,12 @@ +package com.ciscowebex.androidsdk.internal.model; + +import java.util.List; + +public class LocusListResponseModel { + + private List loci; + + public List getLoci() { + return loci; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusLockControlModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusLockControlModel.java new file mode 100644 index 00000000..b3bd5426 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusLockControlModel.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class LocusLockControlModel { + private boolean locked; + private LocusControlMetaModel meta; + + public LocusLockControlModel(boolean locked, LocusControlMetaModel meta) { + this.locked = locked; + this.meta = meta; + } + + public boolean isLocked() { + return locked; + } + + public LocusControlMetaModel getMeta() { + return meta; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusMediaDirection.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusMediaDirection.java new file mode 100644 index 00000000..3c6cc86a --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusMediaDirection.java @@ -0,0 +1,30 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public enum LocusMediaDirection { + SENDRECV, + SENDONLY, + RECVONLY, + INACTIVE +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusMediaResponseModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusMediaResponseModel.java new file mode 100644 index 00000000..bb4b1954 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusMediaResponseModel.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.List; + +public class LocusMediaResponseModel { + + private LocusModel locus; + private List mediaConnections; + + public LocusModel getLocus() { + return locus; + } + + public List getMediaConnections() { + return mediaConnections; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusModel.java new file mode 100644 index 00000000..9f1ad90e --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusModel.java @@ -0,0 +1,831 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.net.Uri; +import android.support.annotation.Nullable; +import android.telephony.PhoneNumberUtils; +import android.text.TextUtils; +import com.ciscowebex.androidsdk.internal.Device; +import com.ciscowebex.androidsdk.phone.Call; +import com.ciscowebex.androidsdk.utils.DateUtils; +import com.ciscowebex.androidsdk.utils.Json; +import com.google.gson.annotations.SerializedName; +import me.helloworld.utils.Checker; +import me.helloworld.utils.Objects; + +import java.text.DateFormat; +import java.util.*; + +public class LocusModel { + + public enum LocusTag { + ONE_ON_ONE, + ONE_ON_ONE_MEETING, + WEBEX, + EXTERNAL_URL + } + + @SerializedName("url") + private LocusKeyModel key; + private Date created; + private LocusParticipantInfoModel host; + private LocusStateModel fullState = new LocusStateModel(false, 0, LocusStateModel.State.INACTIVE); + private LocusControlModel controls; + private List participants = new ArrayList<>(); + private LocusSelfModel self; + private LocusSequenceModel sequence; + private LocusSequenceModel baseSequence; + private String syncUrl; + private List mediaShares = new ArrayList<>(); + private List replaces = new ArrayList<>(); + private String conversationUrl; + private LocusDescriptionModel info; + private LocusScheduledMeetingModel meeting; + private Uri aclUrl; + private List mediaConnections; + + public Date getCreated() { + return created; + } + + public LocusParticipantInfoModel getHost() { + return host; + } + + public LocusStateModel getFullState() { + return fullState; + } + + public LocusControlModel getControls() { + return controls; + } + + public LocusLockControlModel getLockControl() { + return controls == null ? null : controls.getLock(); + } + + public LocusRecordControlModel getRecordControl() { + return controls == null ? null : controls.getRecord(); + } + + public List getRawParticipants() { + return participants; + } + + public List getParticipants() { + ArrayList filtered = new ArrayList<>(participants.size()); + for (LocusParticipantModel part : participants) { + if (!part.isRemoved()) + filtered.add(part); + } + return filtered; + } + + @Nullable + public LocusSelfModel getSelf() { + return self; + } + + public LocusSequenceModel getSequence() { + return sequence; + } + + public List getMediaShares() { + return mediaShares; + } + + public LocusSequenceModel getBaseSequence() { + return baseSequence; + } + + public String getSyncUrl() { + return syncUrl; + } + + public List getReplaces() { + return replaces; + } + + public List getMediaConnections() { + return mediaConnections; + } + + public void setMediaConnections(List mediaConnections) { + this.mediaConnections = mediaConnections; + } + + @Nullable + @Deprecated + public String getConversationUrl() { + return conversationUrl; + } + + public LocusDescriptionModel getInfo() { + return info; + } + + public LocusScheduledMeetingModel getMeeting() { + return meeting; + } + + /** + * NOTE TO USERS: When this method returns false it has two separate, distinct meanings. + * + * 1. The meeting object on the DTO is null + * 2. The meeting object is non-null, and is inactive. + * + * If you do not know if (1) from above is not the case based on prior processing then this method + * should be called in conjunction with {@link #getMeeting()} to see if the object is null or not. + * Do not assume that because this reports false that there is an inactive meeting object + * + * @return true if the meeting is active, false if either the meeting doesn't exist or it does exist and is inactive + */ + public boolean isMeetingActive() { + return meeting != null && !meeting.isRemoved(); + } + + public Uri getAclUrl() { + return aclUrl; + } + + public void setAclUrl(Uri aclUrl) { + this.aclUrl = aclUrl; + } + + public String getUniqueCallID() { + String locusId = key.getLocusId(); + DateFormat dateFormat = DateUtils.buildIso8601Format(); + String lastActive = dateFormat.format(getFullState().getLastActive()); + if (locusId.length() > 0 && lastActive.length() > 0) { + return String.format("%s,%s", locusId, lastActive); + } + return null; + } + + public boolean isJoinedFromThisDevice(String deviceUrl) { + if (getSelf() != null) { + if (getFullState().isActive() && getSelf().getState().equals(LocusParticipantModel.State.JOINED)) { + List deviceList = getSelf().getDevices(); + if (deviceList != null) { + for (LocusParticipantDeviceModel device : deviceList) { + if (device.getUrl().equals(deviceUrl) && LocusParticipantModel.State.JOINED == device.getState()) { + return true; + } + } + } + } + } + return false; + } + + @Nullable + public LocusParticipantDeviceModel getMyDevice(String deviceUrl) { + if (deviceUrl != null && getSelf() != null) { + List deviceList = getSelf().getDevices(); + if (deviceList != null) { + for (LocusParticipantDeviceModel device : deviceList) { + if (device.getUrl().equals(deviceUrl)) { + return device; + } + } + } + } + return null; + } + + public boolean isJoinedFromOtherDevice(Uri deviceUrl) { + if (getSelf() != null) { + if (getFullState().isActive() && getSelf().getState().equals(LocusParticipantModel.State.JOINED)) { + List deviceList = getSelf().getDevices(); + if (deviceList != null) { + for (LocusParticipantDeviceModel device : deviceList) { + if (!device.getUrl().equals(deviceUrl) && LocusParticipantModel.State.JOINED == device.getState()) { + return true; + } + } + } + } + } + return false; + } + + /** + * This is the participant who called a Cisco Spark user or the participant a user on Cisco Spark called + * For instance, User A calling B with telephone number +1-408-474-3XXX using our app + * Note that this participant is not to be confused with a call-in participant in the PSTN feature + * The call must be initiated between Cisco Spark app user and a cellular/landline network or vice versa + * This call must not be a PMR call, one of the participant the cellular/landline network must be external, and + * the participant's primary display name must be a telephone number + * @return + */ + @Nullable + public LocusParticipantModel getFirstExternalParticipantOnTelephone() { + List participants = getParticipants(); + if (!getInfo().isPmr() && participants != null && !participants.isEmpty()) { + for (LocusParticipantModel participant : participants) { + if (participant.getPerson().isExternal()) { + String displayName = participant.getPerson().getDisplayName(); + if (PhoneNumberUtils.isGlobalPhoneNumber(displayName) && displayName.equals(participant.getPerson().getPrimaryDisplayString())) { + return participant; + } + } + } + } + return null; + } + + /** + * Counts the number of participants with type=USER or type=RESOURCE_ROOM who are joined or in lobby + * + * If a user is observing a resource we remove that room from the count. + * + * We only count a room if it's not being observed, and we count everyone observing the room as a participant + * + * Bob and Alice is observing Batcave + * Charlie is joined from android + * Mayflower is a room joined without any observers + * + * Count Bob, Alice, Charlie and Mayflower (Ignore Batcave) + * + * Tests in common/LocusTest + * + * @return joinedAndInLobbyParticipants + */ + public int getJoinedAndInLobbyParticipantCount() { + int joinedAndInLobbyParticipantCount = 0; + Set observedResources = new HashSet<>(); + List participants = getParticipants(); + for (LocusParticipantModel locusParticipant : participants) { + List devices = locusParticipant.getDevices(); + if (devices != null) { + for (LocusParticipantDeviceModel device : devices) { + IntentModel intent = device.getIntent(); + if (intent == null) { + continue; + } + if (intent.getType() == LocusParticipantModel.IntentType.OBSERVE) { + observedResources.add(intent.getAssociatedWith()); + } + } + } + if ((locusParticipant.isJoined() || locusParticipant.isInLobby()) && locusParticipant.isUserOrResourceRoom()) { + joinedAndInLobbyParticipantCount += 1; + } + } + joinedAndInLobbyParticipantCount -= observedResources.size(); + return joinedAndInLobbyParticipantCount; + } + + public boolean isObtp() { + return getMeeting() != null; + } + + public boolean isActiveObtp() { + return isMeetingActive() && + (getFullState().getState() == LocusStateModel.State.INITIALIZING || getFullState().getState() == LocusStateModel.State.ACTIVE); + } + + public boolean isAnyoneJoined() { + List locusParticipants = getParticipants(); + if (locusParticipants != null) { + for (LocusParticipantModel participant : locusParticipants) { + if (participant.isUserOrResourceRoom() && + (participant.isJoined() || participant.isInLobby())) + return true; + } + } + return false; + } + + public boolean isAnyNonHostJoined() { + LocusParticipantInfoModel host = getHost(); + List locusParticipants = getParticipants(); + if (host != null && locusParticipants != null) { + String hostId = host.getId(); + for (LocusParticipantModel participant : locusParticipants) { + LocusParticipantInfoModel person = participant.getPerson(); + if (person != null) { + String participantId = person.getId(); + if (hostId != null && + participant.isUserOrResourceRoom() && + !hostId.equals(participantId) && + (participant.isJoined() || participant.isInLobby())) { + return true; + } + } + } + } + return false; + } + + public boolean isSelfHost() { + LocusParticipantInfoModel host = getHost(); + LocusSelfModel self = getSelf(); + + if (host != null && self != null) { + LocusParticipantInfoModel selfParticipant = self.getPerson(); + if (selfParticipant != null) { + String hostId = host.getId(); + String selfId = self.getId().toString(); + String hostEmail = host.getEmail(); + String selfEmail = selfParticipant.getEmail(); + return (hostId != null && hostId.equals(selfId)) || + (hostEmail != null && hostEmail.equals(selfEmail)); + } + } + return false; + } + + public boolean isSelfGuest() { + LocusSelfModel selfRepresentation = getSelf(); + return selfRepresentation != null && selfRepresentation.isGuest(); + } + + public boolean isHostJoined() { + LocusParticipantInfoModel host = getHost(); + List locusParticipants = getParticipants(); + if (host != null && locusParticipants != null) { + String hostId = host.getId(); + for (LocusParticipantModel participant : locusParticipants) { + if (participant.getPerson() != null && + participant.getPerson().getId() != null && + participant.getPerson().getId().equals(hostId) && + participant.isJoined()) { + return true; + } + } + } + return false; + } + + public boolean isInLobbyFromThisDevice(String deviceUrl) { + boolean isInLobby = false; + if (self != null && self.isIdle()) { + if (self.isWaitingOnDevice(deviceUrl)) { + isInLobby = true; + } else if (self.isObservingOnDevice(deviceUrl)) { + // Determine if paired device is a Webex Share and if it is in the lobby. + LocusParticipantDeviceModel selfDevice = getMyDevice(deviceUrl); + if (selfDevice != null && selfDevice.getIntent() != null && selfDevice.getIntent().getAssociatedWith() != null) { + LocusParticipantModel associatedParticipant = getParticipant(Uri.parse(selfDevice.getIntent().getAssociatedWith())); + if (associatedParticipant != null && associatedParticipant.isDeviceType(Device.WEBEX_SHARE_TYPE)) { + if (associatedParticipant.isInLobby()) { + isInLobby = true; + } + } + } + } + } + return isInLobby; + } + + public boolean isParticipantJoinedWithWebShare(LocusParticipantModel participant) { + if (participant == null) { + return false; + } + for (LocusParticipantModel locusParticipant : getParticipants()) { + if (participant.getId().equals(locusParticipant.getId())) { + String deviceUrl = locusParticipant.getDeviceUrl(); + if (deviceUrl == null) { + continue; + } + for (LocusParticipantDeviceModel device : locusParticipant.getDevices()) { + if (device != null && device.getIntent() != null && device.getIntent().getAssociatedWith() != null) { + LocusParticipantModel associatedParticipant = getParticipant(Uri.parse(device.getIntent().getAssociatedWith())); + if (associatedParticipant != null && associatedParticipant.isDeviceType(Device.WEBEX_SHARE_TYPE) && + associatedParticipant.getState() == LocusParticipantModel.State.JOINED) { + return true; + } + } + } + } + } + return false; + } + + public IntentModel getIntent(Uri deviceUrl) { + if (getSelf() != null) { + List deviceList = getSelf().getDevices(); + if (deviceList != null) { + for (LocusParticipantDeviceModel device : deviceList) { + if (device.getUrl().equals(deviceUrl)) { + return device.getIntent(); + } + } + } + } + return null; + } + + public LocusParticipantModel getParticipant(Uri participantUrl) { + for (LocusParticipantModel locusParticipant : getParticipants()) { + if (locusParticipant.getUrl().equals(participantUrl)) { + return locusParticipant; + } + } + return null; + } + + + public boolean isObserving(Uri deviceUrl) { + IntentModel intent = getIntent(deviceUrl); + return intent != null && intent.getType() != null && + (intent.getType().equals(LocusParticipantModel.IntentType.OBSERVE) || intent.getType().equals(LocusParticipantModel.IntentType.MOVE_MEDIA)); + } + + + public boolean isSelfJoinedFromDeviceType(String deviceType) { + LocusParticipantModel participant = getSelf(); + if (participant == null) { + return false; + } + return isParticipantJoinedFromDeviceType(participant, deviceType); + } + + @Nullable + public String getDisplayNameOrEmailForCaller() { + List locusParticipants = getParticipants(); + if (locusParticipants != null && !locusParticipants.isEmpty()) { + for (LocusParticipantModel locusParticipant : locusParticipants) { + LocusSelfModel self = getSelf(); + if (self != null && !locusParticipant.getId().equals(self.getId()) && locusParticipant.isCreator) { + String displayName = locusParticipant.getPerson().getDisplayName(); + return TextUtils.isEmpty(displayName) ? locusParticipant.getPerson().getEmail() : displayName; + } + } + } + return null; + } + + public boolean isRemoteParticipantJoinedFromDeviceType(String deviceType) { + for (LocusParticipantModel participant : getParticipants()) { + // Ignore self + if (getSelf().getId().equals(participant.getId())) { + continue; + } + return isParticipantJoinedFromDeviceType(participant, deviceType); + } + return false; + } + + public boolean isParticipantJoinedFromDeviceType(LocusParticipantModel participant, String deviceType) { + LocusParticipantModel.State state = participant.getState(); + // self.state is leaving a brief while when the incoming share is ended. + if (getFullState().isActive() && (state.equals(LocusParticipantModel.State.JOINED) || state.equals(LocusParticipantModel.State.LEAVING))) { + List deviceList = participant.getDevices(); + if (deviceList != null) { + for (LocusParticipantDeviceModel device : deviceList) { + if (device.getDeviceType() != null && device.getDeviceType().equalsIgnoreCase(deviceType)) { + return true; + } + } + } + } + return false; + } + + public FloorModel getGrantedFloor() { + if (getMediaShares() != null) { + for (MediaShareModel mediaShare : getMediaShares()) { + if (mediaShare.isValidType() && mediaShare.getFloor() != null && mediaShare.getFloor().getDisposition() == FloorModel.Disposition.GRANTED) { + return mediaShare.getFloor(); + } + } + } + return null; + } + + public boolean isFloorGranted() { + FloorModel floor = getFloor(); + return floor != null && floor.getDisposition() == FloorModel.Disposition.GRANTED; + } + + public boolean isFloorReleased() { + if (getMediaShares() != null) { + for (MediaShareModel mediaShare : getMediaShares()) { + if (mediaShare.isValidType() && mediaShare.getFloor() != null && mediaShare.getFloor().getDisposition() == FloorModel.Disposition.RELEASED) { + return true; + } + } + } + return false; + } + + public MediaShareModel getWhiteboardMedia() { + if (getMediaShares() != null) { + for (MediaShareModel mediaShare : getMediaShares()) { + if (mediaShare.isWhiteboard()) { + return mediaShare; + } + } + } + return null; + } + + public LocusParticipantModel getFloorBeneficiary() { + FloorModel floor = getFloor(); + return floor != null ? floor.getBeneficiary() : null; + } + + public void setFloorBeneficiary(LocusParticipantModel participant) { + FloorModel floor = getFloor(); + if (floor != null) { + floor.setBeneficiary(participant); + } + } + + public boolean isHeld() { + if (getSelf() != null && getSelf().getIntents() != null) { + for (IntentModel intent : getSelf().getIntents()) { + if (intent.getType().equals(LocusParticipantModel.IntentType.HELD)) { + return true; + } + } + } + return false; + } + + public boolean isMeeting() { + return fullState.getType() == LocusStateModel.Type.MEETING; + } + + public boolean isSparkSpaceMeeting() { + return isMeeting() && hasConversationUrl(); + } + + /** + * Is this OBTP for one-on-one space? + * One-on-one spaces have one fixed one-on-one locus for calls associated with the space. + * And another separate locus for one-on-one scheduled space meetings. + * Having two separate loci allows us to have one-on-one scheduled meetings with sharable meeting link while maintaining the current one-on-one private call feature. + * One-on-one scheduled space meetings (OBTPs) will have ONE_ON_ONE_MEETING locus tag to identify them + * @return + */ + public boolean isOneOnOneSpaceObtp() { + return getInfo().getLocusTags().contains(LocusTag.ONE_ON_ONE_MEETING); + } + + public boolean hasConversationUrl() { + return conversationUrl != null; + } + + public boolean isProvisionalDeviceConnected(String provisionalDeviceUrl) { + boolean isConnected = false; + LocusParticipantDeviceModel provisionalDevice = getMyDevice(provisionalDeviceUrl); + if (provisionalDevice == null || provisionalDevice.getFinalUrl() == null) { + return isConnected; + } + + if (isJoinedFromThisDevice(provisionalDeviceUrl)) { + List devices = getSelf().getDevices(); + for (LocusParticipantDeviceModel device : devices) { + // Find a SIP device and points to the provisional device and vice versa and is also either + // joined or in the lobby state. + if (Device.SIP_DEVICE_TYPE.equalsIgnoreCase(device.getDeviceType()) && + provisionalDevice.getFinalUrl().equals(device.getUrl()) && + provisionalDevice.getUrl().equals(device.getProvisionalUrl())) { + isConnected = isJoinedFromThisDevice(device.getUrl()); + break; + } + } + } + return isConnected; + } + + public boolean isProvisionalDevicePresent(String provisionalDeviceUrl) { + return (getMyDevice(provisionalDeviceUrl) != null); + } + + // MARK Shortcut + public boolean isValid() { + String url = getCallUrl(); + LocusSelfModel self = getSelf(); + LocusParticipantInfoModel host = getHost(); + if (url != null && self != null && host != null) { + return true; + } + return url != null && getBaseSequence() != null; + } + + public boolean isOneOnOne() { + LocusStateModel model = getFullState(); + return model != null && model.getType() != LocusStateModel.Type.MEETING; + } + + public boolean isIncomingCall() { + LocusStateModel model = getFullState(); + if (model != null && model.getState() == LocusStateModel.State.ACTIVE) { + LocusSelfModel self = getSelf(); + if (self != null) { + AlertTypeModel alert = self.getAlertType(); + return alert != null && AlertTypeModel.ALERT_FULL.equalsIgnoreCase(alert.getAction()); + } + } + return false; + } + + public boolean isSelfInLobby() { + LocusSelfModel self = getSelf(); + if (self == null) { + return false; + } + if (!self.isIdle()) { + return false; + } + List devices = self.getDevices(); + if (Checker.isEmpty(devices)) { + return false; + } + for (LocusParticipantDeviceModel device : devices) { + IntentModel intent = device.getIntent(); + if (intent != null && intent.getType() == LocusParticipantModel.IntentType.WAIT) { + return true; + } + } + return false; + } + + public boolean isLocalSupportDTMF() { + return getSelf() != null && getSelf().isEnableDTMF(); + } + + public boolean isRemoteAudioMuted() { + List participants = getParticipants(); + LocusSelfModel self = getSelf(); + if (participants == null || self == null) { + return true; + } + for (LocusParticipantModel participant : participants) { + if (!Checker.isEqual(participant.getId(), self.getId()) && participant.isJoined() && participant.isValidCiUser()) { + LocusParticipantStatusModel status = participant.getStatus(); + if (status != null && !LocusMediaDirection.RECVONLY.equals(status.getAudioStatus()) && !LocusMediaDirection.INACTIVE.equals(status.getAudioStatus())) { + return false; + } + } + } + return true; + } + + public String getCallUrl() { + List replaces = getReplaces(); + if (!Checker.isEmpty(replaces)) { + for (LocusReplacesModel replace : replaces) { + return replace.getLocusKey().getUrl(); + } + } + return key.getUrl(); + } + + public String getSelfId() { + LocusSelfModel self = getSelf(); + return self == null ? null : self.getId(); + } + + public String getLocalSdp() { + MediaConnectionModel mc = Checker.isEmpty(mediaConnections) ? null : mediaConnections.get(0); + if (mc == null) { + return null; + } + MediaInfoModel m = Json.fromJson(mc.getLocalSdp(), MediaInfoModel.class); + if (m == null) { + return null; + } + return m.getSdp(); + } + + public String getRemoteSdp(String deviceUrl) { + MediaConnectionModel mc = getMediaConnection(deviceUrl); + if (mc == null || mc.getRemoteSdp() == null) { + mc = getMediaConnection(null); + } + if (mc == null || mc.getRemoteSdp() == null) { + return null; + } + MediaInfoModel m = Json.fromJson(mc.getRemoteSdp(), MediaInfoModel.class); + if (m == null) { + return null; + } + return m.getSdp(); + } + + public @Nullable FloorModel getFloor() { + if (getMediaShares() != null) { + for (MediaShareModel mediaShare : getMediaShares()) { + if (MediaShareModel.SHARE_CONTENT_TYPE.equals(mediaShare.getName())) { + FloorModel floor = mediaShare.getFloor(); + if (floor != null && floor.getGranted() != null) { + return floor; + } + } + } + } + return null; + } + + public @Nullable String getMediaShareUrl() { + if (getMediaShares() != null) { + for (MediaShareModel mediaShare : getMediaShares()) { + if (MediaShareModel.SHARE_CONTENT_TYPE.equals(mediaShare.getName())) { + return mediaShare.getUrl(); + } + } + } + return null; + } + + public String getMediaId(String deviceUrl) { + MediaConnectionModel mc = getMediaConnection(deviceUrl); + return mc == null ? null : mc.getMediaId(); + } + + public String getKeepAliveUrl(String deviceUrl) { + MediaConnectionModel mc = getMediaConnection(deviceUrl); + return mc == null ? null : mc.getKeepAliveUrl(); + } + + public int getKeepAliceSecs(String deviceUrl) { + MediaConnectionModel mc = getMediaConnection(deviceUrl); + return mc == null ? -1 : mc.getKeepAliveSecs(); + } + + private MediaConnectionModel getMediaConnection(String deviceUrl) { + MediaConnectionModel ret = null; + if (deviceUrl != null) { + LocusSelfModel self = getSelf(); + if (self != null) { + List devices = self.getDevices(); + if (!Checker.isEmpty(devices)) { + for (LocusParticipantDeviceModel device : devices) { + if (Checker.isEqual(deviceUrl, device.getUrl())) { + ret = Checker.isEmpty(device.getMediaConnections()) ? null : device.getMediaConnections().get(0); + break; + } + } + } + } + } + if (ret == null) { + ret = Checker.isEmpty(mediaConnections) ? null : mediaConnections.get(0); + } + return ret; + } + + public Call.WaitReason getWaitReason() { + LocusStateModel model = getFullState(); + if (model != null && model.isActive()) { + return Call.WaitReason.WAITING_FOR_ADMITTING; + } + return Call.WaitReason.MEETING_NOT_START; + } + + public LocusModel applyDelta(LocusModel model) { + LocusModel ret = new LocusModel(); + ret.key = Objects.defaultIfNull(model.key, key); + ret.created = Objects.defaultIfNull(model.created, created); + ret.host = Objects.defaultIfNull(model.host, host); + ret.fullState = Objects.defaultIfNull(model.fullState, fullState); + ret.controls = Objects.defaultIfNull(model.controls, controls); + ret.self = Objects.defaultIfNull(model.self, self); + ret.sequence = model.sequence; + ret.baseSequence = model.baseSequence; + ret.syncUrl = model.syncUrl; + ret.mediaShares = Objects.defaultIfNull(model.mediaShares, mediaShares); + ret.replaces = Objects.defaultIfNull(model.replaces, replaces); + ret.conversationUrl = Objects.defaultIfNull(model.conversationUrl, conversationUrl); + ret.info = Objects.defaultIfNull(model.info, info); + ret.meeting = Objects.defaultIfNull(model.meeting, meeting); + ret.aclUrl = Objects.defaultIfNull(model.aclUrl, aclUrl); + ret.mediaConnections = Objects.defaultIfNull(model.mediaConnections, mediaConnections); + HashSet participants = new HashSet<>(); + if (!Checker.isEmpty(this.participants)) { + participants.addAll(this.participants); + } + if (!Checker.isEmpty(model.participants)) { + participants.addAll(model.participants); + } + ret.participants = new ArrayList<>(participants); + return ret; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantAudioControlModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantAudioControlModel.java new file mode 100644 index 00000000..e966e7db --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantAudioControlModel.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class LocusParticipantAudioControlModel { + private boolean muted; + private LocusControlMetaModel meta; + + public LocusParticipantAudioControlModel(boolean muted, LocusControlMetaModel meta) { + this.muted = muted; + this.meta = meta; + } + + public boolean isMuted() { + return muted; + } + + public LocusControlMetaModel getMeta() { + return meta; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantChallengeControlModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantChallengeControlModel.java new file mode 100644 index 00000000..e5600d73 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantChallengeControlModel.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class LocusParticipantChallengeControlModel { + private boolean challenging; + private LocusControlMetaModel meta; + + public boolean isChallenging() { + return challenging; + } + + public LocusControlMetaModel getMeta() { + return meta; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantControlsModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantControlsModel.java new file mode 100644 index 00000000..79f57895 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantControlsModel.java @@ -0,0 +1,67 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.net.Uri; + +import java.util.List; + +public class LocusParticipantControlsModel { + private Uri url; + private LocusParticipantAudioControlModel audio; + private LocusParticipantChallengeControlModel challenge; + private LocusParticipantLocalRecordControlModel localRecord; + private List links; + + + public LocusParticipantControlsModel(Uri url, List links, + LocusParticipantAudioControlModel audio, + LocusParticipantLocalRecordControlModel localRecord, + LocusParticipantChallengeControlModel challenge) { + this.url = url; + this.links = links; + this.audio = audio; + this.challenge = challenge; + this.localRecord = localRecord; + } + + public LocusParticipantAudioControlModel getAudio() { + return audio; + } + + public LocusParticipantLocalRecordControlModel getLocalRecord() { + return localRecord; + } + + public LocusParticipantChallengeControlModel getChallenge() { + return challenge; + } + + public List getLinks() { + return links; + } + + public Uri getUrl() { + return url; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantDeviceModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantDeviceModel.java new file mode 100644 index 00000000..748cf66f --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantDeviceModel.java @@ -0,0 +1,119 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class LocusParticipantDeviceModel { + + private String url; + private List mediaConnections; + private String deviceType; + private Map featureToggles; + private IntentModel intent; + private String keepAliveUrl; + private int keepAliveSecs; + private LocusParticipantModel.State state; + private String correlationId; + private boolean serverTranscoded; + private boolean serverComposed; + private LocusParticipantModel.ProvisionalDeviceType provisionalType; + private String attendeeId; + private String finalUrl; + private String provisionalUrl; + private Set requestedMedia; + + public String getUrl() { + return url; + } + + public List getMediaConnections() { + return mediaConnections; + } + + public String getDeviceType() { + return deviceType; + } + + public Map getFeatureToggles() { + return featureToggles; + } + + public IntentModel getIntent() { + return intent; + } + + public void setIntent(IntentModel intent) { + this.intent = intent; + } + + public String getKeepAliveUrl() { + return keepAliveUrl; + } + + public int getKeepAliveSecs() { + return keepAliveSecs; + } + + public LocusParticipantModel.State getState() { + return state; + } + + public String getCorrelationId() { + return correlationId; + } + + public void setCorrelationId(String correlationId) { + this.correlationId = correlationId; + } + + public String getProvisionalUrl() { + return provisionalUrl; + } + + public String getFinalUrl() { + return finalUrl; + } + + public String getAttendeeId() { + return attendeeId; + } + + public LocusParticipantModel.ProvisionalDeviceType getProvisionalType() { + return provisionalType; + } + + public boolean isServerTranscoded() { + return serverTranscoded; + } + + public boolean isServerComposed() { + return serverComposed; + } + + public Set getRequestedMedia() { + return requestedMedia; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantInfoModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantInfoModel.java new file mode 100644 index 00000000..27a59462 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantInfoModel.java @@ -0,0 +1,161 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.github.benoitdion.ln.Ln; +import me.helloworld.utils.Checker; + +public class LocusParticipantInfoModel { + + private String id; + private String email; + private String name; + private String phoneNumber; + private String sipUrl; + private String telUrl; + private String ownerId; + private String orgId; + private boolean isExternal; + private String primaryDisplayString; + private String secondaryDisplayString; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getOwnerId() { + return ownerId; + } + + public void setOwnerId(String ownerId) { + if (ownerId == null) { + this.ownerId = null; + return; + } + try { + this.ownerId = ownerId; + } catch (IllegalArgumentException exception) { + Ln.w(exception, "Wrong format for uuid"); + this.ownerId = null; + } + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public String getSipUrl() { + return sipUrl; + } + + public void setSipUrl(String sipUrl) { + this.sipUrl = sipUrl; + } + + public String getTelUrl() { + return telUrl; + } + + public void setTelUrl(String telUrl) { + this.telUrl = telUrl; + } + + public String getOrgId() { + return orgId; + } + + public void setOrgId(String orgId) { + this.orgId = orgId; + } + + + public boolean isExternal() { + return isExternal; + } + + public void setExternal(boolean external) { + isExternal = external; + } + + public String getPrimaryDisplayString() { + return primaryDisplayString; + } + + public void setPrimaryDisplayString(String primaryDisplayString) { + this.primaryDisplayString = primaryDisplayString; + } + + public String getSecondaryDisplayString() { + return secondaryDisplayString; + } + + public void setSecondaryDisplayString(String secondaryDisplayString) { + this.secondaryDisplayString = secondaryDisplayString; + } + + public String getIdOrEmail() { + return Checker.isEmpty(id) ? email : id; + } + + public String getDisplayName() { + String displayName = ""; + if (!isExternal) { + displayName = getName(); + } else { + displayName = getPrimaryDisplayString(); + } + return stripDialableProtocol(displayName); + } + + private static String stripDialableProtocol(String dialable) { + if (dialable == null) { + return null; + } + return dialable.replaceFirst("^(sip:|tel:)", ""); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantLocalRecordControlModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantLocalRecordControlModel.java new file mode 100644 index 00000000..09f055ce --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantLocalRecordControlModel.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class LocusParticipantLocalRecordControlModel { + private boolean recording; + private boolean paused; + + public LocusParticipantLocalRecordControlModel(boolean recording, boolean paused) { + this.recording = recording; + this.paused = paused; + } + + public boolean isRecording() { + return recording; + } + + public boolean isPaused() { + return paused; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantModel.java new file mode 100644 index 00000000..bdf65e36 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantModel.java @@ -0,0 +1,407 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.support.annotation.Nullable; +import com.ciscowebex.androidsdk.internal.Device; + +import java.util.*; + +public class LocusParticipantModel { + + public enum Type { + USER, ANONYMOUS, RESOURCE_ROOM, MEETING_BRIDGE, MEDIA_NODE + } + + public enum IntentType { + HELD, HOLDING, JOIN, LEAVE, MOVE_MEDIA, NONE, OBSERVE, WAIT } + + public enum State { + /* the participant is not in the locus */ + IDLE, + /* one of more devices of the participant are alerting */ + NOTIFIED, + /* the participant is in the locus */ + JOINED, + /* the participant is not in the locus */ + LEFT, + /* the participant declined to join */ + DECLINED, + /* local client state indicating we're in process of leaving locus */ + LEAVING + } + + public enum Reason { + REMOTE, + RESOURCE_BUSY, + ANSWERED_ELSEWHERE, + INVALID_PIN, + MOVED, + RESOURCE_TIMED_OUT, + NOT_FOUND, + FORCED, + INVALID_JOIN_TIME, + INTENT_CANCELED, + MEDIA_RESOURCE_RECONNECT, + INTENT_EXPIRED, + JOURNAL_TOO_LARGE, + UNKNOWN, + INACTIVE, + NOT_ACCEPTABLE, + REPLACED, + MEETING_FULL, + UNREACHABLE, + UNANSWERED, + RESOURCE_ERROR, + BUSY, + DND, + LOBBY_EXPIRED, + GARBAGE_COLLECTED, + LOGIN_REQUIRED, + MEETING_LOCKED, + CALL_MAX_DURATION, + MEETING_ENDED, + RESOURCE_DECLINED + } + + public enum ProvisionalDeviceType { + DIAL_IN("dialin"), + DIAL_OUT("dialout"); + + public final String value; + + ProvisionalDeviceType(String value) { + this.value = value; + } + } + + public enum RequestedMedia { + NONE, + AUDIO, + VIDEO, + SLIDES + } + + protected String id; + protected String url; + protected boolean isCreator; + protected LocusParticipantInfoModel person; + protected LocusParticipantModel.State state = LocusParticipantModel.State.IDLE; + protected String deviceUrl; + protected LocusParticipantModel.Type type; + protected LocusParticipantModel.Reason reason; + protected boolean guest; + protected String invitedBy; + protected List devices = new ArrayList<>(); + protected LocusParticipantStatusModel status; + protected List intents; + protected LocusParticipantControlsModel controls; + protected List suggestedMedia; + protected boolean moderator; + protected boolean resourceGuest; + protected boolean removed; + protected boolean moderatorAssignmentNotAllowed; + protected boolean hideInRoster; + + public LocusParticipantModel() { + } + + public LocusParticipantModel(String id, LocusParticipantModel.State state) { + this.id = id; + this.state = state; + } + + public String getUrl() { + return url; + } + + public String getDeviceUrl() { + return this.deviceUrl; + } + + public LocusParticipantModel.State getState() { + return this.state; + } + + public void setState(LocusParticipantModel.State state) { + this.state = state; + } + + public LocusParticipantModel.Reason getReason() { + return reason; + } + + public void setReason(LocusParticipantModel.Reason reason) { + this.reason = reason; + } + + public String getId() { + return this.id; + } + + public boolean isCreator() { + return this.isCreator; + } + + public LocusParticipantInfoModel getPerson() { + return this.person; + } + + public @Nullable + LocusParticipantModel.Type getType() { + return type; + } + + public List getDevices() { + return devices; + } + + public LocusParticipantStatusModel getStatus() { + return status; + } + + public void setStatus(LocusParticipantStatusModel newStatus) { + status = newStatus; + } + + public boolean isGuest() { + return guest; + } + + public String getInvitedBy() { + return invitedBy; + } + + public boolean isModeratorAssignmentNotAllowed() { + return moderatorAssignmentNotAllowed; + } + + public boolean isRoom() { + return LocusParticipantModel.Type.RESOURCE_ROOM == type; + } + + public boolean isJoined() { + return LocusParticipantModel.State.JOINED == state; + } + + public boolean isDeclined() { + return State.DECLINED == state; + } + + public boolean isNotified() { + return getState() == LocusParticipantModel.State.NOTIFIED; + } + + public LocusParticipantControlsModel getControls() { + return controls; + } + + public void setControls(LocusParticipantControlsModel controls) { + this.controls = controls; + } + + public boolean isModerator() { + return moderator; + } + + public void setModerator(boolean moderator) { + this.moderator = moderator; + } + + public boolean isResourceGuest() { + return resourceGuest; + } + + public boolean isRemoved() { + return removed; + } + + public boolean isWebExUser() { + return isDeviceType(Device.WEBEX_DEVICE_TYPE); + } + + public boolean isSipDevice() { + return isDeviceType(Device.SIP_DEVICE_TYPE); + } + + public boolean isDeviceType(String deviceType) { + List deviceList = this.getDevices(); + if (deviceList != null) { + for (LocusParticipantDeviceModel d : deviceList) { + if (deviceType.equalsIgnoreCase(d.getDeviceType())) { + return true; + } + } + } + return false; + } + + @Nullable + public String getRoomIdentifier() { + LocusParticipantInfoModel person = getPerson(); + if (person != null) { + return person.getId(); + } + return null; + } + + public boolean isValidCiUser() { + return (getType() == LocusParticipantModel.Type.USER && !getPerson().isExternal()) || + getType() == LocusParticipantModel.Type.RESOURCE_ROOM; + } + + public boolean isUserOrResourceRoom() { + return getType() == LocusParticipantModel.Type.USER || getType() == LocusParticipantModel.Type.RESOURCE_ROOM; + } + + public boolean isVideoMuted() { + return LocusMediaDirection.RECVONLY.equals(getStatus().getVideoStatus()); + } + + public boolean isAudioMuted() { + return isAudioLocallyMuted() || isAudioRemotelyMuted(); + } + + public boolean isAudioLocallyMuted() { + return LocusMediaDirection.RECVONLY.equals(getStatus().getAudioStatus()); + } + + public boolean isAudioRemotelyMuted() { + return getControls() != null && getControls().getAudio() != null && getControls().getAudio().isMuted(); + } + + public List getSuggestedMedia() { + return suggestedMedia; + } + + public List getIntents() { + return intents; + } + + public boolean isWaiting() { + return hasIntent(LocusParticipantModel.IntentType.WAIT); + } + + public boolean isWaitingOnDevice(String deviceUrl) { + return hasIntentOnDevice(deviceUrl, LocusParticipantModel.IntentType.WAIT); + } + + public boolean isObserving() { + return hasIntent(LocusParticipantModel.IntentType.OBSERVE); + } + + public boolean isObservingOnDevice(String deviceUrl) { + return hasIntentOnDevice(deviceUrl, LocusParticipantModel.IntentType.OBSERVE); + } + + private boolean hasIntent(LocusParticipantModel.IntentType intentType) { + for (LocusParticipantDeviceModel device : devices) { + if (device.getIntent() != null && device.getIntent().getType() != null && + device.getIntent().getType().equals(intentType)) { + return true; + } + } + return false; + } + + private boolean hasIntentOnDevice(String deviceUrl, LocusParticipantModel.IntentType intentType) { + boolean hasIntent = false; + if (devices != null && deviceUrl != null && intentType != null) { + for (LocusParticipantDeviceModel device : devices) { + if (deviceUrl.equals(device.getUrl()) && device.getIntent() != null) { + if (intentType.equals(device.getIntent().getType())) { + hasIntent = true; + } + } + } + } + + return hasIntent; + } + + public boolean isInLobby() { + return isIdle() && isWaiting(); + } + + public boolean isInLobbyOnDevice(String deviceUrl) { + return isIdle() && isWaitingOnDevice(deviceUrl); + } + + public boolean isMySelf(String myId) { + return getId().equals(myId); + } + + public boolean isHideInRoster() { + return hideInRoster; + } + + public boolean isIdle() { + return LocusParticipantModel.State.IDLE == state; + } + + public boolean isLefted(String deviceUrl) { + if (state == State.LEFT) { + return true; + } + return getDevice(deviceUrl) == null; + } + + public boolean isJoined(String deviceUrl) { + if (state != State.JOINED) { + return false; + } + LocusParticipantDeviceModel device = getDevice(deviceUrl); + return device != null && device.getState() == State.JOINED; + } + + public boolean isDeclined(String deviceUrl) { + return isDeclined() && deviceUrl.equals(getDeviceUrl()); + } + + private LocusParticipantDeviceModel getDevice(String deviceUrl) { + if (devices != null && deviceUrl != null) { + for (LocusParticipantDeviceModel device : devices) { + if (deviceUrl.equals(device.getUrl())) { + return device; + } + } + } + return null; + } + + @Override + public boolean equals(Object object) { + if (object instanceof LocusParticipantModel) { + LocusParticipantModel that = (LocusParticipantModel) object; + return this.id.equals(that.id); + } else { + return false; + } + } + + @Override + public int hashCode() { + return id.hashCode(); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantStatusModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantStatusModel.java new file mode 100644 index 00000000..18bd4d09 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusParticipantStatusModel.java @@ -0,0 +1,56 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.List; + +public class LocusParticipantStatusModel { + + public final LocusMediaDirection audioStatus; + public final LocusMediaDirection videoStatus; + public final LocusMediaDirection videoSlidesStatus; + public final List csis; + + public LocusParticipantStatusModel(LocusMediaDirection audioStatus, LocusMediaDirection videoStatus, LocusMediaDirection videoSlidesStatus, List csis) { + this.audioStatus = audioStatus; + this.videoStatus = videoStatus; + this.videoSlidesStatus = videoSlidesStatus; + this.csis = csis; + } + + public LocusMediaDirection getAudioStatus() { + return audioStatus; + } + + public LocusMediaDirection getVideoStatus() { + return videoStatus; + } + + public LocusMediaDirection getVideoSlidesStatus() { + return videoSlidesStatus; + } + + public List getCsis() { + return csis; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusRecordControlModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusRecordControlModel.java new file mode 100644 index 00000000..065cc19c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusRecordControlModel.java @@ -0,0 +1,50 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class LocusRecordControlModel { + private boolean recording; + private boolean paused; + private String errorCode; + private LocusControlMetaModel meta; + + public boolean isRecording() { + return recording; + } + + public boolean isPaused() { + return paused; + } + + public String getErrorCode() { + return errorCode; + } + + public LocusControlMetaModel getMeta() { + return meta; + } + + public boolean isAbleToRecord() { + return meta != null && !meta.isReadOnly(); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusReplacesModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusReplacesModel.java new file mode 100644 index 00000000..4ec5fc61 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusReplacesModel.java @@ -0,0 +1,49 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.Date; + +public class LocusReplacesModel { + @SerializedName("locusUrl") + private LocusKeyModel key; + private Date lastActive; + + public LocusReplacesModel() { + } + + public LocusReplacesModel(final LocusKeyModel key, final Date lastActive) { + this.key = key; + this.lastActive = lastActive; + } + + public LocusKeyModel getLocusKey() { + return key; + } + + public Date getLastActive() { + return lastActive; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusScheduledMeetingModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusScheduledMeetingModel.java new file mode 100644 index 00000000..a43a8905 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusScheduledMeetingModel.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.net.Uri; + +import java.util.Date; +import java.util.UUID; + +public class LocusScheduledMeetingModel { + private UUID organizer; + private String resourceType; + private Uri resourceUrl; + private Date startTime; + private int durationMinutes; + private boolean removed; + private String meetingId; + private String icalUid; + + public UUID getOrganizer() { + return organizer; + } + + public String getResourceType() { + return resourceType; + } + + public Uri getResourceUrl() { + return resourceUrl; + } + + public Date getStartTime() { + return startTime; + } + + public int getDurationMinutes() { + return durationMinutes; + } + + public String getIcalUid() { + return icalUid; + } + + public String getMeetingId() { + return meetingId; + } + + public boolean isRemoved() { + return removed; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusSelfModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusSelfModel.java new file mode 100644 index 00000000..df586481 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusSelfModel.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class LocusSelfModel extends LocusParticipantModel { + + private AlertTypeModel alertType; + private boolean enableDTMF; + private String mediaBaseUrl; + + public boolean isEnableDTMF() { + return enableDTMF; + } + + public String getMediaBaseUrl() { + return mediaBaseUrl; + } + + public AlertTypeModel getAlertType() { + return alertType; + } + + public void setAlertType(AlertTypeModel alertType) { + this.alertType = alertType; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusSequenceModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusSequenceModel.java new file mode 100644 index 00000000..b6b86d6c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusSequenceModel.java @@ -0,0 +1,377 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * A representation of the information needed to determine the order of loci + * + * We use the following information to determine order + * + * entries - array of long ( unique values that define the locus ) + * rangeStart - value of first entry that is not included in entries array + * rangeEnd - value of last entry that is not included in entries array + * since - value of latest locus sequence timestamp + * sequenceHash - hash of all the locus sequence timestamps since locus went active in this session + * dataCenter - data center from/on which the locusSequeceInfo was received/set + * + * If all entries are contained in the entries array, then rangeStart and rangeEnd will be 0 + * + * An empty LocusSequenceInfo will be + * + * rangeStart = 0 + * rangeEnd = 0 + * entries = {} + * since = 0 + * sequenceHash = 0 + * + */ +public class LocusSequenceModel implements Cloneable { + + public enum OverwriteWithResult { + // the value passed in is newer than the current LocusSequenceInfo + TRUE, + // the value passed in is older than or equal to the current LocusSequenceInfo + FALSE, + // there are inconsistencies between the two versions - they both contain overlapping unique values + DESYNC + } + + public enum CompareResult { + GREATER_THAN, + LESS_THAN, + EQUAL, + DESYNC + } + + public static class LocusSequenceSyncDebugModel { + + private static final String UNDEFINED = "undef"; + private static final String DEFINE = "def"; + private static final String EMPTY = "empty"; + private static final String NO_VALUE = "na"; + private static final String EQUAL = "eq"; + private static final String GREATER_THAN = "gt"; + private static final String LESS_THAN = "lt"; + private static final String CONFLICT = "cf"; + + private String base; + private String working; + private String target; + private String comparisonBaseWorking; + private String comparisonWorkingTarget; + private String comparisonBaseTarget; + + + public LocusSequenceSyncDebugModel() { + base = working = target = UNDEFINED; + comparisonBaseWorking = comparisonWorkingTarget = comparisonBaseTarget = NO_VALUE; + } + + public void initializeWorkingToTarget(LocusSequenceModel workingSequence, LocusSequenceModel targetSequence) { + working = getSequenceState(workingSequence); + target = getSequenceState(targetSequence); + comparisonWorkingTarget = getComparisonValue(LocusSequenceModel.compareTo(workingSequence, targetSequence)); + } + + public void initializeBaseToWorkingAndTarget(LocusSequenceModel baseSequence, LocusSequenceModel workingSequence, LocusSequenceModel targetSequence) { + base = getSequenceState(baseSequence); + working = getSequenceState(workingSequence); + target = getSequenceState(targetSequence); + comparisonBaseWorking = getComparisonValue(LocusSequenceModel.compareTo(baseSequence, workingSequence)); + comparisonBaseTarget = getComparisonValue(LocusSequenceModel.compareTo(baseSequence, targetSequence)); + } + + private String getSequenceState(LocusSequenceModel sequenceInfo) { + if (sequenceInfo == null) + return UNDEFINED; + else if (sequenceInfo.isEmpty()) + return EMPTY; + else + return DEFINE; + } + + private String getComparisonValue(LocusSequenceModel.CompareResult result) { + if (result == LocusSequenceModel.CompareResult.GREATER_THAN) + return GREATER_THAN; + else if (result == LocusSequenceModel.CompareResult.LESS_THAN) + return LESS_THAN; + else if (result == LocusSequenceModel.CompareResult.EQUAL) + return EQUAL; + else if (result == LocusSequenceModel.CompareResult.DESYNC) + return CONFLICT; + else + return NO_VALUE; + } + + public String build() { + return String.format("%s,%s,%s,%s,%s,%s", base, working, target, comparisonBaseWorking, comparisonWorkingTarget, comparisonBaseTarget); + } + } + + private final long[] entries; + private final long rangeStart; + private final long rangeEnd; + private long since; + private long sequenceHash; + private String dataCenter; + private int totalParticipants; + private int dirtyParticipants; + private LocusSequenceSyncDebugModel syncDebug = new LocusSequenceSyncDebugModel(); + + public LocusSequenceModel() { + this(0, 0); + } + public LocusSequenceModel(long rangeStart, long rangeEnd, long... entries) { + this(rangeStart, rangeEnd, entries, 0, 0, null); + } + public LocusSequenceModel(long rangeStart, long rangeEnd, long[] entries, long since, long sequenceHash, String dataCenter) { + this.rangeStart = rangeStart; + this.rangeEnd = rangeEnd; + this.entries = entries == null ? new long[0] : entries; + this.since = since; + this.sequenceHash = sequenceHash; + this.dataCenter = dataCenter; + } + + // see: https://sqbu-github.cisco.com/WebExSquared/cloud-apps/wiki/Locus-Sequence-Comparison-Algorithm + public static LocusSequenceModel.CompareResult compareTo(LocusSequenceModel a, LocusSequenceModel b) { + // if all of a's values are less than b's, b is newer + // if all of a's values are greater than b's, a is newer + if (a.getMax() < b.getMin()) + return LocusSequenceModel.CompareResult.LESS_THAN; + if (a.getMin() > b.getMax()) + return LocusSequenceModel.CompareResult.GREATER_THAN; + + List aOnly = new ArrayList<>(); + List bOnly = new ArrayList<>(); + populateUniqueSets(a, b, aOnly, bOnly); + + if (aOnly.isEmpty() && bOnly.isEmpty()) { + if (a.rangeEnd - a.getMin() > b.rangeEnd - b.getMin()) { + return LocusSequenceModel.CompareResult.GREATER_THAN; + } else if (a.rangeEnd - a.getMin() < b.rangeEnd - b.getMin()) { + return LocusSequenceModel.CompareResult.LESS_THAN; + } else { + return LocusSequenceModel.CompareResult.EQUAL; + } + } else if (!aOnly.isEmpty() && bOnly.isEmpty()) { + // if a has nothing unique but b does, then b is newer + return LocusSequenceModel.CompareResult.GREATER_THAN; + } else if (!bOnly.isEmpty() && aOnly.isEmpty()) { + // If b has nothing unique and a does, then a is newer + return LocusSequenceModel.CompareResult.LESS_THAN; + } else { + // both have unique + if ((a.rangeStart == 0 && b.rangeStart == 0) || areNumbersInRange(aOnly, b) || areNumbersInRange(bOnly, a)) { + return LocusSequenceModel.CompareResult.DESYNC; + } else if (aOnly.get(0) > bOnly.get(0)) { + return LocusSequenceModel.CompareResult.GREATER_THAN; + } else { + return LocusSequenceModel.CompareResult.LESS_THAN; + } + } + } + + private static boolean areNumbersInRange(List sequences, LocusSequenceModel sequenceInfo) { + long max = sequenceInfo.getMax(); + long min = sequenceInfo.getMin(); + for (Long sequence : sequences) { + if (sequence >= min && sequence <= max) { + return true; + } + } + return false; + } + + // calculate "only in a's" list and "only in b's" list + private static void populateUniqueSets(LocusSequenceModel a, LocusSequenceModel b, List ua, List ub) { + int idxa = 0, idxb = 0, lena = a.entries.length, lenb = b.entries.length; + + while (idxa < lena && idxb < lenb) { + long aval = a.entries[idxa], bval = b.entries[idxb]; + + if (aval == bval) { + idxa++; idxb++; + } else if (aval < bval) { + if (!b.inRange(aval)) + //ua.set(idxa); + ua.add(a.entries[idxa]); + idxa++; + } else { + if (!a.inRange(bval)) + //ub.set(idxb); + ub.add(b.entries[idxb]); + idxb++; + } + } + + while (idxa < lena && !b.inRange(a.entries[idxa])) { + ua.add(a.entries[idxa]); + idxa++; + } + while (idxb < lenb && !a.inRange(b.entries[idxb])) { + ub.add(b.entries[idxb]); + idxb++; + } + } + + public Long getSince() { + return since == 0 ? null : since; + } + + public Long getSequenceHash() { + return sequenceHash == 0 ? null : sequenceHash; + } + + public String getDataCenter() { + return dataCenter; + } + + public int getTotalParticipants() { + return totalParticipants; + } + + public int getDirtyParticipants() { + return dirtyParticipants; + } + + public String getSyncDebug() { + return syncDebug.build(); + } + + public boolean isEmpty() { + return (entries == null || entries.length == 0) && rangeStart == 0 && rangeEnd == 0; + } + + // apply a new Locus + public LocusSequenceModel.OverwriteWithResult overwriteWith(LocusSequenceModel newLocus) { + LocusSequenceModel.OverwriteWithResult retVal; + + // special case the empty sequence. If you are currently empty then say update no matter what + if (this.isEmpty() || newLocus.isEmpty()) { + retVal = LocusSequenceModel.OverwriteWithResult.TRUE; + } else { + LocusSequenceModel.CompareResult compareResult = compareTo(this, newLocus); + switch (compareResult) { + case GREATER_THAN: + retVal = LocusSequenceModel.OverwriteWithResult.FALSE; + break; + case LESS_THAN: + retVal = LocusSequenceModel.OverwriteWithResult.TRUE; + break; + case EQUAL: + retVal = LocusSequenceModel.OverwriteWithResult.FALSE; + break; + case DESYNC: + retVal = LocusSequenceModel.OverwriteWithResult.DESYNC; + break; + default: + retVal = LocusSequenceModel.OverwriteWithResult.TRUE; + break; + } + syncDebug.initializeWorkingToTarget(this, newLocus); + } + return retVal; + } + + // apply a Locus delta event + public LocusSequenceModel.OverwriteWithResult overwriteWith(LocusSequenceModel baseSequence, LocusSequenceModel targetSequence) { + LocusSequenceModel.OverwriteWithResult ret = this.overwriteWith(targetSequence); + if (ret == LocusSequenceModel.OverwriteWithResult.TRUE && baseSequence != null) { + LocusSequenceModel.CompareResult baselineCompare = compareTo(this, baseSequence); + switch (baselineCompare) { + case GREATER_THAN: + case EQUAL: + ret = LocusSequenceModel.OverwriteWithResult.TRUE; + break; + case LESS_THAN: + case DESYNC: + ret = LocusSequenceModel.OverwriteWithResult.DESYNC; + break; + } + syncDebug.initializeBaseToWorkingAndTarget(baseSequence, this, targetSequence); + } + return ret; + } + + private boolean inRange(long value) { + return value >= rangeStart && value <= rangeEnd; + } + + private long getMin() { + return rangeStart != 0 ? rangeStart : entries.length > 0 ? entries[0] : 0; + } + + private long getMax() { + return entries.length > 0 ? entries[entries.length - 1] : rangeEnd; + } + + @Override + public LocusSequenceModel clone() { + try { + return (LocusSequenceModel) super.clone(); + } catch (CloneNotSupportedException e) { } + return null; + } + + public boolean sequenceEqualsExact(LocusSequenceModel other) { + return rangeStart == other.rangeStart && rangeEnd == other.rangeEnd && Arrays.equals(entries, other.entries); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + LocusSequenceModel that = (LocusSequenceModel) o; + + if (rangeStart != that.rangeStart) return false; + if (rangeEnd != that.rangeEnd) return false; + if (since != that.since) return false; + if (sequenceHash != that.sequenceHash) return false; + if (totalParticipants != that.totalParticipants) return false; + if (dirtyParticipants != that.dirtyParticipants) return false; + if (!Arrays.equals(entries, that.entries)) return false; + if (dataCenter != null ? !dataCenter.equals(that.dataCenter) : that.dataCenter != null) return false; + return true; + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(entries); + result = 31 * result + (int) (rangeStart ^ (rangeStart >>> 32)); + result = 31 * result + (int) (rangeEnd ^ (rangeEnd >>> 32)); + result = 31 * result + (int) (since ^ (since >>> 32)); + result = 31 * result + (int) (sequenceHash ^ (sequenceHash >>> 32)); + result = 31 * result + (dataCenter != null ? dataCenter.hashCode() : 0); + result = 31 * result + totalParticipants; + result = 31 * result + dirtyParticipants; + return result; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusStateModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusStateModel.java new file mode 100644 index 00000000..1239f09b --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusStateModel.java @@ -0,0 +1,93 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.Date; + +public class LocusStateModel { + + public enum State { + TERMINATING, + INACTIVE, + INITIALIZING, + ACTIVE + } + + public enum Type { + CALL, + MEETING, + SIP_BRIDGE, + IVR + } + + private boolean active; + private int count; + private Date lastActive; + private LocusStateModel.State state; + private boolean startingSoon; + private LocusStateModel.Type type; + + public LocusStateModel(boolean active, int count, LocusStateModel.State state) { + this.active = active; + this.count = count; + this.state = state; + } + + public LocusStateModel(boolean active, int count, LocusStateModel.State state, LocusStateModel.Type type) { + this(active, count, state); + this.type = type; + } + + /** + * This is set to true if the locus is active + */ + public boolean isActive() { + return active || (state != null && state.equals(LocusStateModel.State.INITIALIZING)); + } + + + public LocusStateModel.State getState() { + return state; + } + + public int getCount() { + return count; + } + + public Date getLastActive() { + return lastActive; + } + + public void setLastActive(Date lastActive) { + this.lastActive = lastActive; + } + + public LocusStateModel.Type getType() { + return type; + } + + public boolean isStartingSoon() { + return startingSoon; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ListBody.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusUrlResponseModel.java similarity index 82% rename from sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ListBody.java rename to sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusUrlResponseModel.java index 69c8dd0a..a5ff401b 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ListBody.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/LocusUrlResponseModel.java @@ -20,22 +20,16 @@ * THE SOFTWARE. */ -package com.ciscowebex.androidsdk.utils.http; - -import java.util.List; +package com.ciscowebex.androidsdk.internal.model; import com.google.gson.annotations.SerializedName; -/** - * Created by zhiyuliu on 02/09/2017. - */ - -public class ListBody { +public class LocusUrlResponseModel { - @SerializedName("items") - private List _items; + @SerializedName("url") + private String locusUrl; - List getItems() { - return _items; + public String getLocusUrl() { + return this.locusUrl; } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MarkdownableModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MarkdownableModel.java new file mode 100644 index 00000000..47a5c9de --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MarkdownableModel.java @@ -0,0 +1,28 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public interface MarkdownableModel { + String getMarkdown(); + void setMarkdown(String markdown); +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaConnectionModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaConnectionModel.java new file mode 100644 index 00000000..e78ae539 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaConnectionModel.java @@ -0,0 +1,77 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class MediaConnectionModel { + private String localSdp; + private String remoteSdp; + private String type; + private String mediaId; + private String actionsUrl; + private String keepAliveUrl; + private Integer keepAliveSecs; + + public String getLocalSdp() { + return localSdp; + } + + public void setLocalSdp(String localSdp) { + this.localSdp = localSdp; + } + + public String getRemoteSdp() { + return remoteSdp; + } + + public void setRemoteSdp(String remoteSdp) { + this.remoteSdp = remoteSdp; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMediaId() { + return mediaId; + } + + public void setMediaId(String mediaId) { + this.mediaId = mediaId; + } + + public String getActionsUrl() { + return actionsUrl; + } + + public String getKeepAliveUrl() { + return keepAliveUrl; + } + + public int getKeepAliveSecs() { + return keepAliveSecs == null ? 0 : keepAliveSecs; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaEngineReachabilityModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaEngineReachabilityModel.java new file mode 100644 index 00000000..3c49ac49 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaEngineReachabilityModel.java @@ -0,0 +1,31 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.Map; + +public class MediaEngineReachabilityModel { + + public Map reachability; + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaInfoModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaInfoModel.java new file mode 100644 index 00000000..b7af7398 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaInfoModel.java @@ -0,0 +1,112 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.Map; + +public class MediaInfoModel { + + private String type; + private String sdp; + private boolean videoMuted; + private boolean audioMuted; + private boolean dtmfReceiveSupported; + private String calliopeSupplementaryInformation; + private LocusMediaDirection direction; + private Map reachability; + + public MediaInfoModel(String sdp, Map reachability) { + this(sdp, false, false, reachability); + } + + public MediaInfoModel(String sdp, boolean audioMuted, boolean videoMuted, Map reachability) { + this.sdp = sdp; + this.type = "SDP"; + this.audioMuted = audioMuted; + this.videoMuted = videoMuted; + this.reachability = reachability; + } + + public String getSdp() { + return sdp; + } + + public boolean isVideoMuted() { + return videoMuted; + } + + public void setVideoMuted(boolean videoMuted) { + this.videoMuted = videoMuted; + } + + public boolean isAudioMuted() { + return audioMuted; + } + + public void setAudioMuted(boolean audioMuted) { + this.audioMuted = audioMuted; + } + + public boolean isDtmfReceiveSupported() { + return dtmfReceiveSupported; + } + + public void setDtmfReceiveSupported(boolean dtmfReceiveSupported) { + this.dtmfReceiveSupported = dtmfReceiveSupported; + } + + public LocusMediaDirection getDirection() { + return direction; + } + + public void setDirection(LocusMediaDirection direction) { + this.direction = direction; + } + + public Map getReachability() { + return reachability; + } + + public void setReachability(Map reachability) { + this.reachability = reachability; + } + + public String getType() { + return type; + } + + @Override + public String toString() { + return "{" + + "type='" + type + '\'' + + ", sdp='" + sdp + '\'' + + ", audioMuted=" + audioMuted + + ", videoMuted=" + videoMuted + + ", dtmfReceiveSupported=" + dtmfReceiveSupported + + ", direction=" + direction + + ", calliopeSupplementaryInformation=" + "\"" + calliopeSupplementaryInformation + "\"" + + ", reachability=" + reachability + + '}'; + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaShareModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaShareModel.java new file mode 100644 index 00000000..31363272 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MediaShareModel.java @@ -0,0 +1,142 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.net.Uri; +import android.support.annotation.StringDef; +import me.helloworld.utils.Objects; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +public class MediaShareModel { + + @Retention(RetentionPolicy.SOURCE) + @StringDef({ + SHARE_CONTENT_TYPE, + SHARE_WHITEBOARD_TYPE + }) + public @interface ShareType { } + public static final String SHARE_CONTENT_TYPE = "content"; + public static final String SHARE_WHITEBOARD_TYPE = "whiteboard"; + + private String name; + private String url; + private String resourceUrl; + private FloorModel floor; + + public MediaShareModel(String name, String url, FloorModel floor) { + this.name = name; + this.url = url; + this.floor = floor; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public FloorModel getFloor() { + return floor; + } + + public void setFloor(FloorModel floor) { + this.floor = floor; + } + + public String getResourceUrl() { + return resourceUrl; + } + + public boolean isValidType() { + return isWhiteboard() || isContent(); + } + + public boolean isWhiteboard() { + return SHARE_WHITEBOARD_TYPE.equals(name); + } + + public boolean isContent() { + return SHARE_CONTENT_TYPE.equals(name); + } + + public boolean isMediaShareGranted() { + boolean result = false; + if (getFloor() != null && getFloor().getDisposition() == FloorModel.Disposition.GRANTED) { + result = true; + } + return result; + } + + public boolean isMediaShareReleased() { + return getFloor() != null && getFloor().getDisposition() == FloorModel.Disposition.RELEASED; + } + + public void setResourceUrl(Uri resourceUrl) { + this.resourceUrl = resourceUrl.toString(); + } + + public String getDisposition() { + FloorModel.Disposition ret = FloorModel.Disposition.RELEASED; + FloorModel floorModel = getFloor(); + if (floorModel != null) { + ret = Objects.defaultIfNull(floorModel.getDisposition(), ret); + } + return ret.name(); + } + + public String getRequesterUrl() { + FloorModel floor = getFloor(); + if (floor == null) { + return null; + } + LocusParticipantModel participant = floor.getRequester(); + if (participant == null) { + return null; + } + return participant.getUrl(); + } + + public String getBeneficiaryUrl() { + FloorModel floor = getFloor(); + if (floor == null) { + return null; + } + LocusParticipantModel participant = floor.getBeneficiary(); + if (participant == null) { + return null; + } + return participant.getUrl(); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MentionableModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MentionableModel.java new file mode 100644 index 00000000..412dca33 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/MentionableModel.java @@ -0,0 +1,28 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public interface MentionableModel { + ItemsModel getMentions(); + ItemsModel getGroupMentions(); +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ObjectModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ObjectModel.java new file mode 100644 index 00000000..00e5edb7 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ObjectModel.java @@ -0,0 +1,168 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.ciscowebex.androidsdk.internal.crypto.CryptoUtils; +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; +import me.helloworld.utils.Checker; + +import java.util.Date; + +public class ObjectModel { + + public static class Type { + public static final String activity = "activity"; + public static final String person = "person"; + public static final String comment = "comment"; + public static final String conversation = "conversation"; + public static final String file = "file"; + public static final String locus = "locus"; + public static final String content = "content"; + public static final String event = "event"; + public static final String locusSessionSummary = "locusSessionSummary"; + public static final String team = "team"; + public static final String microappInstance = "microappInstance"; + public static final String spaceProperty = "spaceProperty"; + public static final String groupMention = "groupMention"; + public static final String giphy = "giphy"; + public static final String link = "link"; + } + + private String id; + private String url; + private String objectType; + private Date published; + private String content; + private String displayName; + private String clientTempId; + private String kmsMessage; + + public ObjectModel(String type) { + objectType = type; + } + + public String getId() { + return id; + } + + public ObjectModel setId(String id) { + this.id = id; + return this; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getObjectType() { + return objectType; + } + + public Date getPublished() { + return published; + } + + public void setPublished(Date published) { + this.published = published; + } + + public String getContent() { + return content; + } + + public String getDisplayName() { + return displayName; + } + + public String getClientTempId() { + return clientTempId; + } + + public String getKmsMessage() { + return kmsMessage; + } + + public boolean isPerson() { + return this.objectType.equals(ObjectModel.Type.person); + } + + public boolean isConversation() { + return this.objectType.equals(ObjectModel.Type.conversation); + } + + public boolean isActivity() { + return this.objectType.equals(ObjectModel.Type.activity); + } + + public boolean isComment() { + return this.objectType.equals(ObjectModel.Type.comment); + } + + public boolean isContent() { + return this.objectType.equals(ObjectModel.Type.content); + } + + public boolean isLocus() { + return this.objectType.equals(ObjectModel.Type.locus); + } + + public boolean isEvent() { + return this.objectType.equals(ObjectModel.Type.event); + } + + public boolean isTeamObject() { + return this.objectType.equals(ObjectModel.Type.team); + } + + public boolean isLocusSessionSummary() { + return this.objectType.equals(ObjectModel.Type.locusSessionSummary); + } + + public boolean isMicroAppInstance() { + return ObjectModel.Type.microappInstance.equals(objectType); + } + + public boolean isSpaceProperty() { + return ObjectModel.Type.spaceProperty.equals(objectType); + } + + public void encrypt(KeyObject key) { + if (key != null && !Checker.isEmpty(content)) { + content = CryptoUtils.encryptToJwe(key, content); + } + } + + public void decrypt(KeyObject key) { + if (key != null && CryptoUtils.looksLikeCipherText(content)) { + content = CryptoUtils.decryptFromJwe(key, content); + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/OrganizationModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/OrganizationModel.java new file mode 100644 index 00000000..7cbd44aa --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/OrganizationModel.java @@ -0,0 +1,44 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class OrganizationModel { + private String orgId; + private String orgName; + + public String getOrgId() { + return orgId; + } + + public void setOrgId(String orgId) { + this.orgId = orgId; + } + + public String getOrgName() { + return orgName; + } + + public void setOrgName(String orgName) { + this.orgName = orgName; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/OrganizationPolicyModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/OrganizationPolicyModel.java new file mode 100644 index 00000000..9b68a09c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/OrganizationPolicyModel.java @@ -0,0 +1,70 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.net.Uri; + +public class OrganizationPolicyModel { + + private String id; + private String displayName; + private String role; + private Uri retentionUrl; + private AccessInfo access; + + public static final String OWNER_ORG_ROLE = "owner"; + public static final String PARTICIPANT_ORG_ROLE = "participant"; + + public String getId() { + return id; + } + + public String getDisplayName() { + return displayName; + } + + public String getRole() { + return role; + } + + public Uri getRetentionUrl() { + return retentionUrl; + } + + public AccessInfo getAccess() { + return access; + } + + private class AccessInfo { + private String delete; + private String read; + + public String getRead() { + return read; + } + + public String getDelete() { + return delete; + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ParentModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ParentModel.java new file mode 100644 index 00000000..52b4422b --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ParentModel.java @@ -0,0 +1,70 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.Date; + +public class ParentModel { + + private String id; + private String type; + private Date published; + private String actorId; + + public String getId() { + return id; + } + + public String getType() { + return type; + } + + public Date getPublished() { + return published; + } + + public String getActorId() { + return actorId; + } + + public void setId(String id) { + this.id = id; + } + + public void setType(String type) { + this.type = type; + } + + public void setPublished(Date published) { + this.published = published; + } + + public void setActorId(String actorId) { + this.actorId = actorId; + } + + public boolean isReply() { + return "reply".equals(this.type); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/PersonModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/PersonModel.java new file mode 100644 index 00000000..64580ee3 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/PersonModel.java @@ -0,0 +1,186 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.text.TextUtils; +import com.google.gson.annotations.SerializedName; + +import java.util.*; + +public class PersonModel extends ObjectModel { + + public static class RoomPropertiesModel { + + @SerializedName("isModerator") + private boolean moderator; + private Date lastAckDate; + private Date lastSeenActivityDate; + private String lastSeenActivityUUID; + private long lastAckTime; + + public boolean isModerator() { + return moderator; + } + + public Date getLastAckDate() { + return lastAckDate; + } + + public Date getLastSeenActivityDate() { + return lastSeenActivityDate; + } + + public String getLastSeenActivityUUID() { + return lastSeenActivityUUID; + } + public long getLastAckTime() { + return lastAckTime; + } + } + + public static final String BOT = "BOT"; + public static final String ROBOT = "ROBOT"; + public static final String PERSON = "PERSON"; + public static final String RESOURCE_ROOM = "RESOURCE_ROOM"; + public static final String LYRA_SPACE = "LYRA_SPACE"; + public static final String MACHINE = "MACHINE"; + + @SerializedName("tags") + private Set participantTagNames = new HashSet<>(); + private String orgId; + private String entryUUID; + private RoomPropertiesModel roomProperties; + private boolean isLocalContact; + private String emailAddress; + private String type; + + public PersonModel() { + super(ObjectModel.Type.person); + } + + public PersonModel(String email, String entryUUID, String displayName) { + this(); + if (TextUtils.isEmpty(email) && TextUtils.isEmpty(entryUUID)) { + throw new IllegalArgumentException("Person must have an email or actor uuid"); + } + setId(entryUUID == null ? email : entryUUID); + this.emailAddress = email; + this.entryUUID = entryUUID; + setDisplayName(displayName); + } + + public PersonModel(String emailOrUuid) { + this(); + if (TextUtils.isEmpty(emailOrUuid)) { + throw new IllegalArgumentException("Person must have an email or actor uuid"); + } + setId(emailOrUuid); + if (emailOrUuid.contains("@")) { + emailAddress = emailOrUuid; + } + else { + entryUUID = emailOrUuid; + } + } + + public PersonModel(String email, String displayName) { + this(email); + setDisplayName(displayName); + } + + @Override + public String getDisplayName() { + String displayName = super.getDisplayName(); + if (TextUtils.isEmpty(displayName)) { + displayName = getEmail(); + } + return displayName; + } + + public String getOrgId() { + return orgId; + } + + public void setOrgId(String orgId) { + this.orgId = orgId; + } + + public String getUuid() { + return entryUUID; + } + + public String getEmail() { + return emailAddress; + } + + public void setEmail(String emailAddress) { + this.emailAddress = emailAddress; + } + + public String getEmailOrUUID() { + if (!TextUtils.isEmpty(entryUUID)) { + return entryUUID; + } else { + return emailAddress; + } + } + + @Override + public String getId() { + if (TextUtils.isEmpty(getUuid())) { + return super.getId(); + } + return getUuid(); + } + + public RoomPropertiesModel getRoomProperties() { + return roomProperties; + } + + public void setUuid(String entryUUID) { + this.entryUUID = entryUUID; + if (!TextUtils.isEmpty(entryUUID)) + setId(entryUUID); + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof PersonModel)) { + return false; + } + PersonModel that = (PersonModel) o; + if (!TextUtils.isEmpty(entryUUID) && entryUUID.equals(that.entryUUID)) { + return true; + } + return !TextUtils.isEmpty(getEmail()) && getEmail().equals(that.getEmail()); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/PlaceModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/PlaceModel.java new file mode 100644 index 00000000..0d92f706 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/PlaceModel.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import me.helloworld.utils.Checker; + +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PlaceModel { + + private static final Pattern COORDINATE_PATTERN = Pattern.compile("^([+-][0-9]*\\.?[0-9]*)([+-][0-9]*\\.?[0-9]*)"); + private String displayName; + private String position; + + public String getDisplayName() { + return displayName; + } + + public String getGeoUri() { + if (Checker.isEmpty(position)) { + return null; + } + try { + Matcher matcher = COORDINATE_PATTERN.matcher(position); + matcher.find(); + float latitude = Float.parseFloat(matcher.group(1)); + float longitude = Float.parseFloat(matcher.group(2)); + // Geo uris requires the following format: ,?q=,(Label+Name) + String geoUriFormat = "geo:%.4f,%.4f?q=%.4f,%.4f(%s)"; + return String.format(Locale.US, geoUriFormat, latitude, longitude, latitude, longitude, displayName); + } catch (Exception ignore) { + return null; + } + } + + /** + * An ISO6709-formatted string identifying the position at which this + * activity occurred. For example, '+27.5916+086.5640+8850/' + */ + public String getPosition() { + return position; + } + + @Override + public String toString() { + return "Place{" + + "displayName='" + displayName + '\'' + + ", position='" + position + '\'' + + '}'; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ProviderModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ProviderModel.java new file mode 100644 index 00000000..8a4d6008 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ProviderModel.java @@ -0,0 +1,53 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import java.util.Objects; + +public class ProviderModel { + + private String id; + private String displayName; + private String machineAccountId; + + public String getDisplayName() { + return displayName; + } + + public String getMachineAccountId() { + return machineAccountId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ProviderModel provider = (ProviderModel) o; + return Objects.equals(id, provider.id); + } + + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ReachabilityModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ReachabilityModel.java new file mode 100644 index 00000000..71888644 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/ReachabilityModel.java @@ -0,0 +1,14 @@ +package com.ciscowebex.androidsdk.internal.model; + +public class ReachabilityModel { + + public static class ReachabilityTransportStatusModel { + public boolean reachable; + public long latencyInMilliseconds; + } + + public ReachabilityTransportStatusModel udp; + public ReachabilityTransportStatusModel tcp; + public ReachabilityTransportStatusModel https; + public ReachabilityTransportStatusModel xtls; +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/RegionModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/RegionModel.java new file mode 100644 index 00000000..6cb4e48a --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/RegionModel.java @@ -0,0 +1,39 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class RegionModel { + private String regionCode; + private String countryCode; + private String clientRegion; + private String clientAddress; + private String timezone; + + public String getRegionCode() { + return regionCode; + } + + public String getCountryCode() { + return countryCode; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/SpacePropertyModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/SpacePropertyModel.java new file mode 100644 index 00000000..1e73112d --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/SpacePropertyModel.java @@ -0,0 +1,80 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.HashSet; +import java.util.Set; + +public class SpacePropertyModel extends ObjectModel { + + public enum Tag { + ANNOUNCEMENT; + + public static SpacePropertyModel.Tag safeValueOf(String name) { + try { + return valueOf(name); + } catch (IllegalArgumentException e) { + return null; + } + } + } + @SerializedName("tags") + private Set tagNames; + + public SpacePropertyModel() { + super(ObjectModel.Type.spaceProperty); + tagNames = new HashSet<>(); + } + + public SpacePropertyModel(SpacePropertyModel.Tag tag) { + this(); + setTag(tag, true); + } + + public Set getTags() { + Set ret = new HashSet<>(); + for (String tagName : tagNames) { + SpacePropertyModel.Tag tag = SpacePropertyModel.Tag.safeValueOf(tagName); + if (tagName != null) { + ret.add(tag); + } + } + + return ret; + } + + public void setTag(SpacePropertyModel.Tag tag, boolean shouldExist) { + if (shouldExist) { + if (!tagNames.contains(tag.name())) + tagNames.add(tag.name()); + } else { + tagNames.remove(tag.name()); + } + } + + public boolean containsTag(SpacePropertyModel.Tag tag) { + return tagNames.contains(tag.name()); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/SuggestedMediaModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/SuggestedMediaModel.java new file mode 100644 index 00000000..2bb87bbb --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/SuggestedMediaModel.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class SuggestedMediaModel { + private String mediaType; + private String mediaContent; + private String direction; + + public String getMediaType() { + return mediaType; + } + + public String getMediaContent() { + return mediaContent; + } + + public String getDirection() { + return direction; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/TeamModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/TeamModel.java new file mode 100644 index 00000000..81d5efc3 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/TeamModel.java @@ -0,0 +1,94 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import android.text.TextUtils; +import com.ciscowebex.androidsdk.internal.crypto.CryptoUtils; +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; + +public class TeamModel extends ObjectModel { + + private String teamColor; + private String generalConversationUuid; + private String encryptionKeyUrl; // Required to post update color activities but not actually needed + + private ItemsModel conversations; + + public TeamModel() { + super(ObjectModel.Type.team); + } + + public TeamModel(String id) { + this(); + setId(id); + } + + public ItemsModel getConversations() { + return conversations; + } + + public void setConversations(ItemsModel conversations) { + this.conversations = conversations; + } + + public String getTeamColor() { + return teamColor; + } + + public void setTeamColor(String teamColor) { + this.teamColor = teamColor; + } + + public String getGeneralConversationUuid() { + return generalConversationUuid; + } + + public void setGeneralConversationUuid(String generalConversationUuid) { + this.generalConversationUuid = generalConversationUuid; + } + + public void setEncryptionKeyUrl(String encryptionKeyUrl) { + this.encryptionKeyUrl = encryptionKeyUrl; + } + + @Override + public void encrypt(KeyObject key) { + if (key == null) { + return; + } + super.encrypt(key); + encryptionKeyUrl = key.getKeyUrl(); + } + + @Override + public void decrypt(KeyObject key) { + if (key == null) { + return; + } + super.decrypt(key); + if (!TextUtils.isEmpty(getDisplayName())) { + setDisplayName(CryptoUtils.decryptFromJwe(key, getDisplayName())); + } + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/TokenModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/TokenModel.java new file mode 100644 index 00000000..a29ab669 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/TokenModel.java @@ -0,0 +1,61 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +import com.google.gson.annotations.SerializedName; + +public class TokenModel { + + public static final String AUTHENTICATION_INFO = "AUTHENTICATION_INFO"; + + @SerializedName("expires_in") + protected long expiresIn; + + @SerializedName("access_token") + protected String accessToken; + + @SerializedName("refresh_token") + protected String refreshToken; + + public TokenModel(String accessToken, long expiresIn, String refreshToken) { + this.expiresIn = expiresIn; + this.accessToken = accessToken; + this.refreshToken = refreshToken; + } + + public long getExpiresIn() { + return expiresIn; + } + + public void setExpiresIn(long expiresIn) { + this.expiresIn = expiresIn; + } + + public String getAccessToken() { + return accessToken; + } + + public String getRefreshToken() { + return refreshToken; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/UploadSessionModel.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/UploadSessionModel.java new file mode 100644 index 00000000..8acaa474 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/model/UploadSessionModel.java @@ -0,0 +1,52 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.model; + +public class UploadSessionModel { + + private String url; + private String uploadUrl; + private String finishUploadUrl; + + public UploadSessionModel() { + + } + + public UploadSessionModel(String url, String uploadUrl, String finishUploadUrl) { + this.url = url; + this.uploadUrl = uploadUrl; + this.finishUploadUrl = finishUploadUrl; + } + + public String getUrl() { + return this.url; + } + + public String getUploadUrl() { + return this.uploadUrl; + } + + public String getFinishUploadUrl() { + return this.finishUploadUrl; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/BackgroundQueue.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/BackgroundQueue.java new file mode 100644 index 00000000..68f825cc --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/BackgroundQueue.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.queue; + +import android.os.Handler; +import android.os.HandlerThread; + +import java.util.UUID; + +public class BackgroundQueue implements Queue { + + private final Handler handler; + + public BackgroundQueue() { + this(null, true); + } + + public BackgroundQueue(String name, boolean daemon) { + HandlerThread thread = new HandlerThread("Background-" + (name == null ? UUID.randomUUID().toString() : name)); + thread.setDaemon(daemon); + thread.start(); + handler = new Handler(thread.getLooper()); + } + + public void run(Runnable runnable) { + handler.post(runnable); + } + + public void yield() { + + } + + public Queue underlying() { + return this; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/MainQueue.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/MainQueue.java new file mode 100644 index 00000000..ef43bb5c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/MainQueue.java @@ -0,0 +1,49 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.queue; + +import android.os.Handler; +import android.os.Looper; + +public class MainQueue implements Queue { + + private final Handler main; + + public MainQueue() { + main = new Handler(Looper.getMainLooper()); + } + + @Override + public void run(Runnable runnable) { + main.post(runnable); + } + + @Override + public void yield() { + + } + + public Queue underlying() { + return this; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Operation.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Operation.java new file mode 100644 index 00000000..80ea09a9 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Operation.java @@ -0,0 +1,170 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.queue; + +import android.support.annotation.NonNull; +import android.text.TextUtils; +import com.github.benoitdion.ln.Ln; + +import java.util.*; +import java.util.concurrent.locks.Lock; + + +public abstract class Operation { + + public enum State { + WAITING, READY, EXECUTING, FAULTED, SUCCEEDED; + + public boolean isDone() { + return this == FAULTED || this == SUCCEEDED; + } + } + + public static Comparator ascendingStartTimeComparator = new Comparator() { + + @Override + public int compare(Operation lhs, Operation rhs) { + return Long.compare(lhs.startTime, rhs.startTime); + } + }; + + private final String operationId = UUID.randomUUID().toString(); + private volatile State state = State.READY; + private List dependsOn = new ArrayList<>(); + private long startTime = System.currentTimeMillis(); + private Lock queueLock; + private OperationQueue queue; + + @NonNull + public final String getOperationId() { + return operationId; + } + + @NonNull + public final List getDependsOn() { + return Collections.unmodifiableList(dependsOn); + } + + public final boolean setDependsOn(@NonNull Operation dependsOnOperation) { + if (dependsOn.contains(dependsOnOperation.getOperationId())) { + return false; + } + Ln.d("setDependsOn: " + this + " depends on " + dependsOnOperation); + queueLock.lock(); + try { + dependsOn.add(dependsOnOperation.getOperationId()); + cycleCheck(); + if (!dependsOnOperation.getState().isDone()) { + setState(State.WAITING); + } + return true; + } catch (CycleCheckException e) { + dependsOn.remove(dependsOnOperation.getOperationId()); + Ln.w(e, "Failed setting " + this + " depends on " + dependsOnOperation); + return false; + } finally { + queueLock.unlock(); + } + } + + @NonNull + public final State getState() { + return state; + } + + @NonNull + protected final void setState(@NonNull State state) { + State old = this.state; + queueLock.lock(); + try { + old = this.state; + this.state = state; + if (state != old && state.isDone()) { + for (Operation operation : queue.getOperations()) { + if (operation.getDependsOn().contains(getOperationId())) { + if (state == State.FAULTED) { + operation.setState(Operation.State.FAULTED); + } + queue.walk(); + } + } + } + } finally { + queueLock.unlock(); + if (state != old) { + onStateChanged(old); + } + } + } + + final void setQueue(@NonNull OperationQueue queue) { + this.queue = queue; + this.queueLock = queue.getQueueLock(); + } + + public String toString() { + return operationId + "@" + getState(); + } + + protected void onStateChanged(@NonNull State oldState) { + } + + @NonNull + abstract protected State doWork(); + + private void cycleCheck() throws CycleCheckException { + queueLock.lock(); + try { + cycleCheck(getOperationId()); + } finally { + queueLock.unlock(); + } + } + + private void cycleCheck(String rootOperationId) throws CycleCheckException { + for (String dependsOnId : dependsOn) { + Operation dependsOnOp = queue.getOperation(dependsOnId); + if (TextUtils.equals(dependsOnId, rootOperationId)) { + throw new CycleCheckException(dependsOnId, rootOperationId); + } + if (dependsOnOp != null) { + dependsOnOp.cycleCheck(rootOperationId); + } + } + } + + private static class CycleCheckException extends RuntimeException { + private static final long serialVersionUID = 3734254880311311692L; + String a; + String b; + CycleCheckException(String a, String b) { + this.a = a; + this.b = b; + } + public String toString() { + return "Cycle dependency between operations " + a + " and " + b; + } + } + +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/OperationQueue.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/OperationQueue.java new file mode 100644 index 00000000..734790ea --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/OperationQueue.java @@ -0,0 +1,247 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.queue; + +import android.support.annotation.NonNull; +import android.text.TextUtils; +import com.github.benoitdion.ln.Ln; + +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class OperationQueue { + + private static final long DEFAULT_POLL_INTERVAL = 500; + private final Map operations = new ConcurrentHashMap<>(); + private final ReentrantLock lock = new ReentrantLock(); + private ThreadPoolExecutor walkerExecutor; + private QueueWorker queueWorker; + + public OperationQueue() { + this.queueWorker = new QueueWorker(this); + } + + @NonNull + public QueueWorker getQueueWorker() { + return queueWorker; + } + + @NonNull + public Lock getQueueLock() { + return lock; + } + + public void shutdown() { + Ln.i("Shutdown OperationQueue"); + lock.lock(); + try { + getQueueWorker().shutdown(); + getWalkerExecutor().shutdownNow(); + for (Operation op : getOperations()) { + if (!op.getState().isDone()) { + Ln.d("NOT DONE : " + op); + } + } + operations.clear(); + } finally { + lock.unlock(); + } + } + + @NonNull + public List getOperations() { + lock.lock(); + try { + List ret = new ArrayList<>(operations.values()); + Collections.sort(ret, Operation.ascendingStartTimeComparator); + return ret; + } finally { + lock.unlock(); + } + } + + public Operation getOperation(@NonNull String operationId) { + if (TextUtils.isEmpty(operationId)) { + return null; + } + Operation ret = operations.get(operationId); + if (ret != null) { + return ret; + } + lock.lock(); + try { + return operations.get(operationId); + } finally { + lock.unlock(); + } + } + + public void submit(@NonNull Operation operation) { + operation.setQueue(this); + lock.lock(); + try { + operations.put(operation.getOperationId(), operation); + Operation.State state = operation.getState(); + if (state.isDone()) { + this.removeOperation(operation.getOperationId()); + } + else { + this.walk(); + } + } finally { + lock.unlock(); + } + } + + void walk() { + getWalkerExecutor().submit(new WalkTask(this)); + } + + void removeOperation(String operationId) { + lock.lock(); + try { + this.operations.remove(operationId); + } + finally { + lock.unlock(); + } + } + + private boolean hasReadyTask() { + lock.lock(); + try { + for (Operation op : operations.values()) { + if (op.getState() == Operation.State.READY) { + return true; + } + } + } finally { + lock.unlock(); + } + Ln.i("OperationQueue idle"); + return false; + } + + private ExecutorService getWalkerExecutor() { + if (walkerExecutor != null && !walkerExecutor.isShutdown()) { + return walkerExecutor; + } + lock.lock(); + try { + if (walkerExecutor == null || walkerExecutor.isShutdown()) { + ThreadFactory threadFactory = runnable -> { + Thread ret = new Thread(runnable); + ret.setDaemon(true); + ret.setName("QueueWalker"); + return ret; + }; + walkerExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1), threadFactory); + walkerExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); + } + return walkerExecutor; + } finally { + lock.unlock(); + } + } + + private static class WalkTask implements Runnable { + + private final OperationQueue queue; + private final Lock lock; + + WalkTask(OperationQueue queue) { + this.queue = queue; + this.lock = queue.getQueueLock(); + } + + @Override + public void run() { + do { + long startTime = System.currentTimeMillis(); + List operations = this.queue.getOperations(); + Ln.v("WalkQueue operation queue has %d pending operations", operations.size()); + for (Operation operation : operations) { + Ln.v("WalkQueue test operation: %s", operation); + if (operation.getState().isDone()) { + Ln.v("WalkQueue operation state was finished: %s", operation); + this.queue.removeOperation(operation.getOperationId()); + continue; + } + lock.lock(); + try { + Operation.State currentState = operation.getState(); + Operation.State newState = currentState; + if (currentState == Operation.State.WAITING || currentState == Operation.State.READY) { + List dependencie = operation.getDependsOn(); + if (!dependencie.isEmpty()) { + newState = checkDependencies(dependencie); + } + Ln.v("WalkQueue operation: %s oldState: %s newState: %s", operation, currentState, newState); + operation.setState(newState); + if (operation.getState() == Operation.State.READY) { + Ln.v("WalkQueue operation: %s should start set state EXECUTING schedule work", operation); + operation.setState(Operation.State.EXECUTING); + queue.getQueueWorker().schedule(operation); + } + } + } catch (Exception e) { + Ln.e("WalkQueue @ exception condition: %s - %s [ Operation: %s ]", e.getClass(), e.getMessage(), operation); + if (!operation.getState().isDone()) { + operation.setState(Operation.State.FAULTED); + } + } finally { + lock.unlock(); + if (operation.getState().isDone()) { + Ln.v("WalkQueue operation state was finished: %s", operation); + this.queue.removeOperation(operation.getOperationId()); + } + } + } + long duration = System.currentTimeMillis() - startTime; + try { + Thread.sleep(Math.max(0, DEFAULT_POLL_INTERVAL - duration)); + } catch (InterruptedException ignored) { + } + } while (queue.hasReadyTask()); + } + + private Operation.State checkDependencies(List dependencie) { + for (String dependsOnId : dependencie) { + Operation dependsOn = this.queue.getOperation(dependsOnId); + if (dependsOn != null && dependsOn.getState() != Operation.State.SUCCEEDED) { + Operation.State dependsOnState = dependsOn.getState(); + if (dependsOnState == Operation.State.FAULTED) { + return Operation.State.FAULTED; + } + else if (dependsOnState == Operation.State.WAITING || dependsOnState == Operation.State.READY || dependsOnState == Operation.State.EXECUTING) { + return Operation.State.WAITING; + } + } + } + return Operation.State.READY; + } + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Queue.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Queue.java new file mode 100644 index 00000000..bd5e85b2 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Queue.java @@ -0,0 +1,38 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.queue; + +public interface Queue { + + Queue main = new MainQueue(); + + Queue background = new BackgroundQueue("Default", true); + + SerialQueue serial = new SerialQueue(SerialQueue.Mode.BACKGROUND); + + void run(Runnable runnable); + + void yield(); + + Queue underlying(); +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/QueueWorker.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/QueueWorker.java new file mode 100644 index 00000000..307ba1fe --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/QueueWorker.java @@ -0,0 +1,101 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.queue; + +import com.github.benoitdion.ln.Ln; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.Lock; + +public class QueueWorker { + + private static long nextWorkerThreadIndex; + + private final OperationQueue queue; + private ExecutorService executor; + private final Lock lock; + + public QueueWorker(OperationQueue queue) { + this.queue = queue; + this.lock = queue.getQueueLock(); + } + + public void shutdown() { + this.getWorkerService().shutdownNow(); + } + + public void schedule(Operation operation) { + this.getWorkerService().submit(new WorkTask(operation)); + } + + class WorkTask implements Runnable { + + private final Operation operation; + + WorkTask(Operation operation) { + this.operation = operation; + } + + @Override + public void run() { + try { + Ln.v("Starting work task for " + operation); + if (operation.getState() != Operation.State.EXECUTING) { + Ln.d("Unexpected state [%s], aborting work task. %s", operation.getState().name(), operation); + return; + } + operation.setState(operation.doWork()); + } catch (Throwable t) { + Throwable cause = t.getCause(); + Ln.w(t, "handleException - %s - %s (%s) [ %s ] ", t.getClass(), t.getMessage(), cause != null ? cause.getMessage() : "unknown", operation); + operation.setState(Operation.State.FAULTED); + } finally { + Ln.v("Finished work task for " + operation); + if (operation.getState().isDone()) { + queue.removeOperation(operation.getOperationId()); + } + } + } + } + + private ExecutorService getWorkerService() { + if (executor != null && !executor.isShutdown()) { + return executor; + } + lock.lock(); + try { + if (executor == null || executor.isShutdown()) { + executor = Executors.newCachedThreadPool(runnable -> { + Thread ret = new Thread(runnable); + ret.setDaemon(true); + ret.setName("OperationWorker" + nextWorkerThreadIndex++); + return ret; + }); + } + return executor; + } finally { + lock.unlock(); + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Scheduler.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Scheduler.java new file mode 100644 index 00000000..02f989a5 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/Scheduler.java @@ -0,0 +1,48 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.queue; + +import java.util.Timer; +import java.util.TimerTask; + +public class Scheduler { + + private static final Timer TIMER = new Timer(true); + + public static TimerTask schedule(Runnable runnable, int interval, boolean repeat) { + TimerTask task = new TimerTask() { + @Override + public void run() { + runnable.run(); + } + }; + if (repeat) { + TIMER.schedule(task, interval, interval); + } + else { + TIMER.schedule(task, interval); + } + return task; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/SerialQueue.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/SerialQueue.java new file mode 100644 index 00000000..a16d147b --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/queue/SerialQueue.java @@ -0,0 +1,139 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.queue; + +import android.support.annotation.NonNull; +import com.github.benoitdion.ln.Ln; + +import java.util.UUID; +import java.util.concurrent.*; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +public class SerialQueue implements Queue { + + public enum Mode { + MAIN, BACKGROUND + } + + public static abstract class SerialOperation implements Runnable { + + private SerialQueue queue; + + private void setQueue(SerialQueue queue) { + this.queue = queue; + } + + protected void done() { + this.queue.yield(); + } + + } + + private static class PausableThreadPoolExecutor extends ThreadPoolExecutor { + private boolean isPaused; + private ReentrantLock pauseLock = new ReentrantLock(); + private Condition unpaused = pauseLock.newCondition(); + + private PausableThreadPoolExecutor(String uuid) { + super(1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingDeque<>(), r -> { + Thread ret = new Thread(r); + ret.setDaemon(true); + ret.setName("SerialQueue-Waiting-" + uuid); + return ret; + }); + } + + protected void beforeExecute(Thread t, Runnable r) { + super.beforeExecute(t, r); + pauseLock.lock(); + try { + while (isPaused) unpaused.await(); + } catch(InterruptedException ie) { + t.interrupt(); + } finally { + pauseLock.unlock(); + } + } + + public void pause() { + pauseLock.lock(); + try { + isPaused = true; + } finally { + pauseLock.unlock(); + } + } + + public void resume() { + pauseLock.lock(); + try { + isPaused = false; + unpaused.signalAll(); + } finally { + pauseLock.unlock(); + } + } + } + + private final SerialQueue.Mode type; + + private Queue queue; + + private final PausableThreadPoolExecutor picker; + + public SerialQueue(@NonNull Mode type) { + String id = UUID.randomUUID().toString(); + this.type = type; + this.picker = new PausableThreadPoolExecutor(id); + if (type == Mode.MAIN) { + queue = new MainQueue(); + } + else { + queue = new BackgroundQueue("Serial-" + id, true); + } + } + + public void run(Runnable task) { + Ln.d("SerialQueue pasue: %s, size: %s, task: %s", picker.isPaused, picker.getQueue().size(), task); + picker.execute(() -> { + Ln.d("SerialQueue execute task: %s, pasue: %s, size: %s", task, picker.isPaused, picker.getQueue().size()); + picker.pause(); + queue.run(task); + }); + } + + public void run(SerialOperation operation) { + operation.setQueue(this); + run((Runnable) operation); + } + + public void yield() { + picker.resume(); + } + + public Queue underlying() { + return queue; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java new file mode 100644 index 00000000..ceb1b621 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java @@ -0,0 +1,208 @@ +package com.ciscowebex.androidsdk.internal.reachability; + +import android.app.Application; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.BatteryManager; +import android.os.PowerManager; +import com.ciscowebex.androidsdk.BuildConfig; +import com.ciscowebex.androidsdk.internal.queue.Scheduler; +import com.ciscowebex.androidsdk.phone.Phone; +import com.ciscowebex.androidsdk.utils.LoggingLock; +import com.github.benoitdion.ln.Ln; + +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; + +public class BackgroundChecker implements NetworkReachability.NetworkReachabilityObserver{ + + public interface BackgroundListener { + void onTransition(boolean foreground); + } + + private final Context context; + private final PowerManager powerManager; + private final LoggingLock syncLock = new LoggingLock(BuildConfig.DEBUG, "BackgroundCheck"); + private final Condition activenessCondition = syncLock.newCondition(); + private boolean running = false; + private boolean isInactive = true; + + private final NetworkReachability network; + private final BackgroundListener listener; + private TimerTask checker; + + public BackgroundChecker(Application application, BackgroundListener listener) { + this.context = application; + this.powerManager = (PowerManager) this.context.getSystemService(Context.POWER_SERVICE);; + this.listener = listener; + this.network = new NetworkReachability(context, this); + application.registerReceiver(this.network, NetworkReachability.getIntentFilter()); + } + + public void start() { + syncLock.lock(); + try { + running = true; + network.start(); + foregroundActivityDetected(); + } finally { + syncLock.unlock(); + } + } + + public void stop() { + syncLock.lock(); + try { + running = false; + cancelChecker(); + } finally { + syncLock.unlock(); + } + } + + @Override + public void onReachabilityChanged(boolean connected) { + Ln.d("Network reachability changed:, in background = %s networkIsConnected = %s", isInBackground(), connected); + if (waitForActiveState(0)) { + if (connected) { + Ln.d("Network connected. Resetting status"); + listener.onTransition(true); + } else { + Ln.d("Connectivity lost."); + listener.onTransition(false); + } + } + } + + @Override + public void onConfigurationChanged(boolean isProxyChanged) { + Ln.d("Network configuration changed: " + isProxyChanged); + } + + public boolean tryForeground() { + boolean ret = false; + syncLock.lock(); + try { + if (isInactive()) { + listener.onTransition(true); + Ln.i("TRY BG->FG: transition"); + isInactive = false; + activenessCondition.signalAll(); + ret = true; + } + + } finally { + syncLock.unlock(); + } + logBatteryStatus(); + return ret; + } + + public boolean tryBackground() { + boolean ret = false; + syncLock.lock(); + try { + if (isInBackground()) { + isInactive = true; + Ln.i("TRY FG->BG: transition"); + listener.onTransition(false); + ret = true; + } + } + finally { + syncLock.unlock(); + } + logBatteryStatus(); + return ret; + } + + private void foregroundActivityDetected() { + Ln.d("ForegroundActivityDetected"); + syncLock.lock(); + try { + if (isInactive()) { + listener.onTransition(true); + Ln.i("BG->FG: transition"); + isInactive = false; + activenessCondition.signalAll(); + } + if (isInBackground()) { + isInactive = true; + Ln.i("FG->BG: transition"); + listener.onTransition(false); + } + cancelChecker(); + checker = Scheduler.schedule(() -> { + Ln.d("ForegroundActivityDetected: " + isInBackground()); + if (isInBackground()) { + isInactive = true; + Ln.d("FG->BG: transition"); + listener.onTransition(false); + } else { + if (!running) { + cancelChecker(); + } else { + foregroundActivityDetected(); + } + } + }, 10000, true); + } finally { + syncLock.unlock(); + } + logBatteryStatus(); + } + + private void cancelChecker() { + if (checker != null) { + checker.cancel(); + checker = null; + } + } + + public boolean isInBackground() { + boolean isInForeground = ForegroundChecker.getInstance().isForeground(); + boolean isDeviceInteractive = (powerManager == null || powerManager.isInteractive()); + Ln.d("isInForeground = %b, isDeviceInteractive = %b", isInForeground, isDeviceInteractive); + return (!isDeviceInteractive || !isInForeground); + } + + private boolean isInactive() { + return isInactive; + } + + private boolean waitForActiveState(long msTimeToWait) { + if (!isInactive()) { + return true; + } + syncLock.lock(); + try { + if (!isInactive()) { + return true; + } + activenessCondition.await(msTimeToWait, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + syncLock.unlock(); + } + return !isInactive(); + } + + private void logBatteryStatus() { + try { + Intent batteryStatus = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + if (batteryStatus != null) { + int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL; + int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); + int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + int batteryPct = (int) (100 * level / (float) scale); + Ln.i("Battery percentage = %d, charging = %b", batteryPct, isCharging); + } + } catch (Exception ex) { + Ln.w(ex); + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ForegroundChecker.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ForegroundChecker.java new file mode 100644 index 00000000..2ed644a7 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ForegroundChecker.java @@ -0,0 +1,76 @@ +package com.ciscowebex.androidsdk.internal.reachability; + +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; +import android.os.Handler; +import com.github.benoitdion.ln.Ln; + +public class ForegroundChecker implements Application.ActivityLifecycleCallbacks { + + private static ForegroundChecker instance; + private boolean foreground = false, paused = true; + private Handler handler = new Handler(); + private Runnable check; + + public static void init(android.app.Application app) { + if (instance == null) { + instance = new ForegroundChecker(); + instance.onActivityResumed(null); + app.registerActivityLifecycleCallbacks(instance); + } + } + + public static ForegroundChecker getInstance() { + return instance; + } + + private ForegroundChecker() { } + + public boolean isForeground() { + return foreground; + } + + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + } + + public void onActivityStarted(Activity activity) { + } + + public void onActivityResumed(Activity activity) { + Ln.d("onActivityResumed"); + foreground = true; + paused = false; + if (check != null) + handler.removeCallbacks(check); + } + + public void onActivityPaused(Activity activity) { + Ln.d("onActivityPaused"); + paused = true; + if (check != null) { + handler.removeCallbacks(check); + } + handler.postDelayed(check = () -> { + if (foreground && paused) { + foreground = false; + } + }, 500); + } + + @Override + public void onActivityStopped(Activity activity) { + + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkConnectionStatus.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkConnectionStatus.java new file mode 100644 index 00000000..86c5db2b --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkConnectionStatus.java @@ -0,0 +1,106 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.internal.reachability; + +public class NetworkConnectionStatus { + private int networkType = -1; + private String ipAddress; + private boolean isBehindProxy = false; + private boolean isConnected = false; + private boolean proxyRequiresAuth = false; + + public NetworkConnectionStatus(boolean isConnected) { + this.isConnected = isConnected; + } + + public NetworkConnectionStatus(boolean isConnected, boolean proxyRequiresAuth, int networkType, String ipAddress, boolean isBehindProxy) { + this.isConnected = isConnected; + this.proxyRequiresAuth = proxyRequiresAuth; + this.networkType = networkType; + this.ipAddress = ipAddress; + this.isBehindProxy = isBehindProxy; + } + + public int getNetworkType() { + return networkType; + } + + public void setNetworkType(int networkType) { + this.networkType = networkType; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public boolean isBehindProxy() { + return isBehindProxy; + } + + public void setBehindProxy(boolean behindProxy) { + isBehindProxy = behindProxy; + } + + public boolean isConnected() { + return isConnected; + } + + public void setConnected(boolean connected) { + isConnected = connected; + } + + public boolean isProxyRequiresAuth() { + return proxyRequiresAuth; + } + + public void setProxyRequiresAuth(boolean proxyRequiresAuth) { + this.proxyRequiresAuth = proxyRequiresAuth; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + NetworkConnectionStatus that = (NetworkConnectionStatus) o; + return (isConnected == that.isConnected) + && (networkType == that.networkType) + && (ipAddress != null && ipAddress.equalsIgnoreCase(that.ipAddress)) + && (isBehindProxy == that.isBehindProxy); + } + + public boolean isProxyChanged(NetworkConnectionStatus other) { + if (other == null) + return false; + // proxy change detect 1) on => off 2) off => on 3) on => on but different proxy (different ip address) + return (isBehindProxy != other.isBehindProxy) || (isBehindProxy && other.isBehindProxy && (ipAddress != null && !ipAddress.equalsIgnoreCase(other.ipAddress))); + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java new file mode 100644 index 00000000..d21565e7 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java @@ -0,0 +1,138 @@ +package com.ciscowebex.androidsdk.internal.reachability; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiManager; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.queue.Scheduler; +import com.ciscowebex.androidsdk.utils.NetworkUtils; +import com.github.benoitdion.ln.Ln; +import okhttp3.*; + +import java.io.IOException; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.URI; +import java.util.List; +import java.util.TimerTask; + +public class NetworkReachability extends BroadcastReceiver { + + public interface NetworkReachabilityObserver { + void onReachabilityChanged(boolean connected); + void onConfigurationChanged(boolean isProxyChanged); + } + + private final NetworkReachabilityObserver observer; + private final ConnectivityManager connectivityManager; + private NetworkConnectionStatus currentNetworkConnectionStatus = new NetworkConnectionStatus(false); + private TimerTask updateNetworkState; + + public NetworkReachability(Context context, NetworkReachabilityObserver observer) { + this.connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);; + this.observer = observer; + } + + public void onReceive(Context context, Intent intent) { + update(); + } + + public static IntentFilter getIntentFilter() { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + intentFilter.addAction(android.net.Proxy.PROXY_CHANGE_ACTION); + return intentFilter; + } + + public void start() { + update(); + } + + public boolean isNetworkConnected() { + if (currentNetworkConnectionStatus.isConnected()) { + NetworkInfo info = connectivityManager.getActiveNetworkInfo(); + return info != null && info.isConnected(); + } + return false; + } + + public boolean isBehindProxy() { + return ProxySelector.getDefault().select(URI.create(Service.Wdm.endpoint(null) + "/ping")).get(0) != Proxy.NO_PROXY; + } + + public void update() { + if (updateNetworkState != null) { + updateNetworkState.cancel(); + } + updateNetworkState = Scheduler.schedule(this::asyncUpdateNetworkConnectivity, 20000, true); + } + + public NetworkInfo getNetworkInfo() { + return connectivityManager.getActiveNetworkInfo(); + } + + protected void asyncUpdateNetworkConnectivity() { + boolean oldIsConnected = currentNetworkConnectionStatus.isConnected(); + NetworkInfo info = connectivityManager.getActiveNetworkInfo(); + + if (info == null) { + currentNetworkConnectionStatus = new NetworkConnectionStatus(false); + if (oldIsConnected) { + observer.onReachabilityChanged(false); + } + return; + } + + boolean isConnected = info.isConnected(); + if (isConnected) { + boolean currentIsBehindProxy = false; + if (isBehindProxy()) { + currentIsBehindProxy = true; + OkHttpClient client = new OkHttpClient().newBuilder().proxyAuthenticator(new ProxyCheckAuthenticator()).build(); + Request request = new Request.Builder().url(Service.Wdm.endpoint(null) + "/").build(); + try { + Response response = client.newCall(request).execute(); + Ln.d("response.code() = " + response.code()); + } catch (IOException ex) { + Ln.d("proxyRequiresAuth: " + currentNetworkConnectionStatus.isProxyRequiresAuth()); + } + } + int currentNetworkType = info.getType(); + String currentIPAddress = NetworkUtils.getLocalIpAddress(); + NetworkConnectionStatus oldNetworkConnectionStatus = currentNetworkConnectionStatus; + currentNetworkConnectionStatus = new NetworkConnectionStatus(isConnected, oldNetworkConnectionStatus.isProxyRequiresAuth(), currentNetworkType, currentIPAddress, currentIsBehindProxy); + if (oldIsConnected && !currentNetworkConnectionStatus.equals(oldNetworkConnectionStatus)) { + observer.onConfigurationChanged(currentNetworkConnectionStatus.isProxyChanged(oldNetworkConnectionStatus)); + } + } else { + currentNetworkConnectionStatus = new NetworkConnectionStatus(isConnected); + } + + if (oldIsConnected != isConnected) { + Ln.i("Different start and end states, sending event"); + observer.onReachabilityChanged(isConnected); + } + } + + private class ProxyCheckAuthenticator implements Authenticator { + + @Override + public Request authenticate(Route route, Response response) { + currentNetworkConnectionStatus.setProxyRequiresAuth(true); + List headers = response.headers("Proxy-Authenticate"); + Ln.d("Proxy-Authenticate Headers:\n%s", headers); + ProxyHelpers.ProxyAutheticationMethod choosenMethod = ProxyHelpers.chooseAuthenticationMethod(headers); + if (null == choosenMethod) { + Ln.d("Unknown proxy authetication method."); + } + return null; + } + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ProxyHelpers.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ProxyHelpers.java new file mode 100644 index 00000000..1d48c421 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ProxyHelpers.java @@ -0,0 +1,196 @@ +package com.ciscowebex.androidsdk.internal.reachability; + +import com.ciscowebex.androidsdk.utils.Utils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ProxyHelpers { + public enum ProxyAutheticationMethod { + PROXY_AUTH_BASIC("Basic"), + PROXY_AUTH_DIGEST("Digest"), + PROXY_AUTH_NTLM("NTLM"); + + private String type; + + ProxyAutheticationMethod(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public static ProxyAutheticationMethod fromString(String text) { + for (ProxyAutheticationMethod method : ProxyAutheticationMethod.values()) { + if (method.type.equals(text)) { + return method; + } + } + return null; + } + } + + public static String authenticateHeaderForType(List headers, ProxyAutheticationMethod type) { + String foundHeader = null; + + if (headers.size() == 1) { + foundHeader = parseSingleHeader(headers.get(0), type); + } else { + for (String currentHeader : headers) { + if (currentHeader.startsWith(type.getType())) { + foundHeader = currentHeader; + break; + } + } + } + + return foundHeader; + } + + public static ProxyAutheticationMethod chooseAuthenticationMethod(List availableAuthenticationHeaders) { + List methods = new ArrayList<>(); + + if (availableAuthenticationHeaders.size() > 1) { + for (String authenticationHeader : availableAuthenticationHeaders) { + ProxyAutheticationMethod method = authenticationMethod(authenticationHeader); + + if (method != null) { + methods.add(method); + } + } + } else { + String header = availableAuthenticationHeaders.get(0); + + if (header != null) { + String[] parts = header.split(", "); + + for (String part : parts) { + ProxyAutheticationMethod method = authenticationMethod(part); + + if (method != null) { + methods.add(method); + } + } + } + } + + if (methods.contains(ProxyAutheticationMethod.PROXY_AUTH_NTLM)) { + return ProxyAutheticationMethod.PROXY_AUTH_NTLM; + } else if (methods.contains(ProxyAutheticationMethod.PROXY_AUTH_DIGEST)) { + return ProxyAutheticationMethod.PROXY_AUTH_DIGEST; + } else if (methods.contains(ProxyAutheticationMethod.PROXY_AUTH_BASIC)) { + return ProxyAutheticationMethod.PROXY_AUTH_BASIC; + } else { + return null; + } + } + + + private static ProxyAutheticationMethod authenticationMethod(String authenticateHeader) { + String[] parts = authenticateHeader.split(" "); + + return ProxyAutheticationMethod.fromString(parts[0]); + } + + /* + * Split a single Proxy-Authenticate header into multiple headers, and return a specific header based on type. + * + *

+ * Webservers or Proxy servers can choose to send proxy information as either multiple headers or one header joined + * by commas. Conversely the receiving side may design to combine multiple headers into a single header. + * As such the code below handles the former when a server sends back a single header but has multiple items in it. + * Examples: + * Proxy-Authenticate: Kerberos + * Proxy-Authenticate: NTLM + * + * OR + * + * Proxy-Authenticate: Kerberos, NTLM + *

+ * + * @param original Original Header we want to split up. + * @param type Authentication type we want + * @return Full authentication header for the type specified, or null if not found. + */ + public static String parseSingleHeader(String original, ProxyAutheticationMethod type) { + /* + * Regular Expression Matches: + * "word" - Just an auth type. + * "word key=" - Auth type with key value pairs + * "word abxcfg+/=" - Auth type with base 64 encoded data + */ + Pattern regEx = Pattern.compile("(\\w+)\\s[\\w+\\/=]+="); + + /* + * Take original header and seperate on ", " + * Giving an array of: + * [ + * "Kerberos", + * "NTLM", + * "Digest realm=\"Hello\"", + * "key=\"value\"", + * "key2=\"value2\"", + * "Basic realm=\"Hello"\"" + * ] + */ + String[] parts = original.split(", "); + Map headers = new HashMap<>(); + List components = new ArrayList<>(); + String authType = null; + + /* + * Iterate over all the parts and process them. + */ + for (String part : parts) { + Matcher ranges = regEx.matcher(part); + + /* + * If part matches regular expression we have the start of a header. + * There is possibly more data that needs to be tacked on. + */ + if (ranges.find()) { + /* + * The first capturing group in the regular expression is the auth type. + */ + String newAuthType = ranges.group(1); + + if (components.size() > 0) { // We already have a header combine it back into a single string + if (authType == null) { // If this is the first authType we have seen set authType to avoid NPE + authType = newAuthType; + } + + String header = Utils.join(", ", components); + headers.put(authType, header); // Store the header + components = new ArrayList<>(); // Reset the components + + } + + /* + * Start storing header components for latter. + */ + authType = newAuthType; + components.add(part); + } else if (part.contains("=")) { // This is a key value pair stash it away for latter + components.add(part); + } else { // Just a plan header, its authType = part + headers.put(part, part); + } + } + + /* + * Finished processing parts, combine left overs into a single header + */ + if (components.size() > 0) { + String lastHeader = Utils.join(", ", components); + headers.put(authType, lastHeader); + } + + return headers.get(type.getType()); // Return the header we want. + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/Membership.java b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/Membership.java index d15fe49a..63d64c33 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/Membership.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/Membership.java @@ -24,11 +24,9 @@ import java.util.Date; -import com.cisco.spark.android.model.ParticipantRoomProperties; -import com.cisco.spark.android.model.Person; -import com.cisco.spark.android.model.Verb; -import com.cisco.spark.android.model.conversation.Activity; -import com.cisco.spark.android.model.conversation.Conversation; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; +import com.ciscowebex.androidsdk.internal.model.ConversationModel; +import com.ciscowebex.androidsdk.internal.model.PersonModel; import com.ciscowebex.androidsdk.utils.WebexId; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; @@ -68,14 +66,14 @@ public class Membership { @SerializedName("created") private Date _created; - protected Membership(Conversation conversation, Person person) { + protected Membership(ConversationModel conversation, PersonModel person) { _id = new WebexId(WebexId.Type.MEMBERSHIP_ID, person.getId() + ":" + conversation.getId()).toHydraId(); _spaceId = new WebexId(WebexId.Type.ROOM_ID, conversation.getId()).toHydraId(); _personId = new WebexId(WebexId.Type.PEOPLE_ID, person.getId()).toHydraId(); _personEmail = person.getEmail(); _personDisplayName = person.getDisplayName(); _personOrgId = new WebexId(WebexId.Type.ORGANIZATION_ID, person.getOrgId()).toHydraId(); - ParticipantRoomProperties roomProperties = person.getRoomProperties(); + PersonModel.RoomPropertiesModel roomProperties = person.getRoomProperties(); if (roomProperties != null) { _isModerator = roomProperties.isModerator(); _isMonitor = _isModerator; @@ -83,18 +81,18 @@ protected Membership(Conversation conversation, Person person) { _created = null; // created is not available in the conversations payload } - protected Membership(Activity activity) { + protected Membership(ActivityModel activity) { this._created = activity.getPublished(); - if (activity.getVerb().equals(Verb.hide)) { + if (activity.getVerb() == ActivityModel.Verb.hide) { this._spaceId = new WebexId(WebexId.Type.ROOM_ID, activity.getObject().getId()).toHydraId(); } else { this._spaceId = new WebexId(WebexId.Type.ROOM_ID, activity.getTarget().getId()).toHydraId(); } - Person person = null; - if (activity.getVerb().equals(Verb.acknowledge)) { + PersonModel person = null; + if (activity.getVerb() == ActivityModel.Verb.acknowledge) { person = activity.getActor(); - } else if (activity.getObject() instanceof Person) { - person = (Person) activity.getObject(); + } else if (activity.getObject() instanceof PersonModel) { + person = (PersonModel) activity.getObject(); } if (null != person) { this._id = new WebexId(WebexId.Type.MEMBERSHIP_ID, person.getId() + ":" + WebexId.translate(this._spaceId)).toHydraId(); diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/MembershipObserver.java b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/MembershipObserver.java index b75e1c92..ad69bd84 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/MembershipObserver.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/MembershipObserver.java @@ -22,8 +22,8 @@ package com.ciscowebex.androidsdk.membership; -import com.cisco.spark.android.model.conversation.Activity; import com.ciscowebex.androidsdk.WebexEvent; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; /** * Callback to receive the events from a {@link MembershipClient}. @@ -45,7 +45,7 @@ class MembershipCreated extends WebexEvent.Base implements MembershipEvent { private Membership membership; - protected MembershipCreated(Membership membership, Activity activity) { + protected MembershipCreated(Membership membership, ActivityModel activity) { super(activity); this.membership = membership; } @@ -65,7 +65,7 @@ class MembershipDeleted extends WebexEvent.Base implements MembershipEvent { private Membership membership; - protected MembershipDeleted(Membership membership, Activity activity) { + protected MembershipDeleted(Membership membership, ActivityModel activity) { super(activity); this.membership = membership; } @@ -85,7 +85,7 @@ class MembershipUpdated extends WebexEvent.Base implements MembershipEvent { private Membership membership; - protected MembershipUpdated(Membership membership, Activity activity) { + protected MembershipUpdated(Membership membership, ActivityModel activity) { super(activity); this.membership = membership; } @@ -106,7 +106,7 @@ class MembershipMessageSeen extends WebexEvent.Base implements MembershipEvent { private Membership membership; private String lastSeenMessageId; - protected MembershipMessageSeen(Membership membership, Activity activity, String lastSeenMessageId) { + protected MembershipMessageSeen(Membership membership, ActivityModel activity, String lastSeenMessageId) { super(activity); this.membership = membership; this.lastSeenMessageId = lastSeenMessageId; diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/MembershipReadStatus.java b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/MembershipReadStatus.java index 3a88854d..ada44ffe 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/MembershipReadStatus.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/MembershipReadStatus.java @@ -22,9 +22,8 @@ package com.ciscowebex.androidsdk.membership; -import com.cisco.spark.android.model.ParticipantRoomProperties; -import com.cisco.spark.android.model.Person; -import com.cisco.spark.android.model.conversation.Conversation; +import com.ciscowebex.androidsdk.internal.model.ConversationModel; +import com.ciscowebex.androidsdk.internal.model.PersonModel; import com.ciscowebex.androidsdk.utils.WebexId; import com.ciscowebex.androidsdk.message.Message; @@ -43,8 +42,8 @@ public class MembershipReadStatus { private Date _lastSeenDate; - protected MembershipReadStatus(Conversation conversation, Person person) throws IllegalArgumentException { - ParticipantRoomProperties roomProperties = person.getRoomProperties(); + protected MembershipReadStatus(ConversationModel conversation, PersonModel person) throws IllegalArgumentException { + PersonModel.RoomPropertiesModel roomProperties = person.getRoomProperties(); if (roomProperties == null) { throw new IllegalArgumentException("RoomProperties is null"); } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/InternalMembership.java b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/InternalMembership.java index e073eec1..699aebcd 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/InternalMembership.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/InternalMembership.java @@ -1,36 +1,58 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.membership.internal; -import com.cisco.spark.android.model.conversation.Activity; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; import com.ciscowebex.androidsdk.membership.Membership; import com.ciscowebex.androidsdk.membership.MembershipObserver; class InternalMembership extends Membership { static class InternalMembershipCreated extends MembershipObserver.MembershipCreated { - InternalMembershipCreated(Membership membership, Activity activity) { + InternalMembershipCreated(Membership membership, ActivityModel activity) { super(membership, activity); } } static class InternalMembershipDeleted extends MembershipObserver.MembershipDeleted { - InternalMembershipDeleted(Membership membership, Activity activity) { + InternalMembershipDeleted(Membership membership, ActivityModel activity) { super(membership, activity); } } static class InternalMembershipUpdated extends MembershipObserver.MembershipUpdated { - InternalMembershipUpdated(Membership membership, Activity activity) { + InternalMembershipUpdated(Membership membership, ActivityModel activity) { super(membership, activity); } } static class InternalMembershipMessageSeen extends MembershipObserver.MembershipMessageSeen { - InternalMembershipMessageSeen(Membership membership, Activity activity, String messageId) { + InternalMembershipMessageSeen(Membership membership, ActivityModel activity, String messageId) { super(membership, activity, messageId); } } - InternalMembership(Activity activity) { + InternalMembership(ActivityModel activity) { super(activity); } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/InternalMembershipReadStatus.java b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/InternalMembershipReadStatus.java index a757590a..2fe779c6 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/InternalMembershipReadStatus.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/InternalMembershipReadStatus.java @@ -1,12 +1,34 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.membership.internal; -import com.cisco.spark.android.model.Person; -import com.cisco.spark.android.model.conversation.Conversation; +import com.ciscowebex.androidsdk.internal.model.ConversationModel; +import com.ciscowebex.androidsdk.internal.model.PersonModel; import com.ciscowebex.androidsdk.membership.MembershipReadStatus; class InternalMembershipReadStatus extends MembershipReadStatus { - InternalMembershipReadStatus(Conversation conversation, Person person) { + InternalMembershipReadStatus(ConversationModel conversation, PersonModel person) { super(conversation, person); } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/MembershipClientImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/MembershipClientImpl.java index 3000ad4b..cc7a6523 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/MembershipClientImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/membership/internal/MembershipClientImpl.java @@ -23,199 +23,150 @@ package com.ciscowebex.androidsdk.membership.internal; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import java.util.Map; -import android.content.Context; -import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.cisco.spark.android.authenticator.ApiTokenProvider; -import com.cisco.spark.android.core.ApiClientProvider; -import com.cisco.spark.android.model.Person; -import com.cisco.spark.android.model.Verb; -import com.cisco.spark.android.model.conversation.Activity; -import com.cisco.spark.android.model.conversation.Conversation; -import com.cisco.spark.android.processing.ActivityListener; import com.ciscowebex.androidsdk.CompletionHandler; -import com.ciscowebex.androidsdk.auth.Authenticator; -import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.*; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; +import com.ciscowebex.androidsdk.internal.model.ConversationModel; +import com.ciscowebex.androidsdk.internal.model.PersonModel; import com.ciscowebex.androidsdk.membership.Membership; import com.ciscowebex.androidsdk.membership.MembershipClient; import com.ciscowebex.androidsdk.membership.MembershipObserver; import com.ciscowebex.androidsdk.membership.MembershipReadStatus; +import com.ciscowebex.androidsdk.phone.internal.PhoneImpl; import com.ciscowebex.androidsdk.utils.WebexId; -import com.ciscowebex.androidsdk.utils.http.ListBody; -import com.ciscowebex.androidsdk.utils.http.ListCallback; -import com.ciscowebex.androidsdk.utils.http.ObjectCallback; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; +import com.ciscowebex.androidsdk.internal.model.ItemsModel; -import com.ciscowebex.androidsdk_commlib.SDKCommonInjector; -import com.github.benoitdion.ln.Ln; +import com.google.gson.reflect.TypeToken; import me.helloworld.utils.collection.Maps; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.GET; -import retrofit2.http.Header; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; -import retrofit2.http.Query; -import javax.inject.Inject; +public class MembershipClientImpl implements MembershipClient, ActivityListener { -public class MembershipClientImpl implements MembershipClient { + private PhoneImpl phone; + private MembershipObserver observer; - private Authenticator _authenticator; - - private MembershipService _service; - - private MembershipObserver _observer; - - private Context _context; - - @Inject - ActivityListener activityListener; - - @Inject - ApiTokenProvider _provider; - - @Inject - ApiClientProvider _client; - - public MembershipClientImpl(Context context, Authenticator authenticator, SDKCommonInjector injector) { - injector.inject(this); - _authenticator = authenticator; - _service = new ServiceBuilder().build(MembershipService.class); - _context = context; - activityListener.register(activity -> { - processorActivity(activity); - return null; - }); + public MembershipClientImpl(PhoneImpl phone) { + this.phone = phone; } @Override public void setMembershipObserver(MembershipObserver observer) { - _observer = observer; + this.observer = observer; + } + + public void processActivity(@NonNull ActivityModel activity) { + if (observer == null) { + return; + } + final MembershipObserver.MembershipEvent event; + if (activity.isAddParticipant()) { + event = new InternalMembership.InternalMembershipCreated(new InternalMembership(activity), activity); + } + else if (activity.isLeaveActivity()) { + event = new InternalMembership.InternalMembershipDeleted(new InternalMembership(activity), activity); + } + else if (activity.getVerb() == ActivityModel.Verb.assignModerator || activity.getVerb() == ActivityModel.Verb.unassignModerator) { + event = new InternalMembership.InternalMembershipUpdated(new InternalMembership(activity), activity); + } + else if (activity.getVerb() == ActivityModel.Verb.acknowledge) { + event = new InternalMembership.InternalMembershipMessageSeen(new InternalMembership(activity), activity, new WebexId(WebexId.Type.MESSAGE_ID, activity.getObject().getId()).toHydraId()); + } + else { + event = null; + } + if (event != null) { + Queue.main.run(() -> observer.onEvent(event)); + } } @Override public void list(@Nullable String spaceId, @Nullable String personId, @Nullable String personEmail, int max, @NonNull CompletionHandler> handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.list(s, spaceId, spaceId, personId, personEmail, max <= 0 ? null : max), new ListCallback<>(handler)); + Service.Hydra.get("memberships") + .with("roomId", spaceId) + .with("spaceId", spaceId) + .with("personId", personId) + .with("personEmail", personEmail) + .with("max", max <= 0 ? null : String.valueOf(max)) + .auth(phone.getAuthenticator()) + .queue(Queue.main) + .model(new TypeToken>(){}.getType()) + .error(handler) + .async((Closure>) result -> handler.onComplete(ResultImpl.success(result.getItems()))); } @Override - public void create(@NonNull String spaceId, @Nullable String personId, @Nullable String personEmail, boolean isModerator, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.create(s, Maps.makeMap("roomId", spaceId, "spaceId", spaceId, "personId", personId, "personEmail", personEmail, "isModerator", isModerator)), new ObjectCallback<>(handler)); + public void get(@NonNull String membershipId, @NonNull CompletionHandler handler) { + Service.Hydra.get("memberships", membershipId) + .auth(phone.getAuthenticator()) + .queue(Queue.main) + .model(Membership.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override - public void get(@NonNull String membershipId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.get(s, membershipId), new ObjectCallback<>(handler)); + public void create(@NonNull String spaceId, @Nullable String personId, @Nullable String personEmail, boolean isModerator, @NonNull CompletionHandler handler) { + Service.Hydra.post(Maps.makeMap("roomId", spaceId, "spaceId", spaceId, "personId", personId, "personEmail", personEmail, "isModerator", isModerator)) + .to("memberships") + .auth(phone.getAuthenticator()) + .queue(Queue.main) + .model(Membership.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override public void update(@NonNull String membershipId, boolean isModerator, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.update(s, membershipId, Maps.makeMap("isModerator", isModerator)), new ObjectCallback<>(handler)); + Service.Hydra.put(Maps.makeMap("isModerator", isModerator)) + .to("memberships", membershipId) + .auth(phone.getAuthenticator()) + .queue(Queue.main) + .model(Membership.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override public void delete(@NonNull String membershipId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.delete(s, membershipId), new ObjectCallback<>(handler)); + Service.Hydra.delete("memberships", membershipId) + .auth(phone.getAuthenticator()) + .queue(Queue.main) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override public void listWithReadStatus(@NonNull String spaceId, @NonNull CompletionHandler> handler) { - _client.getConversationClient().getConversationParticipantsReadStatus(WebexId.translate(spaceId)).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - Conversation conversation = response.body(); + Service.Conv.get("conversations", WebexId.translate(spaceId)) + .with("uuidEntryFormat", "true") + .with("personRefresh", "true") + .with("includeParticipants", "true") + .with("participantAckFilter", "all") + .with("activitiesLimit", "0") + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .queue(Queue.main) + .model(ConversationModel.class) + .error(handler) + .async((Closure) model -> { + if (model == null) { + handler.onComplete(ResultImpl.success(Collections.emptyList())); + return; + } List result = new ArrayList<>(); - for (Person person : conversation.getParticipants().getItems()) { + for (PersonModel person : model.getParticipants().getItems()) { try { - result.add(new InternalMembershipReadStatus(conversation, person)); - } - catch (Throwable ignored) { + result.add(new InternalMembershipReadStatus(model, person)); + } catch (Throwable ignored) { } } handler.onComplete(ResultImpl.success(result)); - } else { - handler.onComplete(ResultImpl.error(response)); - } - } - - @Override - public void onFailure(Call call, Throwable throwable) { - handler.onComplete(ResultImpl.error(throwable)); - } - }); - } - - private void processorActivity(Activity activity) { - if (null == _observer) { - return; - } - if (null == activity) { - Ln.e("MembershipClientImpl.processorActivity() activity is null"); - return; - } - Membership membership = new InternalMembership(activity); - MembershipObserver.MembershipEvent event; - switch (activity.getVerb()) { - case Verb.add: - event = new InternalMembership.InternalMembershipCreated(membership, activity); - break; - case Verb.leave: - event = new InternalMembership.InternalMembershipDeleted(membership, activity); - break; - case Verb.assignModerator: - case Verb.unassignModerator: - event = new InternalMembership.InternalMembershipUpdated(membership, activity); - break; - case Verb.acknowledge: - event = new InternalMembership.InternalMembershipMessageSeen(membership, activity, new WebexId(WebexId.Type.MESSAGE_ID, activity.getObject().getId()).toHydraId()); - break; - default: - return; - } - runOnUiThread(() -> _observer.onEvent(event), _observer); - } - - private void runOnUiThread(Runnable r, Object conditioner) { - if (conditioner == null) return; - Handler handler = new Handler(_context.getMainLooper()); - handler.post(r); - } - - private interface MembershipService { - @GET("memberships") - Call> list(@Header("Authorization") String authorization, - @Query("roomId") String roomId, - @Query("spaceId") String spaceId, - @Query("personId") String personId, - @Query("personEmail") String personEmail, - @Query("max") Integer max); - - @POST("memberships") - Call create(@Header("Authorization") String authorization, @Body Map parameters); - - @GET("memberships/{membershipId}") - Call get(@Header("Authorization") String authorization, @Path("membershipId") String membershipId); - - @PUT("memberships/{membershipId}") - Call update(@Header("Authorization") String authorization, @Path("membershipId") String membershipId, @Body Map parameters); - - @DELETE("memberships/{membershipId}") - Call delete(@Header("Authorization") String authorization, @Path("membershipId") String membershipId); + }); } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/LocalFile.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/LocalFile.java index 179b488e..7b67f8ac 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/LocalFile.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/LocalFile.java @@ -2,8 +2,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; - -import com.cisco.spark.android.util.MimeUtils; +import com.ciscowebex.androidsdk.utils.MimeUtils; import java.io.File; import java.net.URLConnection; diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java index 2b49c19e..46aeed70 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java @@ -27,9 +27,11 @@ import java.util.List; import android.support.annotation.NonNull; -import com.cisco.spark.android.model.*; -import com.cisco.spark.android.model.conversation.*; +import com.ciscowebex.androidsdk.internal.Credentials; +import com.ciscowebex.androidsdk.internal.model.*; +import com.ciscowebex.androidsdk.message.internal.DraftImpl; import com.ciscowebex.androidsdk.message.internal.RemoteFileImpl; +import com.ciscowebex.androidsdk.utils.Utils; import com.ciscowebex.androidsdk.utils.WebexId; import com.ciscowebex.androidsdk.space.Space; import com.google.gson.Gson; @@ -41,6 +43,48 @@ */ public class Message { + /** + * Write a draft to be posted. + * + * @param text The content of draft to be posted. The content can be plain text, html, or markdown. + * @since 2.5.0 + */ + public static Draft draft(Text text) { + return new DraftImpl(text); + } + + /** + * Encapsulating the content will be post. + * + * @since 2.5.0 + */ + public interface Draft { + + /** + * Attach local files to the draft. + * + * @param files Local files to be attached with the draft. + * @since 2.5.0 + */ + Draft addAttachments(LocalFile... files); + + /** + * Mention either one people or all people in a space. + * + * @param mentions Notify either one or all in a space about this message. + * @since 2.5.0 + */ + Draft addMentions(Mention... mentions); + + /** + * Set the parent message of the threading message. + * + * @param parent The parent message of the threading message. + * @since 2.5.0 + */ + Draft setParent(Message parent); + } + /** * The wrapper for the message text in different formats: plain text, markdown, and html. * Please note this version of the SDK requires the application to convert markdown to html. @@ -92,11 +136,11 @@ private Text(String plain, String html, String markdown) { this.markdown = markdown; } - private Text(@NonNull ActivityObject object) { + private Text(@NonNull ObjectModel object) { this.plain = object.getDisplayName(); this.html = object.getContent(); - if (object instanceof Comment) { - this.markdown = ((Comment) object).getMarkdown(); + if (object instanceof MarkdownableModel) { + this.markdown = ((MarkdownableModel) object).getMarkdown(); } } @@ -123,7 +167,7 @@ public String getPlain() { } } - private transient Activity activity; + private transient ActivityModel activity; private String id; @@ -147,14 +191,12 @@ public String getPlain() { private transient List remoteFiles; - private boolean isReply; - - private ParentObject parent; + private ParentModel parent; - protected Message(Activity activity, AuthenticatedUser user, boolean received) { + protected Message(ActivityModel activity, Credentials user, boolean received) { this.activity = activity; this.id = new WebexId(WebexId.Type.MESSAGE_ID, activity.getId()).toHydraId(); - if (activity.getVerb().equals(Verb.delete) && activity.getObject() != null) { + if (activity.getVerb().equals(ActivityModel.Verb.delete) && activity.getObject() != null) { this.id = new WebexId(WebexId.Type.MESSAGE_ID, activity.getObject().getId()).toHydraId(); } if (activity.getActor() != null) { @@ -165,16 +207,16 @@ protected Message(Activity activity, AuthenticatedUser user, boolean received) { if (activity.getObject() != null) { this.textAsObject = new Text(activity.getObject()); } - if (activity.getTarget() instanceof Conversation) { + if (activity.getTarget() instanceof ConversationModel) { this.spaceId = new WebexId(WebexId.Type.ROOM_ID, activity.getTarget().getId()).toHydraId(); - this.spaceType = ((Conversation) activity.getTarget()).isOneOnOne() ? Space.SpaceType.DIRECT : Space.SpaceType.GROUP; - } else if (activity.getTarget() instanceof SpaceProperty) { + this.spaceType = ((ConversationModel) activity.getTarget()).isOneOnOne() ? Space.SpaceType.DIRECT : Space.SpaceType.GROUP; + } else if (activity.getTarget() instanceof SpacePropertyModel) { this.spaceId = new WebexId(WebexId.Type.ROOM_ID, activity.getTarget().getId()).toHydraId(); - this.spaceType = ((SpaceProperty) activity.getTarget()).getTags().contains("ONE_ON_ONE") ? Space.SpaceType.DIRECT : Space.SpaceType.GROUP; - } else if (activity.getTarget() instanceof Person) { + this.spaceType = ((ConversationModel) activity.getTarget()).getTags().contains("ONE_ON_ONE") ? Space.SpaceType.DIRECT : Space.SpaceType.GROUP; + } else if (activity.getTarget() instanceof PersonModel) { this.spaceType = Space.SpaceType.DIRECT; this.toPersonId = new WebexId(WebexId.Type.PEOPLE_ID, activity.getTarget().getId()).toHydraId(); - this.toPersonEmail = ((Person) activity.getTarget()).getEmail(); + this.toPersonEmail = ((PersonModel) activity.getTarget()).getEmail(); } if (this.spaceId == null) { this.spaceId = new WebexId(WebexId.Type.ROOM_ID, activity.getConversationId()).toHydraId(); @@ -183,23 +225,22 @@ protected Message(Activity activity, AuthenticatedUser user, boolean received) { if (this.toPersonId == null && received) { this.toPersonId = new WebexId(WebexId.Type.PEOPLE_ID, user.getUserId()).toHydraId(); } - if (this.toPersonEmail == null && received) { - this.toPersonEmail = user.getEmail(); + if (this.toPersonEmail == null && received && user.getPerson() != null) { + this.toPersonEmail = Utils.getFirst(user.getPerson().getEmails()); } this.isSelfMentioned = activity.isSelfMention(user, 0); } ArrayList remoteFiles = new ArrayList<>(); if (activity.getObject() != null && activity.getObject().isContent()) { - com.cisco.spark.android.model.conversation.Content content = (com.cisco.spark.android.model.conversation.Content) activity.getObject(); - ItemCollection files = content.getContentFiles(); - for (File file : files.getItems()) { + ContentModel content = (ContentModel) activity.getObject(); + ItemsModel files = content.getContentFiles(); + for (FileModel file : files.getItems()) { RemoteFile remoteFile = new RemoteFileImpl(file); remoteFiles.add(remoteFile); } } this.remoteFiles = remoteFiles; - this.isReply = activity.isReply(); this.parent = activity.getParent(); } @@ -355,17 +396,17 @@ public List getFiles() { * @since 2.5.0 */ public boolean isReply() { - return isReply; + return activity.isReply(); } /** - * Returns the parent object reference, if this message is a reply message. + * Returns the parent if this message is a reply message. * * @return the parent or null if not reply message. * @since 2.5.0 */ - public ParentObject getParent() { - return parent; + public String getParentId() { + return parent == null ? null : new WebexId(WebexId.Type.MESSAGE_ID, parent.getId()).toHydraId(); } /** diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageClient.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageClient.java index 50853ee9..3640a7a5 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageClient.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageClient.java @@ -75,17 +75,18 @@ public interface MessageClient { void get(@NonNull String messageId, @NonNull CompletionHandler handler); /** - * Posts a message with optional file attachments to a person asynchronously. + * Posts a message to a space or a person asynchronously. *

* The content of the message can be plain text, html, or markdown. + * To notify specific person or everyone in a space, mentions should be used. + * Having @johndoe in the content of the message does not generate notification. * - * @param id The identifier of a person to which the message is to be posted. - * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. - * @param files Local files to be attached with the message. Null if no files to be attached. + * @param target The identifier of a space or a person or an email address to which the message is to be posted. + * @param draft The content of message to be posted to the space. * @param handler A closure to be executed once the message has posted. - * @since 2.1.0 + * @since 2.5.0 */ - void postToPerson(@NonNull String id, @Nullable String text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); + void post(@NonNull String target, @NonNull Message.Draft draft, @NonNull CompletionHandler handler); /** * Posts a message with optional file attachments to a person asynchronously. @@ -96,49 +97,9 @@ public interface MessageClient { * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. * @param files Local files to be attached with the message. Null if no files to be attached. * @param handler A closure to be executed once the message has posted. - * @since 2.3.0 - */ - void postToPerson(@NonNull String id, @Nullable Message.Text text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); - - /** - * Posts a message with optional file attachments to a person asynchronously. - *

- * The content of the message can be plain text, html, or markdown. - * - * @param email The email address of a person to which the message is to be posted. - * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. - * @param files Local files to be attached with the message. Null if no files to be attached. - * @param handler A closure to be executed once the message has posted. * @since 2.1.0 */ - void postToPerson(@NonNull EmailAddress email, @Nullable String text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); - - /** - * Posts a message with optional file attachments to a person asynchronously. - *

- * The content of the message can be plain text, html, or markdown. - * - * @param email The email address of a person to which the message is to be posted. - * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. - * @param files Local files to be attached with the message. Null if no files to be attached. - * @param handler A closure to be executed once the message has posted. - * @since 2.3.0 - */ - void postToPerson(@NonNull EmailAddress email, @Nullable Message.Text text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); - - /** - * Posts a message with optional file attachments to a person asynchronously. - *

- * The content of the message can be plain text, html, or markdown. - * - * @param id The identifier of a person to which the message is to be posted. - * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. - * @param files Local files to be attached with the message. Null if no files to be attached. - * @param parentMessage Parent message. Null if no parent message. - * @param handler A closure to be executed once the message has posted. - * @since 2.5.0 - */ - void postToPerson(@NonNull String id, @Nullable String text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); + void postToPerson(@NonNull String id, @Nullable String text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); /** * Posts a message with optional file attachments to a person asynchronously. @@ -148,11 +109,10 @@ public interface MessageClient { * @param id The identifier of a person to which the message is to be posted. * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. * @param files Local files to be attached with the message. Null if no files to be attached. - * @param parentMessage Parent message. Null if no parent message. * @param handler A closure to be executed once the message has posted. - * @since 2.5.0 + * @since 2.3.0 */ - void postToPerson(@NonNull String id, @Nullable Message.Text text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); + void postToPerson(@NonNull String id, @Nullable Message.Text text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); /** * Posts a message with optional file attachments to a person asynchronously. @@ -162,11 +122,10 @@ public interface MessageClient { * @param email The email address of a person to which the message is to be posted. * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. * @param files Local files to be attached with the message. Null if no files to be attached. - * @param parentMessage Parent message. Null if no parent message. * @param handler A closure to be executed once the message has posted. - * @since 2.5.0 + * @since 2.1.0 */ - void postToPerson(@NonNull EmailAddress email, @Nullable String text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); + void postToPerson(@NonNull EmailAddress email, @Nullable String text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); /** * Posts a message with optional file attachments to a person asynchronously. @@ -176,11 +135,10 @@ public interface MessageClient { * @param email The email address of a person to which the message is to be posted. * @param text The content of message to be posted to the person. The content can be plain text, html, or markdown. * @param files Local files to be attached with the message. Null if no files to be attached. - * @param parentMessage Parent message. Null if no parent message. * @param handler A closure to be executed once the message has posted. - * @since 2.5.0 + * @since 2.3.0 */ - void postToPerson(@NonNull EmailAddress email, @Nullable Message.Text text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); + void postToPerson(@NonNull EmailAddress email, @Nullable Message.Text text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); /** * Posts a message with optional file attachments to a space asynchronously. @@ -214,40 +172,6 @@ public interface MessageClient { */ void postToSpace(@NonNull String id, @Nullable Message.Text text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @NonNull CompletionHandler handler); - /** - * Posts a message with optional file attachments to a space asynchronously. - *

- * The content of the message can be plain text, html, or markdown. - * To notify specific person or everyone in a space, mentions should be used. - * Having @johndoe in the content of the message does not generate notification. - * - * @param id The identifier of a space to which the message is to be posted. - * @param text The content of message to be posted to the space. The content can be plain text, html, or markdown. - * @param mentions Notify either one or all in a space about this message. - * @param files Local files to be attached with the message. Null if no files to be attached. - * @param parentMessage Parent message. Null if no parent message. - * @param handler A closure to be executed once the message has posted. - * @since 2.5.0 - */ - void postToSpace(@NonNull String id, @Nullable String text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); - - /** - * Posts a message with optional file attachments to a space asynchronously. - *

- * The content of the message can be plain text, html, or markdown. - * To notify specific person or everyone in a space, mentions should be used. - * Having @johndoe in the content of the message does not generate notification. - * - * @param id The identifier of a space to which the message is to be posted. - * @param text The content of message to be posted to the space. The content can be plain text, html, or markdown. - * @param mentions Notify either one or all in a space about this message. - * @param files Local files to be attached with the message. Null if no files to be attached. - * @param parentMessage Parent message. Null if no parent message. - * @param handler A closure to be executed once the message has posted. - * @since 2.5.0 - */ - void postToSpace(@NonNull String id, @Nullable Message.Text text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler); - /** * Downloads a file attachement asynchronously. * See File Sharing for more details. @@ -365,7 +289,7 @@ void post(@NonNull String idOrEmail, * @param messageId the id of a message. * @since 2.3.0 */ - void markAsRead(@NonNull String spaceId, String messageId); + void markAsRead(@NonNull String spaceId, @NonNull String messageId); /** * A callback to indicate the progress of an action in already processed size (bytes). diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageObserver.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageObserver.java index 4487c8d3..a7eca3ec 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageObserver.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/MessageObserver.java @@ -1,7 +1,7 @@ package com.ciscowebex.androidsdk.message; -import com.cisco.spark.android.model.conversation.Activity; import com.ciscowebex.androidsdk.WebexEvent; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; /** * Callback to receive the events from a {@link MessageClient}. @@ -26,7 +26,7 @@ interface MessageEvent extends WebexEvent { class MessageArrived extends WebexEvent.Base implements MessageEvent { private Message message; - protected MessageArrived(Message message, Activity activity) { + protected MessageArrived(Message message, ActivityModel activity) { super(activity); this.message = message; } @@ -55,7 +55,7 @@ class MessageReceived extends WebexEvent.Base implements MessageEvent { private Message message; - protected MessageReceived(Message message, Activity activity) { + protected MessageReceived(Message message, ActivityModel activity) { super(activity); this.message = message; } @@ -80,7 +80,7 @@ class MessageDeleted extends WebexEvent.Base implements MessageEvent { private String messageId; - protected MessageDeleted(String messageId, Activity activity) { + protected MessageDeleted(String messageId, ActivityModel activity) { super(activity); this.messageId = messageId; } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostCommentOperation.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostCommentOperation.java deleted file mode 100644 index 95ec9309..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostCommentOperation.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.ciscowebex.androidsdk.message.internal; - -import com.cisco.spark.android.core.Injector; -import com.cisco.spark.android.model.conversation.Comment; -import com.cisco.spark.android.model.conversation.ParentObject; -import com.cisco.spark.android.sync.operationqueue.ActivityOperation; -import com.cisco.spark.android.sync.operationqueue.PostCommentOperation; -import com.cisco.spark.android.sync.operationqueue.core.SyncState; -import com.cisco.spark.android.util.Action; - -public class CallbackablePostCommentOperation extends PostCommentOperation { - - private Action onOperationFinishAction; - private ParentObject parent; - - CallbackablePostCommentOperation(Injector injector, - String conversationId, - Comment comment, - ParentObject parent, - Action onOperationFinishAction) { - super(injector, conversationId, comment); - this.onOperationFinishAction = onOperationFinishAction; - this.parent = parent; - } - - protected void onStateChanged(SyncState oldState) { - super.onStateChanged(oldState); - if (this.onOperationFinishAction != null && (this.getState() == SyncState.FAULTED || this.getState() == SyncState.SUCCEEDED)) { - this.onOperationFinishAction.call(this); - } - } - - @Override - protected void configureActivity() { - super.configureActivity(); - activity.setParent(parent); - } -} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostContentActivityOperation.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostContentActivityOperation.java deleted file mode 100644 index 6d6faeaa..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/CallbackablePostContentActivityOperation.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.ciscowebex.androidsdk.message.internal; - -import com.cisco.spark.android.core.Injector; -import com.cisco.spark.android.model.conversation.Comment; -import com.cisco.spark.android.model.conversation.File; -import com.cisco.spark.android.model.conversation.ParentObject; -import com.cisco.spark.android.sync.operationqueue.ActivityOperation; -import com.cisco.spark.android.sync.operationqueue.PostContentActivityOperation; -import com.cisco.spark.android.sync.operationqueue.core.SyncState; -import com.cisco.spark.android.util.Action; - -import java.util.List; - -public class CallbackablePostContentActivityOperation extends PostContentActivityOperation { - - private Action onOperationFinishAction; - - private ParentObject parent; - - CallbackablePostContentActivityOperation(Injector injector, - String conversationId, - ShareContentData shareContentData, - Comment comment, - List content, - List operationIds, - ParentObject parent, - Action onOperationFinishAction) { - super(injector, conversationId, shareContentData, comment, content, operationIds); - this.onOperationFinishAction = onOperationFinishAction; - this.parent = parent; - } - - protected void onStateChanged(SyncState oldState) { - super.onStateChanged(oldState); - if (this.onOperationFinishAction != null && (this.getState() == SyncState.FAULTED || this.getState() == SyncState.SUCCEEDED)) { - this.onOperationFinishAction.call(this); - } - } - - @Override - protected void configureActivity() { - super.configureActivity(); - activity.setParent(parent); - } -} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/DownloadFileOperation.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/DownloadFileOperation.java new file mode 100644 index 00000000..fc277340 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/DownloadFileOperation.java @@ -0,0 +1,97 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.message.internal; + +import android.net.Uri; +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.crypto.SecureContentReference; +import com.ciscowebex.androidsdk.internal.model.FileModel; +import com.ciscowebex.androidsdk.internal.model.ImageModel; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.message.MessageClient; +import com.ciscowebex.androidsdk.utils.http.ContentDownloadMonitor; +import com.github.benoitdion.ln.Ln; +import okhttp3.Response; + +import java.io.*; + +public class DownloadFileOperation { + + private ContentDownloadMonitor monitor = new ContentDownloadMonitor(); + + private MessageClient.ProgressHandler progressHandler; + private Authenticator authenticator; + private FileModel sourceFile; + + public DownloadFileOperation(Authenticator authenticator, FileModel decryptedFile, MessageClient.ProgressHandler progressHandler) { + this.authenticator = authenticator; + this.sourceFile = decryptedFile; + this.progressHandler = progressHandler; + } + + public void run(File outFile, boolean thumbnail, CompletionHandler callback) { + String url; + SecureContentReference scr; + if (thumbnail) { + ImageModel image = sourceFile.getImage(); + if (image == null) { + callback.onComplete(ResultImpl.error("No thumbnial")); + return; + } + url = image.getUrl(); + scr = image.getSecureContentReference(); + } + else { + url = sourceFile.getUrl(); + scr = sourceFile.getSecureContentReference(); + } + doDownload(url, scr, outFile, callback); + } + + private void doDownload(String url, SecureContentReference scr, File outFile, CompletionHandler callback) { + Service.Common.get().url(url).auth(authenticator).model(Response.class).error(callback).async((Closure) response -> { + InputStream is = response.body().byteStream(); + if (is == null) { + ResultImpl.errorInMain(callback, "Failed downloading from uri: " + url); + return; + } + InputStream in = scr != null ? scr.decrypt(is) : is; + try { + OutputStream out = new FileOutputStream(outFile); + long contentLength = Long.parseLong(response.headers().get("Content-Length")); + monitor.download(in, out, contentLength, progress -> { + if (progressHandler != null) { + Queue.main.run(() -> progressHandler.onProgress(progress)); + } + }); + ResultImpl.inMain(callback, Uri.fromFile(outFile)); + } catch (Throwable t) { + ResultImpl.errorInMain(callback, t); + } + }); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/DraftImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/DraftImpl.java new file mode 100644 index 00000000..f4af13a5 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/DraftImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.message.internal; + +import com.ciscowebex.androidsdk.message.LocalFile; +import com.ciscowebex.androidsdk.message.Mention; +import com.ciscowebex.androidsdk.message.Message; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class DraftImpl implements Message.Draft { + + private Message.Text text; + private List files; + private List mentions; + private Message parent; + + public DraftImpl(Message.Text text) { + this.text = text; + } + + public Message.Draft addAttachments(LocalFile... files) { + if (this.files == null) { + this.files = new ArrayList<>(); + } + this.files.addAll(Arrays.asList(files)); + return this; + } + + public Message.Draft addMentions(Mention... mentions) { + if (this.mentions == null) { + this.mentions = new ArrayList<>(); + } + this.mentions.addAll(Arrays.asList(mentions)); + return this; + } + + public Message.Draft setParent(Message parent) { + this.parent = parent; + return this; + } + + public Message.Text getText() { + return text; + } + + public List getFiles() { + return files; + } + + public List getMentions() { + return mentions; + } + + public Message getParent() { + return parent; + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/InternalMessage.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/InternalMessage.java index b8275f45..8e43b891 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/InternalMessage.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/InternalMessage.java @@ -1,33 +1,53 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.message.internal; -import com.cisco.spark.android.model.AuthenticatedUser; -import com.cisco.spark.android.model.conversation.Activity; +import com.ciscowebex.androidsdk.internal.Credentials; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; import com.ciscowebex.androidsdk.message.Message; import com.ciscowebex.androidsdk.message.MessageObserver; -import com.ciscowebex.androidsdk.space.Space; -import com.ciscowebex.androidsdk.space.SpaceObserver; class InternalMessage extends Message { static class InternalMessageArrived extends MessageObserver.MessageArrived { - InternalMessageArrived(Message message, Activity activity) { + InternalMessageArrived(Message message, ActivityModel activity) { super(message, activity); } } static class InternalMessageReceived extends MessageObserver.MessageReceived { - InternalMessageReceived(Message message, Activity activity) { + InternalMessageReceived(Message message, ActivityModel activity) { super(message, activity); } } static class InternalMessageDeleted extends MessageObserver.MessageDeleted { - InternalMessageDeleted(String message, Activity activity) { + InternalMessageDeleted(String message, ActivityModel activity) { super(message, activity); } } - InternalMessage(Activity activity, AuthenticatedUser user, boolean received) { + InternalMessage(ActivityModel activity, Credentials user, boolean received) { super(activity, user, received); } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageClientImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageClientImpl.java index e5da73fc..1868e9af 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageClientImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageClientImpl.java @@ -22,670 +22,415 @@ package com.ciscowebex.androidsdk.message.internal; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.*; -import java.util.concurrent.*; - -import javax.inject.Inject; - import android.content.Context; import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; - -import com.cisco.spark.android.authenticator.ApiTokenProvider; -import com.cisco.spark.android.content.ContentUploadMonitor; -import com.cisco.spark.android.core.ApiClientProvider; -import com.cisco.spark.android.core.Injector; -import com.cisco.spark.android.model.*; -import com.cisco.spark.android.model.conversation.*; -import com.cisco.spark.android.model.crypto.scr.ContentReference; -import com.cisco.spark.android.processing.ActivityListener; -import com.cisco.spark.android.sync.ContentDataCacheRecord; -import com.cisco.spark.android.sync.ContentDownloadMonitor; -import com.cisco.spark.android.sync.ContentManager; -import com.cisco.spark.android.sync.ConversationContract; -import com.cisco.spark.android.sync.DatabaseProvider; -import com.cisco.spark.android.sync.operationqueue.ActivityOperation; -import com.cisco.spark.android.sync.operationqueue.NewConversationOperation; -import com.cisco.spark.android.sync.operationqueue.PostContentActivityOperation.ContentItem; -import com.cisco.spark.android.sync.operationqueue.PostContentActivityOperation.ShareContentData; -import com.cisco.spark.android.sync.operationqueue.core.Operation; -import com.cisco.spark.android.sync.operationqueue.core.Operations; -import com.cisco.spark.android.util.*; import com.ciscowebex.androidsdk.CompletionHandler; -import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.ActivityListener; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.queue.Queue; import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.crypto.CryptoUtils; +import com.ciscowebex.androidsdk.internal.crypto.KeyManager; +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; +import com.ciscowebex.androidsdk.internal.model.*; import com.ciscowebex.androidsdk.message.*; -import com.ciscowebex.androidsdk.message.Message; -import com.ciscowebex.androidsdk.utils.EmailAddress; -import com.ciscowebex.androidsdk.utils.Lists; -import com.ciscowebex.androidsdk.utils.WebexId; -import com.ciscowebex.androidsdk.utils.http.ListBody; -import com.ciscowebex.androidsdk.utils.http.ObjectCallback; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; -import com.ciscowebex.androidsdk_commlib.SDKCommonInjector; +import com.ciscowebex.androidsdk.phone.internal.PhoneImpl; +import com.ciscowebex.androidsdk.utils.*; import com.github.benoitdion.ln.Ln; - +import com.google.gson.reflect.TypeToken; +import me.helloworld.utils.Checker; import me.helloworld.utils.Strings; +import me.helloworld.utils.collection.Maps; -import org.greenrobot.eventbus.EventBus; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.GET; -import retrofit2.http.Header; -import retrofit2.http.POST; -import retrofit2.http.Path; -import retrofit2.http.Query; - -import static com.cisco.spark.android.content.ContentShareSource.FILE_PICKER; - -/** - * Created with IntelliJ IDEA. - * User: zhiyuliu - * Date: 28/09/2017 - * Time: 5:23 PM - */ - -public class MessageClientImpl implements MessageClient { - - private Authenticator _authenticator; - - private MessageService _service; - - private MessageObserver _observer; - - private Context _context; - - private int lastSendProgress = -1; - - @Inject - Injector injector; - - @Inject - Operations operations; - - @Inject - EventBus _bus; - - @Inject - ContentManager contentManager; - - @Inject - ContentUploadMonitor uploadMonitor; - - @Inject - DatabaseProvider db; +import java.io.File; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; - @Inject - ActivityListener activityListener; +public class MessageClientImpl implements MessageClient, ActivityListener { - @Inject - ApiTokenProvider _provider; + private Context context; + private PhoneImpl phone; + private MessageObserver observer; + private Map conversations = new ConcurrentHashMap<>(); + private String uuid = UUID.randomUUID().toString(); - @Inject - ApiClientProvider _client; + public MessageClientImpl(Context context, PhoneImpl phone) { + this.context = context; + this.phone = phone; + } - @Inject - KeyManager keyManager; + public void setMessageObserver(MessageObserver observer) { + this.observer = observer; + } - public MessageClientImpl(Context context, Authenticator authenticator, SDKCommonInjector injector) { - injector.inject(this); - _authenticator = authenticator; - _service = new ServiceBuilder().build(MessageService.class); - _context = context; - //_bus.register(this); - activityListener.register(activity -> { - processorActivity(activity); - return null; - }); + public void processActivity(ActivityModel activity) { + if (observer == null) { + return; + } + if (activity.getVerb() == ActivityModel.Verb.post || activity.getVerb() == ActivityModel.Verb.share) { + String conversationId = activity.getConversationId(); + if (conversationId == null) { + Ln.d("The activity without conversation"); + return; + } + String clientTempId = activity.getClientTempId(); + if (clientTempId != null && clientTempId.startsWith(uuid)) { + Ln.d("The activity is sent by self"); + return; + } + KeyManager.shared.tryRefresh(conversationId, activity.getEncryptionKeyUrl()); + KeyManager.shared.getKey(conversationId, phone.getCredentials(), phone.getDevice(), keyResult -> { + if (keyResult.getData() != null) { + activity.decrypt(keyResult.getData()); + } + Message message = createMessage(activity, true); + MessageObserver.MessageReceived event = new InternalMessage.InternalMessageReceived(message, activity); + Queue.main.run(() -> observer.onEvent(event)); + // TODO Remove the deprecated event in next big release + Queue.main.run(() -> observer.onEvent(new InternalMessage.InternalMessageArrived(message, activity))); + }); + } + else if (activity.getVerb() == ActivityModel.Verb.delete) { + String id = new WebexId(WebexId.Type.MESSAGE_ID, activity.getObject().getId()).toHydraId(); + MessageObserver.MessageEvent event = new InternalMessage.InternalMessageDeleted(id, activity); + Queue.main.run(() -> observer.onEvent(event)); + } } public void list(@NonNull String spaceId, @Nullable Before before, @IntRange(from = 0, to = Integer.MAX_VALUE) int max, @Nullable Mention[] mentions, @NonNull CompletionHandler> handler) { String id = WebexId.translate(spaceId); if (max == 0) { - runOnUiThread(() -> handler.onComplete(ResultImpl.success(Collections.emptyList())), handler); + ResultImpl.inMain(handler, Collections.emptyList()); return; } if (before == null) { - list(id, null, mentions, max, new ArrayList<>(), handler); + doList(id, null, mentions, max, new ArrayList<>(), handler); } else if (before instanceof Before.Date) { - list(id, ((Before.Date) before).getDate(), mentions, max, new ArrayList<>(), handler); + doList(id, ((Before.Date) before).getDate(), mentions, max, new ArrayList<>(), handler); } else if (before instanceof Before.Message) { get(((Before.Message) before).getMessage(), false, result -> { Message message = result.getData(); if (message == null) { - runOnUiThread(() -> handler.onComplete(ResultImpl.error(result.getError())), handler); + ResultImpl.errorInMain(handler, result); } else { - list(id, message.getCreated(), mentions, max, new ArrayList<>(), handler); + doList(id, message.getCreated(), mentions, max, new ArrayList<>(), handler); } }); } } - private void list(@NonNull String spaceId, @Nullable Date date, @Nullable Mention[] mentions, @IntRange(from = 0, to = Integer.MAX_VALUE) int max, @NonNull List activities, @NonNull CompletionHandler> handler) { + private void doList(@NonNull String spaceId, + @Nullable Date date, + @Nullable Mention[] mentions, + @IntRange(from = 0, to = Integer.MAX_VALUE) int max, + @NonNull List activities, + @NonNull CompletionHandler> handler) { int queryMax = Math.max(max, max * 2); - - List result = activities; - Callback> callback = new Callback>() { - - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - for (Activity activity : response.body().getItems()) { - if (activity.getVerb().equals(Verb.post) || activity.getVerb().equals(Verb.share)) { - result.add(activity); - if (result.size() >= max) + Service.Conv.get(Checker.isEmpty(mentions) ? "activities" : "mentions") + .with("conversationId", WebexId.translate(spaceId)) + .with("limit", String.valueOf(queryMax)) + .with(Checker.isEmpty(mentions) ? "maxDate" : "sinceDate", String.valueOf((date == null ? new Date() : date).getTime())) + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .model(new TypeToken>(){}.getType()) + .error(handler) + .async((Closure>) items -> { + for (ActivityModel model : items.getItems()) { + if (model.getVerb().equals(ActivityModel.Verb.post) || model.getVerb().equals(ActivityModel.Verb.share)) { + activities.add(model); + if (activities.size() >= max) { break; + } } } - if (result.size() >= max || response.body().size() < queryMax) { - AsyncTask.execute(() -> { - CountDownLatch latch = new CountDownLatch(result.size()); - List messages = new ArrayList<>(result.size()); - for (Activity activity : result) { - decryptActivity(activity, new Action() { - @Override - public void call(Activity activity) { - Message message = createMessage(activity, false); - if (message != null) { - messages.add(message); - } - latch.countDown(); - } - }); - } - try { - latch.await(); - } catch (InterruptedException ignored) { + if (activities.size() >= max || items.size() < queryMax) { + KeyManager.shared.getKey(WebexId.translate(spaceId), phone.getCredentials(), phone.getDevice(), keyResult -> { + List messages = new ArrayList<>(activities.size()); + for (ActivityModel model : activities) { + if (keyResult.getData() != null) { + model.decrypt(keyResult.getData()); + } + messages.add(createMessage(model, false)); } - runOnUiThread(() -> handler.onComplete(ResultImpl.success(messages)), handler); + ResultImpl.inMain(handler, messages); }); - } else { - Activity last = Lists.getLast(response.body().getItems()); - list(spaceId, last == null ? null : last.getPublished(), mentions, max, result, handler); } - } else { - runOnUiThread(() -> handler.onComplete(ResultImpl.error(response)), handler); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - runOnUiThread(() -> handler.onComplete(ResultImpl.error(t)), handler); - } - }; - - long time = (date == null ? new Date() : date).getTime() - 1; - if (mentions != null && mentions.length > 0) { - // TODO filter by conv Id - // TODO just get method me for now - _client.getConversationClient().getUserMentions(time, queryMax).enqueue(callback); - } else { - _client.getConversationClient().getConversationActivitiesBefore(spaceId, time, queryMax).enqueue(callback); - } + else { + ActivityModel last = Lists.getLast(items.getItems()); + doList(spaceId, last == null ? null : last.getPublished(), mentions, max, activities, handler); + } + }); } - @Override public void get(@NonNull String messageId, @NonNull CompletionHandler handler) { get(messageId, true, handler); } private void get(@NonNull String messageId, boolean decrypt, @NonNull CompletionHandler handler) { - WebexId webexId = WebexId.from(messageId); - _client.getConversationClient().getActivity("activities/" + webexId.getId()).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - Activity activity = response.body(); - if (decrypt) { - decryptActivity(activity, new Action() { - @Override - public void call(Activity activity) { - runOnUiThread(() -> handler.onComplete(ResultImpl.success(createMessage(activity, false))), handler); - } - }); - } else { - handler.onComplete(ResultImpl.success(createMessage(activity, false))); + Service.Conv.get("activities", WebexId.translate(messageId)) + .auth(phone.getAuthenticator()) + .model(ActivityModel.class) + .device(phone.getDevice()) + .error(handler) + .async((Closure) model -> { + if (!decrypt) { + ResultImpl.inMain(handler, createMessage(model, false)); + return; } - } else { - handler.onComplete(ResultImpl.error(response)); - } - } + KeyManager.shared.getKey(model.getConversationId(), phone.getCredentials(), phone.getDevice(), keyResult -> { + if (keyResult.getData() != null) { + model.decrypt(keyResult.getData()); + } + ResultImpl.inMain(handler, createMessage(model, false)); + }); + }); + } - @Override - public void onFailure(Call call, Throwable t) { - handler.onComplete(ResultImpl.error(t)); - } - }); + public void delete(@NonNull String messageId, @NonNull CompletionHandler handler) { + Service.Hydra.delete("messages", messageId) + .auth(phone.getAuthenticator()) + .queue(Queue.main) + .error(handler) + .async((Closure) data -> handler.onComplete(ResultImpl.success(null))); } @Override public void postToPerson(@NonNull String personId, @Nullable String text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(personId, createComment(Message.Text.html(text, text), null), files, null, handler); + post(personId, Message.draft(Message.Text.html(text, text)).addAttachments(files), handler); } @Override public void postToPerson(@NonNull String personId, @Nullable Message.Text text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(personId, createComment(text, null), files, null, handler); + post(personId, Message.draft(text).addAttachments(files), handler); } @Override public void postToPerson(@NonNull EmailAddress personEmail, @Nullable String text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(personEmail.toString(), createComment(Message.Text.html(text, text), null), files, null, handler); + post(personEmail.toString(), Message.draft(Message.Text.html(text, text)).addAttachments(files), handler); } @Override public void postToPerson(@NonNull EmailAddress personEmail, @Nullable Message.Text text, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(personEmail.toString(), createComment(text, null), files, null, handler); - } - - @Override - public void postToPerson(@NonNull String personId, @Nullable String text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { - post(personId, createComment(Message.Text.html(text, text), null), files, parentMessage, handler); - } - - @Override - public void postToPerson(@NonNull String personId, @Nullable Message.Text text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { - post(personId, createComment(text, null), files, parentMessage, handler); - } - - @Override - public void postToPerson(@NonNull EmailAddress personEmail, @Nullable String text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { - post(personEmail.toString(), createComment(Message.Text.html(text, text), null), files, parentMessage, handler); - } - - @Override - public void postToPerson(@NonNull EmailAddress personEmail, @Nullable Message.Text text, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { - post(personEmail.toString(), createComment(text, null), files, parentMessage, handler); + post(personEmail.toString(), Message.draft(text).addAttachments(files), handler); } @Override public void postToSpace(@NonNull String spaceId, @Nullable String text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(spaceId, createComment(Message.Text.html(text, text), mentions), files, null, handler); + post(spaceId, Message.draft(Message.Text.html(text, text)).addAttachments(files).addMentions(mentions), handler); } @Override public void postToSpace(@NonNull String spaceId, @Nullable Message.Text text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @NonNull CompletionHandler handler) { - post(spaceId, createComment(text, mentions), files, null, handler); + post(spaceId, Message.draft(text).addAttachments(files).addMentions(mentions), handler); } - @Override - public void postToSpace(@NonNull String spaceId, @Nullable String text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { - post(spaceId, createComment(Message.Text.html(text, text), mentions), files, parentMessage, handler); - } - - @Override - public void postToSpace(@NonNull String spaceId, @Nullable Message.Text text, @Nullable Mention[] mentions, @Nullable LocalFile[] files, @Nullable Message parentMessage, @NonNull CompletionHandler handler) { - post(spaceId, createComment(text, mentions), files, parentMessage, handler); - } - - private void post(String personOrSpace, Comment comment, LocalFile[] localFiles, Message parentMessage, CompletionHandler handler) { - Ln.d("Post to: " + personOrSpace); - WebexId webexId = WebexId.from(personOrSpace); + public void post(@NonNull String target, @NonNull Message.Draft draft, @NonNull CompletionHandler handler) { + WebexId webexId = WebexId.from(target); if (webexId == null) { - if (EmailAddress.fromString(personOrSpace) == null) { - doPost(personOrSpace, comment, localFiles, parentMessage, handler); + if (EmailAddress.fromString(target) == null) { + doPost(target, (DraftImpl) draft, handler); } else { - this.createSpaceWithPerson(personOrSpace, result -> { - if (result.getData() != null) { - doPost(result.getData(), comment, localFiles, parentMessage, handler); - } else { - handler.onComplete(ResultImpl.error(result.getError())); + getOrCreateConversation(target, result -> { + String conversationId = result.getData(); + if (conversationId == null) { + ResultImpl.errorInMain(handler, result); + return; } + doPost(conversationId, (DraftImpl) draft, handler); }); } } else if (webexId.is(WebexId.Type.ROOM_ID)) { - doPost(webexId.getId(), comment, localFiles, parentMessage, handler); + doPost(webexId.getId(), (DraftImpl) draft, handler); } else if (webexId.is(WebexId.Type.PEOPLE_ID)) { - this.createSpaceWithPerson(webexId.getId(), result -> { - if (result.getData() != null) { - doPost(result.getData(), comment, localFiles, parentMessage, handler); - } else { - handler.onComplete(ResultImpl.error(result.getError())); + getOrCreateConversation(webexId.getId(), result -> { + String conversationId = result.getData(); + if (conversationId == null) { + ResultImpl.errorInMain(handler, result); + return; } + doPost(conversationId, (DraftImpl) draft, handler); }); - } else { - handler.onComplete(ResultImpl.error("Unknown target: " + personOrSpace)); - } - } - - private void doPost(String conversationId, Comment comment, LocalFile[] localFiles, Message parentMessage, CompletionHandler handler) { - if (TextUtils.isEmpty(conversationId)) { - handler.onComplete(ResultImpl.error("Invalid person or id!")); - return; - } - Action callback = new Action() { - @Override - public void call(ActivityOperation item) { - Activity activity = item.getResult(); - if (activity == null) { - runOnUiThread(() -> handler.onComplete(ResultImpl.error(item.getErrorMessage())), handler); - } else { - decryptActivity(activity, new Action() { - @Override - public void call(Activity activity) { - runOnUiThread(() -> handler.onComplete(ResultImpl.success(createMessage(activity, false))), handler); - } - }); - } - } - }; - ParentObject parent = null; - if (parentMessage != null) { - if (parentMessage.getParent() != null) - parent = parentMessage.getParent(); - else { - parent = new ParentObject(); - parent.setId(WebexId.translate(parentMessage.getId())); - parent.setType(Activities.ACTIVITY_TYPE_REPLY); - parent.setPublished(parentMessage.getCreated()); - parent.setActorId(parentMessage.getPersonId()); - } } - if (localFiles != null && localFiles.length > 0) { - ShareContentData shareContentData = new ShareContentData(); - for (LocalFile localFile : localFiles) { - ContentItem item = new ContentItem(localFile.getFile(), FILE_PICKER.toString()); - File modleFile = createModleFile(localFile, conversationId, contentManager, db); - if (modleFile != null) { - Operation uploadContent = operations.uploadContent(conversationId, modleFile); - item.setContentFile(modleFile); - item.setOperationId(uploadContent.getOperationId()); - shareContentData.addContentItem(item); - executor.scheduleAtFixedRate(new CheckUploadProgressTask(localFile), 0, 1, TimeUnit.SECONDS); - } - } - CallbackablePostContentActivityOperation postContent = new CallbackablePostContentActivityOperation(injector, conversationId, - shareContentData, - comment, - shareContentData.getContentFiles(), - shareContentData.getOperationIds(), - parent, - callback); - operations.submit(postContent); - } else { - CallbackablePostCommentOperation postCommentOperation = new CallbackablePostCommentOperation(injector, conversationId, comment, parent, callback); - operations.submit(postCommentOperation); + else { + ResultImpl.errorInMain(handler, "Unknown target: " + target); } } - @Override - public void delete(@NonNull String messageId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> _service.delete(s, messageId), new ObjectCallback<>(handler)); - } - - @Override public void downloadFile(@NonNull RemoteFile file, @Nullable java.io.File path, @Nullable ProgressHandler progressHandler, @NonNull CompletionHandler handler) { - download(((RemoteFileImpl) file).getFile(), file.getDisplayName(), false, path, progressHandler, handler); + doDownload((RemoteFileImpl) file, path, false, progressHandler, handler); } - @Override public void downloadThumbnail(@NonNull RemoteFile file, @Nullable java.io.File path, @Nullable ProgressHandler progressHandler, @NonNull CompletionHandler handler) { RemoteFileImpl.ThumbnailImpl thumbnail = (RemoteFileImpl.ThumbnailImpl) file.getThumbnail(); if (thumbnail == null || thumbnail.getImage() == null) { - handler.onComplete(ResultImpl.error("No thumbnail for this remote file.")); + ResultImpl.errorInMain(handler, "No thumbnail for this remote file."); return; } - download(thumbnail.getImage(), file.getDisplayName(), true, path, progressHandler, handler); + doDownload((RemoteFileImpl) file, path, true, progressHandler, handler); } - private void download(@NonNull ContentReference reference, - @Nullable String displayName, - boolean thnumnail, - @Nullable java.io.File path, - @Nullable ProgressHandler progressHandler, - @NonNull CompletionHandler completionHandler) { - Action callback = progressHandler == null ? null : new Action() { - @Override - public void call(Long item) { - runOnUiThread(() -> progressHandler.onProgress(item), progressHandler); - } - }; - - Action action = new Action() { - @Override - public void call(ContentDataCacheRecord item) { - if (progressHandler != null) { - runOnUiThread(() -> progressHandler.onProgress(item.getDataSize()), progressHandler); - } - java.io.File target = path; - if (target == null) { - target = new java.io.File(_context.getCacheDir(), "com.ciscowebex.sdk.downloads"); - target.mkdirs(); - } - String name = UUID.randomUUID().toString(); - if (displayName != null) { - name = name + "-" + displayName; - } - if (thnumnail) { - name = "thumb-" + name; - } - final java.io.File file = new java.io.File(target, name); - try { - if (!file.createNewFile()) { - runOnUiThread(() -> completionHandler.onComplete(ResultImpl.error("failed to download File " + file.toString())), completionHandler); - return; - } - FileUtils.copyFile(item.getLocalUriAsFile(), file); - runOnUiThread(() -> completionHandler.onComplete(ResultImpl.success(Uri.fromFile(file))), completionHandler); - } catch (Exception e) { - runOnUiThread(() -> completionHandler.onComplete(ResultImpl.error(e)), completionHandler); - } + public void markAsRead(@NonNull String spaceId) { + this.list(spaceId, null, 1, null, messages -> { + Message message = Lists.getFirst(messages.getData()); + if (message != null) { + markAsRead(spaceId, message.getId()); } - }; + }); + } - Uri uri = null; - String filename = null; - if (reference instanceof File) { - uri = ((File) reference).getUrl(); - filename = ((File) reference).getDisplayName(); + public void markAsRead(@NonNull String spaceId, @NonNull String messageId) { + Map body = new HashMap<>(); + body.put("objectType", ObjectModel.Type.activity); + body.put("verb", ActivityModel.Verb.acknowledge); + body.put("object", Maps.makeMap("id", WebexId.translate(messageId), "objectType", ObjectModel.Type.activity)); + body.put("target", Maps.makeMap("id", WebexId.translate(spaceId), "objectType", ObjectModel.Type.conversation)); + Service.Conv.post(body).to("activities").auth(phone.getAuthenticator()).device(phone.getDevice()).async(null); + } + + private void doDownload(@NonNull RemoteFileImpl file, + @Nullable java.io.File path, + boolean thnumnail, + @Nullable ProgressHandler progressHandler, + @NonNull CompletionHandler completionHandler) { + File outFile = path; + if (outFile == null) { + outFile = new java.io.File(context.getCacheDir(), "com.ciscowebex.sdk.downloads"); + outFile.mkdirs(); } - if (reference instanceof Image) { - uri = ((Image) reference).getUrl(); - filename = "thumbnail.png"; + String name = UUID.randomUUID().toString(); + if (file.getDisplayName() != null) { + name = name + "-" + file.getDisplayName(); } - contentManager.getCacheRecord(ConversationContract.ContentDataCacheEntry.Cache.MEDIA, uri, reference.getSecureContentReference(), filename, action, new ContentDownloadMonitor(), callback); - } - - @Override - public void setMessageObserver(MessageObserver observer) { - _observer = observer; - } - - private void processorActivity(Activity activity) { - if (_observer == null) { - return; + if (thnumnail) { + name = "thumb-" + file.getDisplayName(); } - MessageObserver.MessageEvent event; - Message message; - switch (activity.getVerb()) { - case Verb.post: - case Verb.share: - message = createMessage(activity, true); - event = new InternalMessage.InternalMessageReceived(message, activity); - break; - case Verb.delete: - message = createMessage(activity, true); - event = new InternalMessage.InternalMessageDeleted(message.getId(), activity); - break; - default: - Ln.e("unknown verb " + activity.getVerb()); + outFile = new File(outFile, name); + try { + if (!outFile.createNewFile()) { + ResultImpl.errorInMain(completionHandler, "failed to download File " + file.toString()); return; - } - runOnUiThread(() -> _observer.onEvent(event), _observer); - // TODO Remove the deprecated event in next big release - if (event instanceof MessageObserver.MessageReceived) { - runOnUiThread(() -> _observer.onEvent(new InternalMessage.InternalMessageArrived(((MessageObserver.MessageReceived) event).getMessage(), activity)), _observer); + } + DownloadFileOperation operation = new DownloadFileOperation(phone.getCredentials().getAuthenticator(), file.getFile(), progressHandler); + operation.run(outFile, thnumnail, completionHandler); + } catch (Throwable t) { + ResultImpl.errorInMain(completionHandler, t); } } - private void decryptActivity(Activity activity, Action callback) { - final Uri keyUrl = activity.getEncryptionKeyUrl(); - if (keyUrl == null) { - callback.call(activity); + private void doPost(String conversationId, DraftImpl draft, CompletionHandler handler) { + if (TextUtils.isEmpty(conversationId)) { + ResultImpl.errorInMain(handler, "Invalid person or id"); return; } - keyManager.getBoundKeySync(keyUrl).subscribe(keyObject -> { - try { - CryptoUtils.decryptActivity(keyObject, activity); - } catch (Exception ignored) { - } - callback.call(activity); - }); - } - - private void runOnUiThread(Runnable r, Object conditioner) { - if (conditioner == null) return; - Handler handler = new Handler(_context.getMainLooper()); - handler.post(r); - } - - private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5); - private static ScheduledFuture t; - - class CheckUploadProgressTask implements Runnable { - private Uri contentUri; - private LocalFile file; - - CheckUploadProgressTask(LocalFile file) { - super(); - this.file = file; - contentUri = Uri.fromFile(file.getFile()); + Message.Text text = draft.getText(); + Map parent = draft.getParent() == null ? null : Maps.makeMap("id", WebexId.translate(draft.getParent().getId()), "type", "reply"); + Map target = Maps.makeMap("id", conversationId, "objectType", ObjectModel.Type.conversation); + Map object = new HashMap<>(); + object.put("objectType", ObjectModel.Type.comment); + if (text != null) { + object.put("displayName", text.getPlain()); + object.put("content", text.getHtml()); + object.put("markdown", text.getMarkdown()); } - - public void run() { - if (contentUri == null) { - return; - } - int progress; - progress = uploadMonitor.getProgressForKey(contentUri.toString()); - runOnUiThread(() -> { - if (file.getProgressHandler() != null) { - int sendProgress = Math.max(progress, 0); - if (lastSendProgress != sendProgress) { - file.getProgressHandler().onProgress(sendProgress); - lastSendProgress = sendProgress; - } - } - }, file); - if (progress >= 100) { - lastSendProgress = -1; - t.cancel(false); - } - } - } - - private void createSpaceWithPerson(String person, CompletionHandler action) { - EnumSet createFlags = EnumSet.of(NewConversationOperation.CreateFlags.ONE_ON_ONE, NewConversationOperation.CreateFlags.PERSIST_WITHOUT_MESSAGES); - operations.createConversationWithCallBack(Collections.singletonList(person), null, createFlags, - new Action() { - @Override - public void call(NewConversationOperation item) { - Ln.d("createConversationWithCallBack: " + item.getConversationId()); - action.onComplete(ResultImpl.success(item.getConversationId())); - } - - @Override - public void onException(Exception e) { - super.onException(e); - action.onComplete(ResultImpl.error(e)); - } - }); - } - - private Message createMessage(Activity activity, boolean received) { - return activity == null ? null : new InternalMessage(activity, _provider.getAuthenticatedUserOrNull(), received); - } - - private static Comment createComment(Message.Text text, @Nullable Mention[] mentions) { - Comment comment = new Comment(text == null ? null : text.getPlain()); - comment.setContent(text == null ? null : text.getHtml()); - comment.setMarkdown(text == null ? null : text.getMarkdown()); - if (mentions != null && mentions.length > 0) { - ItemCollection mentionedPersons = new ItemCollection<>(); - ItemCollection mentionAll = new ItemCollection<>(); - for (Mention mention : mentions) { + if (!Checker.isEmpty(draft.getMentions())) { + List> mentionedPeople = new ArrayList<>(); + List> mentionedGroup = new ArrayList<>(); + for (Mention mention : draft.getMentions()) { if (mention instanceof Mention.Person) { - WebexId personId = WebexId.from(((Mention.Person) mention).getPersonId()); - if (personId != null) { - Person person = new Person(personId.getId()); - mentionedPersons.addItem(person); - } - } else if (mention instanceof Mention.All) { - mentionAll.addItem(new GroupMention(GroupMention.GroupType.ALL)); + mentionedPeople.add(Maps.makeMap("objectType", ObjectModel.Type.person, "id", WebexId.translate(((Mention.Person) mention).getPersonId()))); + } + else if (mention instanceof Mention.All) { + mentionedGroup.add(Maps.makeMap("objectType", ObjectModel.Type.groupMention, "groupType", "all")); } } - if (mentionAll.size() > 0) { - comment.setGroupMentions(mentionAll); - } else if (mentionedPersons.size() > 0) { - comment.setMentions(mentionedPersons); + if (mentionedPeople.size() > 0) { + object.put("mentions", Maps.makeMap("items", mentionedPeople)); + } + if (mentionedGroup.size() > 0) { + object.put("groupMentions", Maps.makeMap("items", mentionedGroup)); } } - return comment; - } - - // TODO use info in local file - private static File createModleFile(LocalFile localFile, String conversationId, ContentManager contentManager, DatabaseProvider db) { - try { - Uri contentUri = Uri.fromFile(localFile.getFile()); - contentManager.addUploadedContent(new java.io.File(new URI(contentUri.toString())), contentUri, ConversationContract.ContentDataCacheEntry.Cache.MEDIA); - - File modelFile = new File(); - modelFile.setUrl(contentUri); - modelFile.setMimeType(MimeUtils.getMimeType(contentUri.toString())); - modelFile.setDisplayName(contentUri.getLastPathSegment()); - if (localFile.getThumbnail() != null) { - java.io.File thumbFile = localFile.getThumbnail().getFile(); - if (thumbFile.exists() && thumbFile.isFile()) { - Image newThumb = new Image(Uri.fromFile(thumbFile), localFile.getThumbnail().getWidth(), localFile.getThumbnail().getHeight(), null, true); - modelFile.setImage(newThumb); - } + KeyManager.shared.getKey(conversationId, phone.getCredentials(), phone.getDevice(), keyResult -> { + if (keyResult.getError() != null) { + ResultImpl.errorInMain(handler, keyResult); + return; } - return modelFile; - } catch (URISyntaxException e) { - Ln.e(e, "Failed parsing content URI."); - return null; - } finally { - if (db != null && !TextUtils.isEmpty(conversationId)) { - db.notifyChange(ConversationContract.ConversationEntry.getConversationActivitiesUri(conversationId)); + KeyObject key = keyResult.getData(); + if (key != null && text != null) { + object.put("displayName", CryptoUtils.encryptToJwe(key, text.getPlain())); + object.put("content", CryptoUtils.encryptToJwe(key, text.getHtml())); + object.put("markdown", CryptoUtils.encryptToJwe(key, text.getMarkdown())); } - } + UploadFileOperations operations = new UploadFileOperations(draft.getFiles()); + operations.run(phone.getCredentials().getAuthenticator(), phone.getDevice(), conversationId, key, fileModels -> { + if (fileModels.getError() != null) { + ResultImpl.errorInMain(handler, fileModels); + return; + } + ActivityModel.Verb verb = ActivityModel.Verb.post; + if (!Checker.isEmpty(fileModels.getData())) { + object.put("objectType", ObjectModel.Type.content); + object.put("contentCategory", "documents"); + object.put("files", Maps.makeMap("items", fileModels.getData())); + verb = ActivityModel.Verb.share; + } + Map activityMap = new HashMap<>(); + activityMap.put("verb", verb.name()); + activityMap.put("clientTempId", uuid + ":" + UUID.randomUUID().toString()); + activityMap.put("encryptionKeyUrl", key == null ? null :key.getKeyUrl()); + activityMap.put("object", object); + activityMap.put("target", target); + activityMap.put("parent", parent); + Service.Conv.post(activityMap).to("activities") + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .model(ActivityModel.class) + .error(handler) + .async((Closure) model -> { + model.decrypt(key); + ResultImpl.inMain(handler, createMessage(model, false)); + }); + }); + }); } - private interface MessageService { - @GET("messages") - Call> list(@Header("Authorization") String authorization, - @Query("roomId") String roomId, - @Query("spaceId") String spaceId, - @Query("before") String before, - @Query("beforeMessage") String beforeMessage, - @Query("mentionedPeople") String mentionedPeople, - @Query("max") Integer max); - - @POST("messages") - Call post(@Header("Authorization") String authorization, @Body Map parameters); - - @GET("messages/{messageId}") - Call get(@Header("Authorization") String authorization, @Path("messageId") String messageId); + private void getOrCreateConversation(String person, CompletionHandler handler) { + Queue.background.run(() -> { + String conversionId = conversations.get(person); + if (conversionId != null) { + handler.onComplete(ResultImpl.success(conversionId)); + return; + } + Service.Conv.put().to("conversations", "user", person) + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .queue(Queue.background) + .model(ConversationModel.class) + .error(handler) + .async((Closure) model -> { + if (model == null || model.getId() == null) { + handler.onComplete(ResultImpl.error("Cannot get conversion with the people: " + person)); + return; + } + conversations.put(person, model.getId()); + handler.onComplete(ResultImpl.success(model.getId())); + }); + }); + } - @DELETE("messages/{messageId}") - Call delete(@Header("Authorization") String authorization, @Path("messageId") String messageId); + private Message createMessage(ActivityModel activity, boolean received) { + return activity == null ? null : new InternalMessage(activity, phone.getCredentials(), received); } @Override @@ -714,7 +459,7 @@ public void list(@NonNull String spaceId, @Nullable String before, @Nullable Str } else if (beforeMessage != null) { b = new Before.Message(beforeMessage); } - list(spaceId, b, max, mentions == null ? null : mentions.toArray(new Mention[mentions.size()]), handler); + list(spaceId, b, max, mentions == null ? null : mentions.toArray(new Mention[0]), handler); } @Override @@ -754,13 +499,5 @@ public void post(@NonNull String idOrEmail, @Nullable String text, @Nullable Men } } - @Override - public void markAsRead(@NonNull String spaceId) { - operations.submit(new MessageMarkReadOperation(injector, spaceId)); - } - @Override - public void markAsRead(@NonNull String spaceId, String messageId) { - operations.submit(new MessageMarkReadOperation(injector, spaceId, messageId)); - } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageMarkReadOperation.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageMarkReadOperation.java deleted file mode 100644 index 1157b567..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/MessageMarkReadOperation.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.ciscowebex.androidsdk.message.internal; - -import com.cisco.spark.android.core.Injector; -import com.cisco.spark.android.model.ActivityReference; -import com.cisco.spark.android.model.Verb; -import com.cisco.spark.android.model.conversation.Activity; -import com.cisco.spark.android.sync.SparkDatabaseQueries; -import com.cisco.spark.android.sync.operationqueue.MarkReadOperation; -import com.ciscowebex.androidsdk.utils.WebexId; -import com.github.benoitdion.ln.Ln; - -import java.util.Date; - -public class MessageMarkReadOperation extends MarkReadOperation { - - private String activityId; - - MessageMarkReadOperation(Injector injector, String spaceId) { - super(injector, WebexId.translate(spaceId)); - } - - MessageMarkReadOperation(Injector injector, String spaceId, String messageId) { - super(injector, WebexId.translate(spaceId)); - this.activityId = WebexId.translate(messageId); - } - - @Override - protected void configureActivity() { - super.configureActivity(Verb.acknowledge); - long lastSelfAckTimestamp = SparkDatabaseQueries.getLastSelfAckTimestamp(getDatabaseProvider(), getConversationId()); - ActivityReference activityReference; - if (null == activityId) { - activityReference = SparkDatabaseQueries.getLastAckableActivity(getDatabaseProvider(), conversationId); - } else { - activityReference = SparkDatabaseQueries.getActivityReference(getDatabaseProvider(), activityId); - } - if (activityReference == null) { - Ln.i("Failed marking conversation read because it has no activities"); - cancel(); - return; - } - if (lastSelfAckTimestamp >= activityReference.getPublishTime()) { - Ln.d("Not sending an ack for conversation activity at time " + activityReference.getPublishTime() + " because we've already sent an ack for a more recent activity in this conversation"); - cancel(); - return; - } - Activity object = new Activity(); - object.setId(activityReference.getActivityId()); - object.setPublished(new Date(activityReference.getPublishTime())); - object.setActivityType(activityReference.getType()); - activity.setObject(object); - } - -} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/RemoteFileImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/RemoteFileImpl.java index 22b42e8c..65b4c19e 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/RemoteFileImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/RemoteFileImpl.java @@ -1,41 +1,63 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.message.internal; -import android.net.Uri; import android.support.annotation.NonNull; -import com.cisco.spark.android.model.conversation.File; -import com.cisco.spark.android.model.conversation.Image; +import com.ciscowebex.androidsdk.internal.model.FileModel; +import com.ciscowebex.androidsdk.internal.model.ImageModel; import com.ciscowebex.androidsdk.message.RemoteFile; public class RemoteFileImpl implements RemoteFile { - public class ThumbnailImpl implements Thumbnail{ + public static class ThumbnailImpl implements Thumbnail{ - private Image image; + private ImageModel image; private String mimeType; - public ThumbnailImpl(@NonNull Image image) { + public ThumbnailImpl(@NonNull ImageModel image) { this.image = image; } - Image getImage() { + ImageModel getImage() { return this.image; } public int getWidth() { - return image.getWidth(); + return image == null ? 0 : image.getWidth(); } public int getHeight() { - return image.getHeight(); + return image == null ? 0 : image.getHeight(); } + @Deprecated public String getMimeType() { return mimeType; } @Deprecated public String getUrl() { - return image.getUrl().toString(); + return image.getUrl(); } @Deprecated @@ -56,17 +78,17 @@ public void setHeight(int height) { } } - private File file; + private FileModel file; private Thumbnail thumbnail; - public RemoteFileImpl(@NonNull File file) { + public RemoteFileImpl(@NonNull FileModel file) { this.file = file; if (file.getImage() != null) { this.thumbnail = new ThumbnailImpl(file.getImage()); } } - File getFile() { + FileModel getFile() { return file; } @@ -87,7 +109,7 @@ public String getMimeType() { @Override public String getUrl() { - return file.getUrl().toString(); + return file.getUrl(); } @Override @@ -121,7 +143,7 @@ public void setMimeType(String mimeType) { @Override @Deprecated public void setUrl(String url) { - file.setUrl(Uri.parse(url)); + file.setUrl(url); } @Override diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/UploadFileOperations.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/UploadFileOperations.java new file mode 100644 index 00000000..81912531 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/internal/UploadFileOperations.java @@ -0,0 +1,167 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.message.internal; + +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.crypto.TypedSecureContentReferenceOutput; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.internal.queue.SerialQueue; +import com.ciscowebex.androidsdk.internal.Device; +import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.crypto.KeyObject; +import com.ciscowebex.androidsdk.internal.crypto.SecureContentReference; +import com.ciscowebex.androidsdk.internal.model.FileModel; +import com.ciscowebex.androidsdk.internal.model.ImageModel; +import com.ciscowebex.androidsdk.internal.model.UploadSessionModel; +import com.ciscowebex.androidsdk.message.LocalFile; +import com.ciscowebex.androidsdk.utils.Metadata; +import com.ciscowebex.androidsdk.utils.MimeUtils; +import com.google.gson.reflect.TypeToken; +import me.helloworld.utils.Checker; +import me.helloworld.utils.Objects; +import me.helloworld.utils.collection.Maps; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class UploadFileOperations { + + private SerialQueue queue = new SerialQueue(SerialQueue.Mode.BACKGROUND); + private List operations = new ArrayList<>(); + + public UploadFileOperations(List locals) { + if (locals != null) { + for (LocalFile local : locals) { + operations.add(new Operation(local)); + } + } + } + + public void run(Authenticator authenticator, Device device, String conversationId, KeyObject key, CompletionHandler> callback) { + if (Checker.isEmpty(operations)) { + callback.onComplete(ResultImpl.success(Collections.emptyList())); + return; + } + getSpaceUrl(authenticator, device, conversationId, spaceUrl -> { + if (spaceUrl == null || spaceUrl.getData() == null) { + callback.onComplete(ResultImpl.error(spaceUrl)); + return; + } + List success = new ArrayList<>(); + for (Operation op : operations) { + if (!op.done) { + queue.run(() -> op.run(authenticator, spaceUrl.getData(), key, result -> { + if (result.getData() != null) { + success.add(result.getData()); + } + queue.yield(); + })); + } + } + queue.run(() -> callback.onComplete(ResultImpl.success(success))); + }); + } + + private static class Operation { + + private LocalFile local; + + private boolean done = false; + + private Operation(LocalFile local) { + this.local = local; + } + + private void run(Authenticator authenticator, String spaceUrl, KeyObject key, CompletionHandler callback) { + doUpload(authenticator, spaceUrl, local.getFile(), false, uploadResult -> { + if (uploadResult.getData() == null || uploadResult.getError() != null) { + callback.onComplete(ResultImpl.error(uploadResult)); + return; + } + FileModel uploaded = uploadResult.getData(); + uploaded.setDisplayName(local.getName()); + uploaded.setMimeType(local.getMimeType()); + LocalFile.Thumbnail thumbnail = local.getThumbnail(); + if (thumbnail != null && thumbnail.getFile() != null) { + doUpload(authenticator, spaceUrl, thumbnail.getFile(), true, thumbnailResult -> { + if (thumbnailResult != null && thumbnailResult.getData() != null) { + ImageModel image = new ImageModel(thumbnailResult.getData().getUrl(), thumbnail.getWidth(), thumbnail.getHeight(), thumbnailResult.getData().getSecureContentReference(), true); + uploaded.setImage(image); + } + uploaded.encrypt(key); + callback.onComplete(ResultImpl.success(uploaded)); + }); + return; + } + uploaded.encrypt(key); + callback.onComplete(ResultImpl.success(uploaded)); + }); + } + + private void doUpload(Authenticator authenticator, String spaceUrl, java.io.File file, boolean thumbnial, CompletionHandler callback) { +// Metadata metadata = new Metadata(file); +// metadata.sanitize(); + String mimeType = MimeUtils.getMimeType(file.getAbsolutePath()); + if (mimeType == null) { + mimeType = "application/unknown"; + } + TypedSecureContentReferenceOutput typedOutput = new TypedSecureContentReferenceOutput(mimeType, file, progress -> { + if (local.getProgressHandler() != null && !thumbnial) { + Queue.main.run(() -> local.getProgressHandler().onProgress(progress)); + } + }); + Service.Common.post(Maps.makeMap("uploadProtocol", "content-length")).url(spaceUrl).to("upload_sessions").auth(authenticator).model(UploadSessionModel.class).error(callback) + .async((Closure) sessionModel -> Service.Common.put(typedOutput).url(sessionModel.getUploadUrl()).error(callback) + .async((Closure) uploaded -> Service.Common.post(Maps.makeMap("size", file.length())).url(sessionModel.getFinishUploadUrl()).auth(authenticator).model(FileModel.class).error(callback) + .async((Closure) finish -> { + if (finish == null) { + callback.onComplete(ResultImpl.error("Cannot download the uploaded file")); + return; + } + finish.setUrl(finish.getUrl() + "/versions/" + finish.getVersion() + "/bytes"); + SecureContentReference scr = typedOutput.getSecureContentReference(); + scr.setLoc(finish.getUrl()); + finish.setSecureContentReference(scr); + finish.setFileSize(file.length()); + callback.onComplete(ResultImpl.success(finish)); + }))); + } + } + + private void getSpaceUrl(Authenticator authenticator, Device device, String conversionId, CompletionHandler callback) { + Service.Conv.put().to("conversations", conversionId, "space").auth(authenticator).device(device).model(new TypeToken>() { + }.getType()).error(callback).async((Closure>) map -> { + String spaceUrl = map == null ? null : Objects.toString(map.get("spaceUrl"), null); + if (spaceUrl == null) { + callback.onComplete(ResultImpl.error("No spaceUrl")); + return; + } + callback.onComplete(ResultImpl.success(spaceUrl)); + }); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/people/internal/PersonClientImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/people/internal/PersonClientImpl.java index 08842bb7..579efc26 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/people/internal/PersonClientImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/people/internal/PersonClientImpl.java @@ -26,99 +26,95 @@ import android.support.annotation.Nullable; import java.util.List; -import java.util.Map; import com.ciscowebex.androidsdk.CompletionHandler; import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.queue.Queue; import com.ciscowebex.androidsdk.people.Person; import com.ciscowebex.androidsdk.people.PersonClient; -import com.ciscowebex.androidsdk.utils.http.ListBody; -import com.ciscowebex.androidsdk.utils.http.ListCallback; -import com.ciscowebex.androidsdk.utils.http.ObjectCallback; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; +import com.ciscowebex.androidsdk.internal.model.ItemsModel; +import com.google.gson.reflect.TypeToken; import me.helloworld.utils.collection.Maps; -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.GET; -import retrofit2.http.Header; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; -import retrofit2.http.Query; +import org.jetbrains.annotations.NotNull; public class PersonClientImpl implements PersonClient { - private Authenticator _authenticator; - - private PersonService _service; + private Authenticator authenticator; public PersonClientImpl(Authenticator authenticator) { - _authenticator = authenticator; - _service = new ServiceBuilder().build(PersonService.class); + this.authenticator = authenticator; } - public void list(String email, String displayName, int max, CompletionHandler> handler) { + public void list(@NotNull String email, String displayName, int max, @NotNull CompletionHandler> handler) { this.list(email, displayName, null, null, max, handler); } - public void list(String email, String displayName, String id, String orgId, int max, CompletionHandler> handler) { - ServiceBuilder.async(_authenticator, handler, s -> _service.list(s, email, displayName, id, orgId, max <= 0 ? null : max), new ListCallback<>(handler)); + public void list(String email, String displayName, String id, String orgId, int max, @NotNull CompletionHandler> handler) { + Service.Hydra.get("people") + .with("email", email) + .with("displayName", displayName) + .with("id", id) + .with("orgId", orgId) + .with("max", max <= 0 ? null : String.valueOf(max)) + .auth(authenticator) + .queue(Queue.main) + .model(new TypeToken>(){}.getType()) + .error(handler) + .async((Closure>) result -> handler.onComplete(ResultImpl.success(result.getItems()))); } - public void get(String personId, CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.get(s, personId), new ObjectCallback<>(handler)); + public void get(@NotNull String personId, @NotNull CompletionHandler handler) { + Service.Hydra.get("people", personId) + .auth(authenticator) + .queue(Queue.main) + .model(Person.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } - public void getMe(CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.getMe(s), new ObjectCallback<>(handler)); + public void getMe(@NotNull CompletionHandler handler) { + Service.Hydra.get("people", "me") + .auth(authenticator) + .queue(Queue.main) + .model(Person.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override public void create(@NonNull String email, @Nullable String displayName, @Nullable String firstName, @Nullable String lastName, @Nullable String avatar, @Nullable String orgId, @Nullable String roles, @Nullable String licenses, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.create(s, Maps.makeMap("email", email, "displayName", displayName, "firstName", firstName, "lastName", lastName - , "avatar", avatar, "orgId", orgId, "roles", roles, "licenses", licenses)), new ObjectCallback<>(handler)); + Service.Hydra.post(Maps.makeMap("email", email, "displayName", displayName, "firstName", firstName, "lastName", lastName, + "avatar", avatar, "orgId", orgId, "roles", roles, "licenses", licenses)).to("people") + .auth(authenticator) + .queue(Queue.main) + .model(Person.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override public void update(@NonNull String personId, @Nullable String email, @Nullable String displayName, @Nullable String firstName, @Nullable String lastName, @Nullable String avatar, @Nullable String orgId, @Nullable String roles, @Nullable String licenses, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.update(s, personId, Maps.makeMap("email", email, "displayName", displayName, "firstName", firstName, "lastName", lastName - , "avatar", avatar, "orgId", orgId, "roles", roles, "licenses", licenses)), new ObjectCallback<>(handler)); + Service.Hydra.put(Maps.makeMap("email", email, "displayName", displayName, "firstName", firstName, "lastName", lastName, + "avatar", avatar, "orgId", orgId, "roles", roles, "licenses", licenses)).to("people", personId) + .auth(authenticator) + .queue(Queue.main) + .model(Person.class) + .error(handler) + .async((Closure) result -> { + handler.onComplete(ResultImpl.success(result)); + }); } @Override public void delete(@NonNull String personId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.delete(s, personId), new ObjectCallback<>(handler)); - } - - private interface PersonService { - @GET("people") - Call> list(@Header("Authorization") String authorizationHeader, - @Query("email") String email, - @Query("displayName") String displayName, - @Query("id") String id, - @Query("orgId") String orgId, - @Query("max") Integer max); - - @GET("people/{personId}") - Call get(@Header("Authorization") String authorizationHeader, @Path("personId") String personId); - - @GET("people/me") - Call getMe(@Header("Authorization") String authorizationHeader); - - @POST("people") - Call create(@Header("Authorization") String authorizationHeader, @Body Map parameters); - - @PUT("people/{personId}") - Call update(@Header("Authorization") String authorization, @Path("personId") String personId, @Body Map parameters); - - @DELETE("people/{personId}") - Call delete(@Header("Authorization") String authorization, @Path("personId") String personId); + Service.Hydra.delete("people", personId) + .auth(authenticator) + .queue(Queue.main) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/AuxStream.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/AuxStream.java index 07eb81b4..6c034bec 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/AuxStream.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/AuxStream.java @@ -1,6 +1,7 @@ package com.ciscowebex.androidsdk.phone; import android.graphics.Rect; +import android.util.Size; import android.view.View; @@ -23,7 +24,7 @@ public interface AuxStream { * @return the video dimensions of this auxiliary stream in pixels * @since 2.0.0 */ - Rect getSize(); + Size getSize(); /** * @return the person represented this auxiliary stream @@ -40,7 +41,9 @@ public interface AuxStream { /** * Update the auxiliary stream view. When the view size is changed, you may need to refresh the view. * @since 2.0.0 + * @deprecated */ + @Deprecated void refresh(); /** diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/Call.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/Call.java index d98bb9a5..c2f4b2c4 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/Call.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/Call.java @@ -24,13 +24,11 @@ import java.util.List; -import android.graphics.Rect; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.cisco.spark.android.locus.model.LocusParticipant; +import android.util.Size; import com.ciscowebex.androidsdk.CompletionHandler; -import com.google.gson.JsonArray; import android.view.View; import android.util.Pair; @@ -181,19 +179,19 @@ enum WaitReason{ * @return The local video render view dimensions (points) of this call. * @since 0.1 */ - Rect getLocalVideoViewSize(); + Size getLocalVideoViewSize(); /** * @return The remote video render view dimensions (points) of this call. * @since 0.1 */ - Rect getRemoteVideoViewSize(); + Size getRemoteVideoViewSize(); /** * @return The content sharing render view dimensions (points) of this call. * @since 1.3.0 */ - Rect getSharingViewSize(); + Size getSharingViewSize(); /** * @return True if the remote party of this call is sending video. Otherwise, false. @@ -377,6 +375,12 @@ enum WaitReason{ */ boolean isSendingSharing(); + /** + * @param sending True if this call is sharing content. Otherwise, false. + * @since 2.5.0 + */ + void setSendingSharing(boolean sending); + /** * Open a new auxiliary stream with a view. The Maximum of auxiliary streams can be opened is 4 currently. * You can invoke this API instead of {@link MultiStreamObserver#onAuxStreamAvailable} to open an available auxiliary stream diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/CallMembership.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/CallMembership.java index efb27cb3..c4f9dbb6 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/CallMembership.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/CallMembership.java @@ -132,4 +132,10 @@ enum State { * @since 1.3.0 */ boolean isSendingSharing(); + + /** + * @return True if this `CallMembership` is speaking in this meeting and video is prsenting on remote media render view. Otherwise, false. + * @since 2.5.0 + */ + boolean isActiveSpeaker(); } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/CallObserver.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/CallObserver.java index 87be2821..566b16f2 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/CallObserver.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/CallObserver.java @@ -555,6 +555,17 @@ public LocalVideoViewSizeChanged(Call call) { } } + /** + * Local video rendering view size has changed. + * + * @since 2.5.0 + */ + class LocalSharingViewSizeChanged extends AbstractCallEvent implements MediaChangedEvent { + public LocalSharingViewSizeChanged(Call call) { + super(call); + } + } + /** * Remote video rendering view size has changed. * diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/MediaOption.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/MediaOption.java index 07038d28..4b189428 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/MediaOption.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/MediaOption.java @@ -34,6 +34,15 @@ */ public class MediaOption { + /** + * The video layout for the active speaker and other attendees in the group video meeting. + * + * @since 2.5.0 + */ + public enum VideoLayout { + SINGLE, FILMSTRIP, GRID + } + /** * Constructs an audio only media option. * @@ -82,14 +91,11 @@ public static MediaOption audioVideoSharing(@Nullable Pair videoRend } private View _remoteView; - private View _localView; - private View _sharingView; - private boolean _hasSharing; - private boolean _hasVideo; + private VideoLayout layout; private MediaOption(@Nullable View localView, @Nullable View remoteView, @Nullable View sharingView, boolean hasSharing, boolean hasVideo) { _localView = localView; @@ -143,4 +149,21 @@ public View getSharingView() { return _sharingView; } + /** + * Returns the video layout of the active speaker and other attendees for the group video call. + * + * @since 2.5.0 + */ + public VideoLayout getLayout() { + return layout; + } + + /** + * Set the video layout of the active speaker and other attendees for the group video call. + * + * @since 2.5.0 + */ + public void setLayout(VideoLayout layout) { + this.layout = layout; + } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/MultiStreamObserver.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/MultiStreamObserver.java index 7cb63e16..bf372948 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/MultiStreamObserver.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/MultiStreamObserver.java @@ -97,8 +97,9 @@ class AuxStreamOpenedEvent extends AbstractAuxStreamChangedEvent { public AuxStreamOpenedEvent(Call call, View view, String error) { super(call, error == null ? call.getAuxStream(view) : null); _view = view; - if (error != null) + if (error != null) { _error = new WebexError(WebexError.ErrorCode.UNEXPECTED_ERROR, error); + } } /** diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/AuxStreamImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/AuxStreamImpl.java index f8bace05..015e0077 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/AuxStreamImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/AuxStreamImpl.java @@ -1,88 +1,88 @@ -package com.ciscowebex.androidsdk.phone.internal; +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.ciscowebex.androidsdk.phone.internal; -import android.graphics.Rect; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import android.util.Size; import android.view.View; -import com.cisco.spark.android.locus.model.LocusKey; import com.ciscowebex.androidsdk.phone.CallMembership; import com.ciscowebex.androidsdk.phone.AuxStream; -/** - * Created by qimdeng on 8/8/18. - */ - public class AuxStreamImpl implements AuxStream { - private @NonNull - LocusKey _key; - - private @NonNull PhoneImpl _phone; - private @NonNull long _vid; + private CallImpl call; - private View _renderView; + private int vid; - private boolean isSendingVideo; + private View view; - private CallMembership _person; + private CallMembership person; - private Rect _size; + AuxStreamImpl(CallImpl call, int vid, View view) { + this.call = call; + this.vid = vid; + this.view = view; + } - AuxStreamImpl(@NonNull LocusKey key, @NonNull PhoneImpl phone, @NonNull long vid, @Nullable View view) { - _key = key; - _phone = phone; - _vid = vid; - _renderView = view; + public int getVid() { + return vid; } - public long getVid(){return _vid;} + public void setVid(int vid) { + this.vid = vid; + } @Override public View getRenderView() { - return _renderView; + return view; } @Override + @Deprecated public void refresh() { - if (_renderView != null){ - _phone.getCallService().updateRemoteWindowForVid(_key, _vid, _renderView); - } } @Override public boolean isSendingVideo() { - return isSendingVideo; + return call.getMedia() != null && !call.getMedia().isAuxVideoRemoteMuted(vid); } @Override - public void close() { - CallImpl call = _phone.getCall(_key); - if (call != null){ - call.closeAuxStream(this, _renderView); - } - } - - public void setSendingVideo(boolean isSending){ - isSendingVideo = isSending; + public Size getSize() { + return call.getMedia() == null ? new Size(0, 0) : call.getMedia().getAuxVideoViewSize(vid); } @Override - public Rect getSize() { - return _size; - } - - public void setSize(Rect size){ - _size = size; + public void close() { + call.closeAuxStream(view); } @Override public CallMembership getPerson() { - return _person; + return person; } public void setPerson(CallMembership person) { - _person = person; + this.person = person; } } \ No newline at end of file diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallContext.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallContext.java new file mode 100644 index 00000000..433ee89c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallContext.java @@ -0,0 +1,101 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.phone.internal; + +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.phone.Call; +import com.ciscowebex.androidsdk.phone.MediaOption; + +public abstract class CallContext { + + private MediaOption option; + + public MediaOption getOption() { + return option; + } + + public CallContext(MediaOption option) { + this.option = option; + } + + static class Incoming extends CallContext { + + private CompletionHandler callback; + private CallImpl call; + + public Incoming(CallImpl call, MediaOption option, CompletionHandler callback) { + super(option); + this.callback = callback; + this.call = call; + } + + public CompletionHandler getCallback() { + return callback; + } + + public CallImpl getCall() { + return call; + } + } + + static class Outgoing extends CallContext { + + private CompletionHandler callback; + private String target; + + public Outgoing(String target, MediaOption option, CompletionHandler callback) { + super(option); + this.target = target; + this.callback = callback; + } + + public CompletionHandler getCallback() { + return callback; + } + + public String getTarget() { + return target; + } + + } + + static class Sharing extends CallContext { + private CompletionHandler callback; + private CallImpl call; + + public Sharing(CallImpl call, CompletionHandler callback) { + super(null); + this.call = call; + this.callback = callback; + } + + public CompletionHandler getCallback() { + return callback; + } + + public CallImpl getCall() { + return call; + } + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallImpl.java index 49ab4964..c7a774bc 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallImpl.java @@ -22,201 +22,151 @@ package com.ciscowebex.androidsdk.phone.internal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import android.graphics.Rect; -import android.util.Pair; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.View; import android.support.annotation.NonNull; import android.support.annotation.Nullable; - -import com.cisco.spark.android.callcontrol.CallControlService; -import com.cisco.spark.android.callcontrol.events.CallControlMediaDecodeSizeChangedEvent; -import com.cisco.spark.android.events.OperationCompletedEvent; -import com.cisco.spark.android.locus.model.Locus; -import com.cisco.spark.android.locus.model.LocusData; -import com.cisco.spark.android.locus.model.LocusKey; -import com.cisco.spark.android.locus.model.LocusParticipant; -import com.cisco.spark.android.locus.model.LocusSelfRepresentation; -import com.cisco.spark.android.locus.model.MediaDirection; -import com.cisco.spark.android.locus.model.MediaShare; -import com.cisco.spark.android.media.MediaEngine; -import com.cisco.spark.android.media.MediaRequestSource; -import com.cisco.spark.android.media.MediaSession; -import com.cisco.spark.android.sync.operationqueue.SendDtmfOperation; -import com.cisco.spark.android.sync.operationqueue.core.Operation; +import android.util.Pair; +import android.util.Size; +import android.view.View; import com.ciscowebex.androidsdk.CompletionHandler; -import com.ciscowebex.androidsdk.internal.ResultImpl; -import com.ciscowebex.androidsdk.phone.AuxStream; -import com.ciscowebex.androidsdk.phone.Call; -import com.ciscowebex.androidsdk.phone.CallMembership; -import com.ciscowebex.androidsdk.phone.CallObserver; -import com.ciscowebex.androidsdk.phone.MediaOption; -import com.ciscowebex.androidsdk.phone.MultiStreamObserver; -import com.ciscowebex.androidsdk.phone.Phone; -import com.ciscowebex.androidsdk.utils.Utils; -import com.ciscowebex.androidsdk.utils.WebexId; +import com.ciscowebex.androidsdk.WebexError; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.internal.queue.Scheduler; +import com.ciscowebex.androidsdk.internal.Device; +import com.ciscowebex.androidsdk.internal.model.*; +import com.ciscowebex.androidsdk.phone.*; +import com.ciscowebex.androidsdk.utils.Lists; import com.github.benoitdion.ln.Ln; -import com.google.gson.JsonArray; - +import me.helloworld.utils.Checker; import me.helloworld.utils.Objects; -import me.helloworld.utils.annotation.StringPart; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; public class CallImpl implements Call { - private @NonNull - PhoneImpl _phone; - - @StringPart - private @NonNull - CallStatus _status; - - @StringPart - private @NonNull - Direction _direction; - - @StringPart - private @NonNull - LocusKey _key; - - private MediaOption _option; - - private CallObserver _observer; - - private CompletionHandler _answerCallback; + private final PhoneImpl phone; + private final Device device; + private final Direction direction; + private final boolean group; - private CompletionHandler _rejectCallback; + private @Nullable MediaSession media; + private CallObserver observer; + private MultiStreamObserver streamObserver; + private CallStatus status = CallStatus.INITIATED; + private LocusModel model; - private CompletionHandler _hangupCallback; + private List memberships = new ArrayList<>(); + private List streams = new ArrayList<>(); + private CallMembershipImpl activeSpeaker; + private int availableStreamCount = 0; - private CompletionHandler _shareRequestCallback; + private boolean sendingVideo = true; + private boolean sendingAudio = true; + private boolean receivingVideo = true; + private boolean receivingAudio = true; - private CompletionHandler _shareReleaseCallback; + private Pair videoViews; + private View sharingView; - private Rect _localVideoViewSize = new Rect(0, 0, 0, 0); + private TimerTask keepAliveTask; + private AtomicInteger predicate = new AtomicInteger(0); + private AtomicInteger dtmfCorrelation = new AtomicInteger(1); - private Rect _remoteVideoViewSize = new Rect(0, 0, 0, 0); - - private Rect _sharingViewSize = new Rect(0, 0, 0, 0); - - private Map> _dtmfOperations = new HashMap<>(1); - - private boolean _isGroup; - - private View _sharingRenderView; - - private Pair _videoRenderViews; - - private List _openedAuxStreamList = new ArrayList<>(); - - private int _availableAuxStreamCount; - - private CallMembership _activeSpeaker; - - private MultiStreamObserver _multiStreamObserver; - - CallImpl(@NonNull PhoneImpl phone, @Nullable MediaOption option, @NonNull Direction direction, @NonNull LocusKey key, boolean group) { - _phone = phone; - _direction = direction; - _key = key; - _status = CallStatus.INITIATED; - _isGroup = group; - setMediaOption(option); + public CallImpl(LocusModel model, PhoneImpl phone, Device device, MediaSession media, Direction direction, boolean group) { + this.phone = phone; + this.model = model; + this.device = device; + this.direction = direction; + this.group = (group ? group : !model.isOneOnOne()); + setMedia(media); + doLocusModel(model); } - @NonNull - LocusKey getKey() { - return _key; + LocusModel getModel() { + return model; } - void setStatus(@NonNull CallStatus status) { - Ln.d("CallStatus from " + _status + " to " + status + ", " + this); - _status = status; + public String getUrl() { + return getModel().getCallUrl(); } - MediaOption getOption() { - return _option; + @Nullable + MediaSession getMedia() { + return media; } - void setMediaOption(@Nullable MediaOption option) { - _option = option; - if (option != null) { - if (option.getLocalView() != null && option.getRemoteView() != null) { - _videoRenderViews = new Pair<>(option.getLocalView(), option.getRemoteView()); - } else { - _videoRenderViews = null; - } - _sharingRenderView = option.getSharingView(); + void setMedia(MediaSession media) { + this.media = media; + if (media != null) { + this.videoViews = media.getVideoViews(); + this.sharingView = media.getSharingView(); } } - CompletionHandler getAnswerCallback() { - return _answerCallback; + boolean isGroup() { + return group; } - CompletionHandler getRejectCallback() { - return _rejectCallback; + void setStatus(CallStatus status) { + Ln.d("Call status changed from " + this.status + " to " + status); + this.status = status; } - CompletionHandler getHangupCallback() { - return _hangupCallback; + @Override + public Phone.FacingMode getFacingMode() { + return media == null ? phone.getDefaultFacingMode() : media.getFacingMode(); } - CompletionHandler getShareRequestCallback() { - return _shareRequestCallback; + @Override + public void setFacingMode(Phone.FacingMode facingMode) { + if (media != null) { + media.setFacingMode(facingMode); + } } - CompletionHandler getShareReleaseCallback() { - return _shareReleaseCallback; + @Override + public Direction getDirection() { + return direction; } - @NonNull + @Override public CallStatus getStatus() { - return _status; - } - - @NonNull - public Call.Direction getDirection() { - return _direction; + return status; } + @Override public void setObserver(CallObserver observer) { - _observer = observer; + this.observer = observer; + Queue.serial.run(() -> { + if (observer != null) { + if (status == CallStatus.RINGING) { + Queue.main.run(() -> observer.onRinging(CallImpl.this)); + } else if (status == CallStatus.WAITING) { + Queue.main.run(() -> observer.onWaiting(CallImpl.this, model.getWaitReason())); + } else if (status == CallStatus.CONNECTED) { + Queue.main.run(() -> observer.onConnected(CallImpl.this)); + } + } + Queue.serial.yield(); + }); } + @Override public CallObserver getObserver() { - return _observer; + return observer; } + @Override public List getMemberships() { - List participants = getParticipants(); - List memberships = new ArrayList<>(participants.size()); - for (LocusParticipant p : participants) { - memberships.add(new CallMembershipImpl(p, this)); - } - return memberships; - } - - public List getJoinedMemberships() { - List participants = getParticipants(); - List memberships = new ArrayList<>(participants.size()); - for (LocusParticipant p : participants) { - if (p.getState() == LocusParticipant.State.JOINED) - memberships.add(new CallMembershipImpl(p, this)); + synchronized (this) { + return Collections.unmodifiableList(memberships); } - return memberships; } + @Override public CallMembership getFrom() { - for (CallMembership membership : getMemberships()) { + List memberships = getMemberships(); + for (CallMembership membership : memberships) { if (membership.isInitiator()) { return membership; } @@ -224,8 +174,10 @@ public CallMembership getFrom() { return null; } + @Override public CallMembership getTo() { - for (CallMembership membership : getMemberships()) { + List memberships = getMemberships(); + for (CallMembership membership : memberships) { if (!membership.isInitiator()) { return membership; } @@ -233,605 +185,981 @@ public CallMembership getTo() { return null; } - public Rect getLocalVideoViewSize() { - return _localVideoViewSize; + @Override + public Size getLocalVideoViewSize() { + return media == null ? new Size(0, 0) : media.getLocalVideoViewSize(); } - public Rect getRemoteVideoViewSize() { - return _remoteVideoViewSize; + @Override + public Size getRemoteVideoViewSize() { + return media == null ? new Size(0, 0) : media.getRemoteVideoViewSize(); + } + + @Override + public Size getSharingViewSize() { + return media == null ? new Size(0, 0) : media.getRemoteSharingViewSize(); } - public Rect getSharingViewSize() { - return _sharingViewSize; + @Override + public boolean isSendingDTMFEnabled() { + return getModel().isLocalSupportDTMF(); } + @Override public boolean isRemoteSendingVideo() { - return _phone.getRemoteSendingVideo(); + return media != null && media.isRemoteVideoSending(); } + @Override public boolean isRemoteSendingAudio() { - for (LocusParticipant p : getRemoteParticipants()) { - if (p.getState() == LocusParticipant.State.JOINED && p.getStatus() != null) { - MediaDirection direction = p.getStatus().getAudioStatus(); - if (direction == null || direction == MediaDirection.SENDONLY || direction == MediaDirection.SENDRECV) { - return true; - } - } - } - return false; + return !model.isRemoteAudioMuted(); } + @Override public boolean isRemoteSendingSharing() { - LocusData locus = _phone.getCallService().getLocusData(getKey()); - return locus != null && locus.isFloorGranted() && !_phone.isSharingFromThisDevice(locus); + return model.isFloorGranted() && !isSharingFromThisDevice(); } - public boolean isSendingSharing() { - LocusData locus = _phone.getCallService().getLocusData(getKey()); - return locus != null && _phone.isSharingFromThisDevice(locus); + @Override + public boolean isSendingVideo() { + return media != null && media.hasVideo() && media.isLocalVideoSending(); } @Override - public int getOpenedAuxStreamCount() { - return _openedAuxStreamList.size(); + public void setSendingVideo(boolean sending) { + if (media != null) { + media.setLocalVideoSending(sending); + sendingVideo = sending; + } } - public void setAvailableAuxStreamCount(int count) { - _availableAuxStreamCount = count; + @Override + public boolean isSendingAudio() { + return media != null && media.hasAudio() && media.isLocalAudioSending(); } @Override - public int getAvailableAuxStreamCount() { - return _availableAuxStreamCount; + public void setSendingAudio(boolean sending) { + if (media != null) { + media.setLocalAudioSending(sending); + sendingAudio = sending; + } } - public void setActiveSpeaker(CallMembership person) { - _activeSpeaker = person; + @Override + public boolean isReceivingVideo() { + return media != null && media.hasVideo() && media.isRemoteVideoReceiving(); } @Override - public CallMembership getActiveSpeaker() { - return _activeSpeaker; + public void setReceivingVideo(boolean receiving) { + if (media != null) { + media.setRemoteVideoReceiving(receiving); + receivingVideo = receiving; + } } @Override - public void setMultiStreamObserver(MultiStreamObserver observer) { - _multiStreamObserver = observer; + public boolean isReceivingAudio() { + return media != null && media.hasAudio() && media.isRemoteAudioReceiving(); } @Override - public MultiStreamObserver getMultiStreamObserver() { - return _multiStreamObserver; + public void setReceivingAudio(boolean receiving) { + if (media != null) { + media.setRemoteAudioReceiving(receiving); + receivingAudio = receiving; + } } - public AuxStreamImpl getAuxStream(long vid) { - for (AuxStreamImpl auxStream : _openedAuxStreamList) { - if (auxStream.getVid() == vid) - return auxStream; + @Override + public boolean isReceivingSharing() { + if (media == null) { + return false; + } + if (!media.hasSharing() && media.hasVideo()) { + return media.isRemoteVideoReceiving(); + } + else { + return media.hasSharing() && media.isRemoteSharingReceiving(); } - return null; } @Override - public AuxStream getAuxStream(View view) { - for (AuxStreamImpl auxStream : _openedAuxStreamList) { - if (auxStream.getRenderView() == view) - return auxStream; + public void setReceivingSharing(boolean receiving) { + if (media == null) { + return; + } + if (!media.hasSharing() && media.hasVideo() && model.isFloorGranted()) { + setReceivingVideo(receiving); + } + else if (media.hasSharing()) { + media.setRemoteSharingReceiving(receiving); } - return null; } @Override - public void openAuxStream(@NonNull View view) { - Ln.d("openAuxStream: " + view); - String error = null; - if (getOpenedAuxStreamCount() >= _availableAuxStreamCount || getOpenedAuxStreamCount() >= MediaEngine.MAX_NUMBER_STREAMS) { - error = "Reach maximum count"; - } + public Pair getVideoRenderViews() { + return videoViews; + } - if (getAuxStream(view) != null) { - error = "This view has been used"; - } + @Override + public void setVideoRenderViews(@Nullable Pair views) { + Queue.main.run(() -> { + if (media != null && media.hasVideo()) { + Ln.d("setVideoRenderViews, old: " + videoViews + ", new: " + views); + if (videoViews == null && views == null) { + Ln.d("Do nothing."); + return; + } + if (views != null && (views.first == null || views.second == null)) { + Ln.e("The local and remote video views must be set in same time"); + return; + } + if (videoViews != null && views != null) { + if (videoViews.first == views.first && videoViews.second == views.second) { + Ln.d("Same views"); + return; + } + } + videoViews = views; + media.update(new MediaSession.MediaTypeVideo(views)); + phone.update(this, isSendingAudio(), isSendingVideo(), media.getLocalSdp(), result -> { + WebexError error = result.getError(); + if (error != null) { + Ln.d("Update media failed " + error); + } + }); + } + }); + } - if (!isGroup()) { - error = "Only can be used for group call"; - } - - if (error == null) { - long vid = _phone.getCallService().subscribeRemoteAuxVideo(getKey(), view); - Ln.d("openAuxStream vid: " + vid); - if (vid >= 0) { - AuxStreamImpl auxStream = new AuxStreamImpl(getKey(), _phone, vid, view); - _openedAuxStreamList.add(auxStream); - if (view instanceof SurfaceView) { - ((SurfaceView) view).getHolder().addCallback(new SurfaceHolder.Callback() { - @Override - public void surfaceCreated(SurfaceHolder surfaceHolder) { - Ln.d("remote surfaceCreated vid: " + vid); - if (!_phone.getCallService().isRemoteWindowAttached(_key, vid, view)) - _phone.getCallService().setRemoteWindowForVid(_key, vid, view); - } + @Override + public View getSharingRenderView() { + return sharingView; + } - @Override - public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { - Ln.d("remote surfaceChanged vid: " + vid); + @Override + public void setSharingRenderView(View view) { + Queue.main.run(() -> { + if (media != null && media.hasSharing()) { + Ln.d("setSharingRenderView, old: " + sharingView + ", new: " + view); + if (sharingView == view) { + Ln.d("Same view"); + return; + } + sharingView = view; + media.update(new MediaSession.MediaTypeSharing(view)); + phone.update(this, isSendingAudio(), isSendingVideo(), media.getLocalSdp(), result -> { + WebexError error = result.getError(); + if (error != null) { + Ln.d("Update media failed " + error); + } + FloorModel floor = model.getFloor(); + if (floor != null && floor.getGranted() != null) { + if (sharingView == null) { + media.joinSharing(floor.getGranted(), false); } - - @Override - public void surfaceDestroyed(SurfaceHolder surfaceHolder) { - Ln.d("remote surfaceDestroyed vid: " + vid); - _phone.getHandler().post(() -> _phone.getCallService().removeRemoteWindowForVid(_key, vid, view)); + else { + media.leaveSharing(false); } - }); - } - } else { - error = "Open aux stream error"; + } + }); } - } + }); + } - if (_multiStreamObserver != null) { - _multiStreamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamOpenedEvent(this, view, error)); - } + @Override + public void acknowledge(@NonNull CompletionHandler callback) { + phone.acknowledge(this, callback); } @Override - public void closeAuxStream(@NonNull View view) { - Ln.d("closeAuxStream: " + view); - closeAuxStream(getAuxStream(view), view); + public void answer(@NonNull MediaOption option, @NonNull CompletionHandler callback) { + phone.answer(this, option, callback); } - public void closeAuxStream(AuxStream auxStream, View view) { - Ln.d("closeAuxStream auxStream: " + auxStream); - String error = null; - if (auxStream != null && _phone.getCallService().unsubscribeRemoteAuxVideo(getKey(), ((AuxStreamImpl) auxStream).getVid())) { - _openedAuxStreamList.remove(auxStream); - } else { - error = "Close aux stream error"; - } + @Override + public void reject(@NonNull CompletionHandler callback) { + phone.reject(this, callback); + } - if (_multiStreamObserver != null) { - _multiStreamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamClosedEvent(this, view, error)); - } + @Override + public void hangup(@NonNull CompletionHandler callback) { + phone.hangup(this, callback); } - public void closeAuxStream() { - if (getOpenedAuxStreamCount() > _availableAuxStreamCount) { - AuxStream auxStream = _openedAuxStreamList.get(_openedAuxStreamList.size() - 1); - closeAuxStream(auxStream, auxStream.getRenderView()); - } + @Override + public void sendDTMF(String tones, @NonNull CompletionHandler callback) { + phone.dtmf(this, tones, dtmfCorrelation.getAndIncrement(), callback); } - public boolean isSendingVideo() { - return _option != null && _option.hasVideo() && !_phone.getCallService().isVideoMuted(getKey()); + @Override + public void sendFeedback(int rating, @Nullable String comment) { + Map info = new HashMap<>(); + info.put("user.rating", String.valueOf(rating)); + info.put("user.comments", comment); + info.put("locusId", getModel().getUniqueCallID()); + info.put("participantId", getModel().getSelfId()); + phone.feedback(info); } - public void setSendingVideo(boolean sending) { - if (_option == null || !_option.hasVideo()) { - Ln.d("Can not setSendingVideo in a Audio call, return"); - return; - } - if (sending) { - _phone.getCallService().unMuteVideo(getKey(), MediaRequestSource.USER); - } else { - _phone.getCallService().muteVideo(getKey(), MediaRequestSource.USER); - } + @Override + public void startSharing(@NonNull CompletionHandler callback) { + phone.startSharing(this, callback); } - public boolean isSendingAudio() { - return !_phone.getCallService().isAudioMuted(getKey()); + @Override + public void stopSharing(@NonNull CompletionHandler callback) { + phone.stopSharing(this, callback); } - public void setSendingAudio(boolean sending) { - if (sending) { - _phone.getCallService().unmuteAudio(getKey()); - } else { - _phone.getCallService().muteAudio(getKey()); + @Override + public boolean isSendingSharing() { + return media != null && media.hasSharing() && media.isLocalSharingSending() && isSharingFromThisDevice(); + } + + public void setSendingSharing(boolean sending) { + if (media != null) { + media.setLocalSharingSending(sending); } } - public boolean isReceivingVideo() { - return _option != null && _option.hasVideo() && !_phone.getCallService().isRemoteVideoMuted(getKey()); + @Override + public void openAuxStream(@NonNull View view) { + Queue.main.run(() -> { + if (media != null && streams.size() >= media.getCapability().getMaxNumberStreams()) { + if (streamObserver != null) { + streamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamOpenedEvent(this, view, "Exceeded the auxiliary streams limit")); + } + return; + } + if (!isGroup()) { + if (streamObserver != null) { + streamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamOpenedEvent(this, view, "Only available for group call")); + } + return; + } + AuxStreamImpl stream = (AuxStreamImpl) getAuxStream(view); + if (stream != null) { + if (streamObserver != null) { + streamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamOpenedEvent(this, view, "Open aux stream with same view")); + } + return; + } + if (streams.size() >= getAvailableAuxStreamCount()) { + if (streamObserver != null) { + streamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamOpenedEvent(this, view, "Cannot exceed available stream count")); + } + return; + } + int vid = media.subscribeAuxVideo(view); + if (vid == -1) { + if (streamObserver != null) { + streamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamOpenedEvent(this, view, "Open stream fail")); + } + return; + } + stream = new AuxStreamImpl(this, vid, view); + streams.add(stream); + if (streamObserver != null) { + streamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamOpenedEvent(this, view, null)); + } + }); } - public void setReceivingVideo(boolean receiving) { - if (_option == null || !_option.hasVideo()) { - Ln.d("Can not setReceivingVideo in a Audio call, return"); + @Override + public void closeAuxStream(@NonNull View view) { + if (media == null) { return; } - _phone.getCallService().muteRemoteVideo(getKey(), !receiving); - CallObserver observer = getObserver(); - if (observer != null) { - observer.onMediaChanged(new CallObserver.ReceivingVideo(this, receiving)); - } + Queue.main.run(() -> { + AuxStreamImpl stream = (AuxStreamImpl) getAuxStream(view); + if (stream == null) { + if (streamObserver != null) { + streamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamClosedEvent(this, view, "auxiliary stream not found")); + } + return; + } + media.unsubscribeAuxVideo(stream.getVid()); + streams.remove(stream); + if (streamObserver != null) { + streamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamClosedEvent(this, view, null)); + } + }); } - public boolean isReceivingAudio() { - return !_phone.getCallService().isRemoteAudioMuted(getKey()); + @Override + public AuxStream getAuxStream(@NonNull View view) { + for (AuxStream stream : streams) { + if (stream.getRenderView() == view) { + return stream; + } + } + return null; } - public void setReceivingAudio(boolean receiving) { - _phone.getCallService().muteRemoteAudio(getKey(), !receiving); - CallObserver observer = getObserver(); - if (observer != null) { - observer.onMediaChanged(new CallObserver.ReceivingAudio(this, receiving)); + public AuxStream getAuxStream(long vid) { + if (vid >= 0) { + for (AuxStream stream : streams) { + if (stream instanceof AuxStreamImpl && ((AuxStreamImpl) stream).getVid() == vid) { + return stream; + } + } } + return null; } @Override - public boolean isReceivingSharing() { - if (!_option.hasSharing() && _option.hasVideo()) { - return isReceivingVideo(); - } else if (_option.hasSharing()) { - return !_phone.getCallService().isRemoteScreenShareMuted(getKey()); - } else { - return false; - } + public int getAvailableAuxStreamCount() { + return availableStreamCount; } @Override - public void setReceivingSharing(boolean receiving) { - if (_option == null || (!_option.hasSharing() && !_option.hasVideo())) { - Ln.d("Can not setReceivingSharing in a Audio call, return"); - return; - } + public int getOpenedAuxStreamCount() { + return streams.size(); + } - if (!_option.hasSharing() && _option.hasVideo()) { - if (!isRemoteSendingSharing()) { - // not have sharing and have video and the remote doesn't start sharing. - // do nothing when user set the receivingSharing - return; - } - setReceivingVideo(receiving); - } else { - _phone.getCallService().muteRemoteScreenShare(getKey(), !receiving); - } + @Override + public CallMembership getActiveSpeaker() { + return activeSpeaker; + } - CallObserver observer = getObserver(); - if (observer != null) { - observer.onMediaChanged(new CallObserver.ReceivingSharing(this, receiving)); - } + public void setActiveSpeaker(CallMembershipImpl membership) { + activeSpeaker = membership; } - public Pair getVideoRenderViews() { - return _videoRenderViews; + @Override + public void setMultiStreamObserver(MultiStreamObserver observer) { + streamObserver = observer; + } + + @Override + public MultiStreamObserver getMultiStreamObserver() { + return streamObserver; + } + + @Override + public void letIn(@NonNull CallMembership membership) { + phone.admit(this, Lists.asList(membership), result -> {}); } @Override - public void setVideoRenderViews(@Nullable Pair videoRenderViews) { - if (_status == CallStatus.DISCONNECTED) { + public void letIn(@NonNull List memberships) { + phone.admit(this, memberships, result -> {}); + } + + void startMedia() { + if (media == null) { return; } - Ln.d("setVideoRenderViews, old: " + _videoRenderViews + ", new: " + videoRenderViews); - if (videoRenderViews != null && (videoRenderViews.first == null || videoRenderViews.second == null)) { - Ln.e("The local and remote video views must be set in same time"); + String remoteSdp = model.getRemoteSdp(device.getDeviceUrl()); + if (remoteSdp == null) { + Ln.e("Remote SDP is null"); return; } - if (_videoRenderViews != null && (_videoRenderViews.first == null || _videoRenderViews.second == null)) { - Ln.e("The local and remote video views must be set in same time"); - return; + media.setRemoteSdp(remoteSdp); + for (AuxStreamImpl stream : streams) { + if (stream.getVid() == -1 && stream.getRenderView() != null) { + int vid = media.subscribeAuxVideo(stream.getRenderView()); + if (vid != -1) { + stream.setVid(vid); + media.addAuxVideoView(stream.getRenderView(), vid); + } + } } - CallControlService service = _phone.getCallService(); - LocusKey key = getKey(); - if (_videoRenderViews == null && videoRenderViews == null) { - Ln.d("Do nothing."); + media.startCloud(this); + if (media.hasSharing() && model.getFloor() != null && model.getFloor().getGranted() != null) { + media.joinSharing(model.getFloor().getGranted(), isSharingFromThisDevice()); } - else if (_videoRenderViews == null) { - _videoRenderViews = videoRenderViews; - service.setPreviewWindow(key, _videoRenderViews.first); - service.setRemoteWindow(key, _videoRenderViews.second); - updateMedia(); + } + + void stopMedia() { + if (media == null) { + return; } - else if (videoRenderViews == null) { - _videoRenderViews = null; - service.removePreviewWindows(key); - service.removeRemoteVideoWindows(key); - updateMedia(); + //stopMedia must run in the main thread. Because WME will remove the videoRender view. + if (media.hasSharing() && model.getFloor() != null && model.getFloor().getGranted() != null) { + media.leaveSharing(isSharingFromThisDevice()); } - else { - if (_videoRenderViews.first != videoRenderViews.first) { - service.removePreviewWindow(key, _videoRenderViews.first); - service.setPreviewWindow(key, videoRenderViews.first); - } - if (_videoRenderViews.second != videoRenderViews.second) { - service.removeRemoteWindow(key, _videoRenderViews.second); - service.setRemoteWindow(key, videoRenderViews.second); + for (AuxStreamImpl stream : streams) { + if (stream.getVid() != -1) { + media.unsubscribeAuxVideo(stream.getVid()); } - _videoRenderViews = videoRenderViews; } + media.stopCloud(); } - public View getSharingRenderView() { - return _sharingRenderView; + void updateMedia(boolean sendingAudio, boolean sendingVideo) { + phone.update(this, sendingAudio, sendingVideo, null, result -> Ln.d("Update media: " + result)); } - @Override - public void setSharingRenderView(View view) { - if (_status == CallStatus.DISCONNECTED) { - return; - } - if (_sharingRenderView == null && view == null) { + void startKeepAlive() { + int sec = getModel().getKeepAliceSecs(device.getDeviceUrl()); + if (sec <= 0) { return; } - CallControlService service = _phone.getCallService(); - LocusKey key = getKey(); - View oldView = _sharingRenderView; - _sharingRenderView = view; - if (oldView != null && view == null) { - service.removeShareWindow(key); - updateMedia(); - return; - } - if (oldView == null && view != null) { - service.setShareWindow(key, view); - updateMedia(); - return; - } - if (oldView != view) { - service.removeShareWindow(key); - service.setShareWindow(key, view); - } + stopKeepAlive(); + keepAliveTask = Scheduler.schedule(() -> phone.keepAlive(this), sec * 1000, true); } - public void acknowledge(@NonNull CompletionHandler callback) { - _phone.getCallService().acknowledge(getKey()); - // TODO post event when locus alert responsed in common lib - callback.onComplete(null); + void stopKeepAlive() { + if (keepAliveTask != null) { + keepAliveTask.cancel(); + keepAliveTask = null; + } } - public void answer(@NonNull MediaOption option, @NonNull CompletionHandler callback) { - setMediaOption(option); - _answerCallback = callback; - _phone.answer(this); + void updateAuxStreamCount() { + if (media == null) { + return; + } + Queue.main.run(() -> { + int count = 0; + for (CallMembershipImpl membership : memberships) { + if (membership.getModel().getState() == LocusParticipantModel.State.JOINED && !membership.isSelf()) { + count = count + 1; + } + } + int newAvailableAuxStreamCount = Math.min(count - 1, media.getAuxStreamCount() - 1); + if (newAvailableAuxStreamCount < 0) { + newAvailableAuxStreamCount = 0; + } + else if (getAvailableAuxStreamCount() >= media.getCapability().getMaxNumberStreams() + && newAvailableAuxStreamCount > media.getCapability().getMaxNumberStreams()) { + availableStreamCount = media.getCapability().getMaxNumberStreams(); + return; + } + if (streamObserver != null) { + int diff = newAvailableAuxStreamCount - availableStreamCount; + if (diff > media.getCapability().getMaxNumberStreams()) { + diff = media.getCapability().getMaxNumberStreams(); + } + if (diff > 0) { + for (int i = 0; i < diff; i++) { + View view = streamObserver.onAuxStreamAvailable(); + if (view != null) { + openAuxStream(view); + } + } + } + else if (diff < 0) { + for (int i = 0; i < -diff; i++) { + View view = streamObserver.onAuxStreamUnavailable(); + AuxStream stream = getAuxStream(view); + if (stream == null) { + view = null; + } + if (view == null) { + if (newAvailableAuxStreamCount < streams.size()) { + AuxStream last = Lists.getLast(streams); + if (last != null) { + view = last.getRenderView(); + } + } + } + if (view != null) { + closeAuxStream(view); + } + } + } + } + availableStreamCount = newAvailableAuxStreamCount; + }); } - public void reject(@NonNull CompletionHandler callback) { - _rejectCallback = callback; - _phone.reject(this); + void joinSharing(LocusParticipantModel participant, String shareId) { + if (media == null) { + return; + } + if (isSharingFromThisDevice()) { + if (media.hasSharing()) { + media.joinSharing(shareId, true); + } + if (media.isLocalSharingSending()) { + if (observer != null) { + observer.onMediaChanged(new CallObserver.SendingSharingEvent(this, true)); + } + } + } + else { + if (media.hasSharing()) { + media.joinSharing(shareId, false); + } + if (observer != null) { + observer.onMediaChanged(new CallObserver.RemoteSendingSharingEvent(this, true)); + } + } + if (!isSharingFromThisDevice() || media.isLocalSharingSending()) { + for (CallMembershipImpl membership : memberships) { + if (Checker.isEqual(membership.getId(), participant.getId())) { + if (observer != null) { + observer.onCallMembershipChanged(new CallObserver.MembershipSendingSharingEvent(this, membership)); + } + } + } + } } - public void hangup(@NonNull CompletionHandler callback) { - _hangupCallback = callback; - _phone.hangup(this); + void leaveSharing(LocusParticipantModel participant, String granted, FloorModel oldFloor) { + if (media == null) { + return; + } + if (isSharingByModel(oldFloor)) { + if (media.hasSharing()) { + media.leaveSharing(true); + } + if (observer != null) { + observer.onMediaChanged(new CallObserver.SendingSharingEvent(this, false)); + } + } + else { + if (media.hasSharing()) { + media.leaveSharing(false); + } + if (observer != null) { + observer.onMediaChanged(new CallObserver.RemoteSendingSharingEvent(this, false)); + } + } + for (CallMembershipImpl membership : memberships) { + if (Checker.isEqual(membership.getId(), participant.getId())) { + if (observer != null) { + observer.onCallMembershipChanged(new CallObserver.MembershipSendingSharingEvent(this, membership)); + } + } + } } - public boolean isSendingDTMFEnabled() { - LocusSelfRepresentation self = getSelf(); - return self != null && self.isEnableDTMF(); + void end(CallObserver.CallDisconnectedEvent reason) { + Ln.d("Call end by reason: " + reason); + if (isSharingFromThisDevice()) { + stopSharing(result -> Ln.d("Unshare screen by call end!")); + if (media != null) { + media.leaveSharing(true); + } + } + if (reason instanceof CallObserver.RemoteDecline || reason instanceof CallObserver.RemoteLeft) { + String url = model.getSelf() == null ? null : model.getSelf().getUrl(); + if (url != null) { + phone.getService().leave(url, device, result -> Ln.d("Leave call: " + result)); + } + } + phone.removeCall(this); + setStatus(CallStatus.DISCONNECTED); + Queue.main.run(() -> { + stopMedia(); + if (observer != null) { + observer.onDisconnected(reason); + } + }); } - public void sendDTMF(@NonNull String dtmf, @NonNull CompletionHandler callback) { - SendDtmfOperation operation = _phone.getOperations().sendDtmf(dtmf); - _dtmfOperations.put(operation, callback); - } + void update(LocusModel remote) { + Ln.d("Update locus: " + model.getCallUrl()); + LocusModel local = this.model; + if (local != null) { + List connections = remote.getMediaConnections(); + if (connections == null) { + connections = local.getMediaConnections(); + } + if (connections != null) { + local.setMediaConnections(connections); + remote.setMediaConnections(connections); + } + } - public void sendFeedback(int rating, @Nullable String comment) { - Map info = new HashMap<>(); - info.put("user.rating", String.valueOf(rating)); - info.put("user.comments", comment); - info.put("locusId", this._key.getLocusId()); - Locus locus = _phone.getCallService().getLocus(_key); - if (locus != null && locus.getSelf() != null) { - info.put("participantId", locus.getSelf().getId().toString()); + boolean isDelta = remote.getBaseSequence() != null; + if (local != null) { + LocusSequenceModel.OverwriteWithResult overwriteWithResult; + if (isDelta) { + Ln.d("processLocusUpdate() processing with delta sequence information"); + overwriteWithResult = local.getSequence().overwriteWith(remote.getBaseSequence(), remote.getSequence()); + } else { + Ln.d("processLocusUpdate() processing with full DTO"); + overwriteWithResult = local.getSequence().overwriteWith(remote.getSequence()); + } + if (overwriteWithResult.equals(LocusSequenceModel.OverwriteWithResult.FALSE) && local.getFullState().isStartingSoon() != remote.getFullState().isStartingSoon()) { + Ln.d("Overwrite was FALSE, but startingSoon flags do not match so forcing overwrite to TRUE"); + overwriteWithResult = LocusSequenceModel.OverwriteWithResult.TRUE; + } + if (overwriteWithResult.equals(LocusSequenceModel.OverwriteWithResult.TRUE)) { + if (isDelta) { + remote = local.applyDelta(remote); + } + Ln.d("Updating locus DTO and notifying listeners of data change for: %s", remote.getCallUrl()); + } else if (overwriteWithResult.equals(LocusSequenceModel.OverwriteWithResult.FALSE)) { + Ln.d("Didn't overwrite locus DTO as new one was older version than one currently in memory."); + } else if (overwriteWithResult.equals(LocusSequenceModel.OverwriteWithResult.DESYNC)) { + Ln.d("Didn't overwrite locus DTO as new one was out of sync with one currently in memory."); + phone.fetch(this, false); + return; + } + } + else if (isDelta) { + // locus doesn't exist in the cache, but this DTO is a delta, so fetch a full DTO and reprocess + phone.fetch(this, true); + return; } - _phone.sendFeedback(info); + doLocusModel(remote); + LocusModel newModule = remote; + Queue.main.run(() -> { + if (local != null) { + if (newModule.isRemoteAudioMuted() != local.isRemoteAudioMuted()) { + if (observer != null) { + observer.onMediaChanged(new CallObserver.RemoteSendingAudioEvent(this, !newModule.isRemoteAudioMuted())); + } + } + doFloorUpdate(local.getFloor(), newModule.getFloor()); + } + }); } - @Override - public void startSharing(@NonNull CompletionHandler callback) { - if (_status == CallStatus.CONNECTED) { - LocusData locusData = _phone.getCallService().getLocusData(_key); - if (locusData != null) { - MediaShare contentMediaShare = locusData.getLocus().getShareContentMedia(); - if (contentMediaShare == null || !contentMediaShare.isMediaShareGranted() || !_phone.isSharingFromThisDevice(locusData)) { - _shareRequestCallback = callback; - _phone.startSharing(_key); - } else if (callback != null) { - Ln.w("Can not startSharing, because call is sharing content"); - callback.onComplete(ResultImpl.error("Call is sharing content")); + void doFloorUpdate(FloorModel old, FloorModel current) { + if (current != null && current.isValid()) { + if (old == null || !old.isValid()) { + if (current.getDisposition() == FloorModel.Disposition.GRANTED) { + joinSharing(current.getBeneficiary(), current.getGranted()); + } + else if (current.getDisposition() == FloorModel.Disposition.RELEASED) { + leaveSharing(current.getBeneficiary(), current.getGranted(), null); + } + else { + Ln.d("Failure: floor dispostion is unknown."); + } + } + else { + if (old.getDisposition() != current.getDisposition()) { + if (current.getDisposition() == FloorModel.Disposition.GRANTED) { + joinSharing(current.getBeneficiary(), current.getGranted()); + } + else if (current.getDisposition() == FloorModel.Disposition.RELEASED) { + leaveSharing(old.getBeneficiary(), old.getGranted(), old); + } + else { + Ln.d("Failure: floor dispostion is unknown."); + } + } + else if (media != null && Checker.isEqual(old.getGranted(), current.getGranted()) && current.getDisposition() == FloorModel.Disposition.GRANTED) { + if (isSharingByModel(old) && !isSharingByModel(current)) { + if (media.hasSharing()) { + media.leaveSharing(true); + media.joinSharing(current.getGranted(), false); + } + if (observer != null) { + observer.onMediaChanged(new CallObserver.SendingSharingEvent(this, false)); + observer.onMediaChanged(new CallObserver.RemoteSendingSharingEvent(this, true)); + } + } + else if (!isSharingByModel(old) && isSharingByModel(current)) { + if (media.hasSharing()) { + media.leaveSharing(false); + media.joinSharing(current.getGranted(), true); + } + if (observer != null) { + observer.onMediaChanged(new CallObserver.RemoteSendingSharingEvent(this, false)); + if (media.isLocalSharingSending()) { + observer.onMediaChanged(new CallObserver.SendingSharingEvent(this, true)); + } + } + } + String id = current.getBeneficiary().getId(); + if (id != null) { + for (CallMembershipImpl membership : memberships) { + if (Checker.isEqual(membership.getId(), id)) { + if (observer != null) { + observer.onCallMembershipChanged(new CallObserver.MembershipSendingSharingEvent(this, membership)); + } + } + } + } } - } else if (callback != null) { - Ln.w("startSharing callControlService.getLocusData is null"); - callback.onComplete(ResultImpl.error("Call is not exist")); } - } else if (callback != null) { - Ln.w("Can not startSharing, because call status is: " + _status); - callback.onComplete(ResultImpl.error("Call is not connected")); } } - @Override - public void stopSharing(@NonNull CompletionHandler callback) { - if (_status == CallStatus.CONNECTED) { - LocusData locusData = _phone.getCallService().getLocusData(_key); - if (locusData != null) { - MediaShare contentMediaShare = locusData.getLocus().getShareContentMedia(); - if (contentMediaShare != null && contentMediaShare.isMediaShareGranted() && _phone.isSharingFromThisDevice(locusData)) { - _shareReleaseCallback = callback; - _phone.stopSharing(_key); - } else if (callback != null) { - Ln.w("Can not stopSharing, because call is not sharing content"); - callback.onComplete(ResultImpl.error("Call is not sharing content")); + void doLocusModel(LocusModel model) { + Ln.d("doLocusModel: " + model.getCallUrl()); + this.model = model; + List participants = Objects.defaultIfNull(model.getParticipants(), Collections.emptyList()); + List oldMemberships = this.memberships; + List newMemberships = new ArrayList<>(); + List events = new ArrayList<>(); + for (LocusParticipantModel participant : participants) { + if (!participant.isValidCiUser()) { + continue; + } + CallMembershipImpl membership = null; + for (CallMembershipImpl m : oldMemberships) { + if (m.getId().equals(participant.getId())) { + membership = m; + break; + } + } + if (membership == null) { + membership = new CallMembershipImpl(participant, this); + events.addAll(generateMembershipEvents(membership)); + events.add(new CallObserver.MembershipSendingAudioEvent(this, membership)); + events.add(new CallObserver.MembershipSendingVideoEvent(this, membership)); + events.add(new CallObserver.MembershipSendingSharingEvent(this, membership)); + } + else { + CallMembership.State oldState = membership.getState(); + boolean tempSendingAudio = membership.isSendingAudio(); + boolean tempSendingVideo = membership.isSendingVideo(); + boolean tempSendingSharing = membership.isSendingSharing(); + membership.setModel(participant); + if (membership.getState() != oldState) { + events.addAll(generateMembershipEvents(membership)); + } + if (membership.isSendingAudio() != tempSendingAudio) { + events.add(new CallObserver.MembershipSendingAudioEvent(this, membership)); + } + if (membership.isSendingVideo() != tempSendingVideo) { + events.add(new CallObserver.MembershipSendingVideoEvent(this, membership)); + } + if (membership.isSendingSharing() != tempSendingSharing) { + events.add(new CallObserver.MembershipSendingSharingEvent(this, membership)); + } + } + newMemberships.add(membership); + } + this.memberships = newMemberships; + for (AuxStreamImpl stream : streams) { + CallMembership old = stream.getPerson(); + for (CallMembership membership : memberships) { + if (old.equals(membership)) { + stream.setPerson(membership); + break; } - } else if (callback != null) { - Ln.w("stopSharing callControlService.getLocusData is null"); - callback.onComplete(ResultImpl.error("Call is not exist")); } - } else if (callback != null) { - Ln.w("Can not stopSharing, because call status is: " + _status); - callback.onComplete(ResultImpl.error("Call is not connected")); } - } - public Phone.FacingMode getFacingMode() { - com.cisco.spark.android.callcontrol.model.Call call = _phone.getCallService().getCall(getKey()); - if (call == null) { - return _phone.getDefaultFacingMode(); + for (CallObserver.CallMembershipChangedEvent event : events) { + Queue.main.run(() -> { + if (observer != null) { + observer.onCallMembershipChanged(event); + } + }); } - MediaSession session = call.getMediaSession(); - if (session == null) { - return _phone.getDefaultFacingMode(); + Ln.d("CallMembership: " + this.memberships); + updateAuxStreamCount(); + updateStatus(model); + if (getStatus() != CallStatus.WAITING) { + stopKeepAlive(); + } + if ((getStatus() == CallStatus.CONNECTED || getStatus() == CallStatus.RINGING ) && media != null && !media.isRunning()) { + Ln.d("Update SDP before start media"); + phone.update(this, isSendingAudio(), isSendingVideo(), media.getLocalSdp(), result -> { + if (result.getError() != null) { + Ln.d("Update SDP failed: " + result.getError()); + return; + } + if (!media.isRunning()) { + startMedia(); + setSendingAudio(sendingAudio); + setSendingVideo(sendingVideo); + setReceivingAudio(receivingAudio); + setReceivingVideo(receivingVideo); + if (getStatus() == CallStatus.CONNECTED && observer != null) { + observer.onConnected(this); + } + } + }); } - return PhoneImpl.toFacingMode(session.getSelectedCamera()); } - public void setFacingMode(Phone.FacingMode facingMode) { - com.cisco.spark.android.callcontrol.model.Call call = _phone.getCallService().getCall(getKey()); - if (call != null) { - MediaSession session = call.getMediaSession(); - if (session != null && !session.getSelectedCamera().equals(PhoneImpl.fromFacingMode(facingMode))) { - session.switchCamera(); - CallObserver observer = getObserver(); + private List generateMembershipEvents(CallMembershipImpl membership) { + List events = new ArrayList<>(); + CallMembership.State state = membership.getState(); + if (state == CallMembership.State.JOINED) { + events.add(new CallObserver.MembershipJoinedEvent(this, membership)); + } + else if (state == CallMembership.State.LEFT) { + events.add(new CallObserver.MembershipLeftEvent(this, membership)); + for (AuxStreamImpl stream : streams) { + if (stream.getPerson() != null && ((CallMembershipImpl)stream.getPerson()).getId().equals(membership.getId())) { + stream.setPerson(null); + if (streamObserver != null) { + streamObserver.onAuxStreamChanged(new MultiStreamObserver.AuxStreamPersonChangedEvent(this, stream, membership, null)); + } + break; + } + } + if (getActiveSpeaker() != null && ((CallMembershipImpl) getActiveSpeaker()).getId().equals(membership.getId())) { + activeSpeaker = null; if (observer != null) { - observer.onMediaChanged(new CallObserver.CameraSwitched(this)); + observer.onMediaChanged(new CallObserver.ActiveSpeakerChangedEvent(this, membership, null)); } } } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlMediaDecodeSizeChangedEvent event) { - Ln.d("CallControlMediaDecodeSizeChangedEvent is received"); - if (event.getVideoId() != 0) - return; - CallObserver.MediaChangedEvent mediaEvent = null; - if (event.getVideoId() == MediaEngine.SHARE_MID) { - _sharingViewSize = event.getSize(); - mediaEvent = new CallObserver.RemoteSharingViewSizeChanged(this); - } else { - _remoteVideoViewSize = event.getSize(); - mediaEvent = new CallObserver.RemoteVideoViewSizeChanged(this); + else if (state == CallMembership.State.DECLINED) { + events.add(new CallObserver.MembershipDeclinedEvent(this, membership)); } - CallObserver observer = getObserver(); - if (observer != null) { - observer.onMediaChanged(mediaEvent); + else if (state == CallMembership.State.WAITING) { + events.add(new CallObserver.MembershipWaitingEvent(this, membership, model.getWaitReason())); } + return events; } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(MediaSession.MediaRenderSizeChangedEvent event) { - Ln.d("MediaRenderSizeChangedEvent is received"); - _localVideoViewSize = event.size; - CallObserver observer = getObserver(); - if (observer != null) { - observer.onMediaChanged(new CallObserver.LocalVideoViewSizeChanged(this)); + private void updateStatus(LocusModel model) { + LocusSelfModel self = model.getSelf(); + if (self == null) { + return; } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(OperationCompletedEvent event) { - Ln.d("OperationCompletedEvent is received"); - Operation operation = event.getOperation(); - if (operation != null) { - CompletionHandler callback = _dtmfOperations.get(operation); - if (callback != null) { - if (operation.isSucceeded()) { - callback.onComplete(ResultImpl.success(null)); - } else { - callback.onComplete(ResultImpl.error(operation.getErrorMessage())); + CallStatus status = getStatus(); + if (status == CallStatus.INITIATED || status == CallStatus.RINGING || status == CallStatus.WAITING) { + if (getDirection() == Direction.INCOMING) { + if (isRemoteJoined()) { + if (self.isJoined(device.getDeviceUrl())) { + setStatus(CallStatus.CONNECTED); + Queue.main.run(() -> { + if (observer != null) { + observer.onConnected(this); + } + }); + } + else if (self.isDeclined(device.getDeviceUrl())) { + end(new CallObserver.LocalDecline(this)); + } + else if (self.isJoined()) { + end(new CallObserver.OtherConnected(this)); + } + else if (self.isDeclined()) { + end(new CallObserver.OtherDeclined(this)); + } + } + else if (isRemoteDeclined() || isRemoteLeft()) { + end(new CallObserver.RemoteCancel(this)); + } + } + else if (getDirection() == Direction.OUTGOING) { + if (self.isLefted(device.getDeviceUrl())) { + end(new CallObserver.LocalCancel(this)); + } + else if (self.isJoined(device.getDeviceUrl())) { + if (isGroup()) { + setStatus(CallStatus.RINGING); + Queue.main.run(() -> { + if (observer != null) { + observer.onRinging(this); + } + setStatus(CallStatus.CONNECTED); + Queue.main.run(() -> { + if (observer != null) { + observer.onConnected(this); + } + }); + }); + } + else { + if (isRemoteNotified()) { + setStatus(CallStatus.RINGING); + Queue.main.run(() -> { + if (observer != null) { + observer.onRinging(this); + } + }); + } + else if (isRemoteJoined()) { + setStatus(CallStatus.CONNECTED); + Queue.main.run(() -> { + if (observer != null) { + observer.onConnected(this); + } + }); + } + else if (isRemoteDeclined()) { + end(new CallObserver.RemoteDecline(this)); + } + } } + else if (self.isInLobby()) { + setStatus(CallStatus.WAITING); + Queue.main.run(() -> { + if (observer != null) { + observer.onWaiting(this, model.getWaitReason()); + } + }); + } + } + } + else if (status == CallStatus.CONNECTED) { + if (self.isLefted(device.getDeviceUrl())) { + end(new CallObserver.LocalLeft(this)); + } + else if (!isGroup() && isRemoteLeft()) { + end(new CallObserver.RemoteLeft(this)); } } } - @Override - public String toString() { - return Objects.toStringByAnnotation(this); + boolean isSharingFromThisDevice() { + return isSharingByModel(model.getFloor()); } - LocusSelfRepresentation getSelf() { - LocusData locusData = _phone.getCallService().getLocusData(getKey()); - if (locusData == null) { - return null; - } - Locus locus = locusData.getLocus(); - if (locus == null) { - return null; + boolean isSharingByModel(FloorModel model) { + if (model != null && media != null && media.hasSharing() && model.getDisposition() == FloorModel.Disposition.GRANTED) { + LocusParticipantModel p = model.getBeneficiary(); + return p != null && Checker.isEqual(device.getDeviceUrl(), p.getDeviceUrl()); } - return locus.getSelf(); + return false; } - private List getParticipants() { - List participants = new ArrayList<>(); - LocusData locusData = _phone.getCallService().getLocusData(getKey()); - if (locusData == null) { - return participants; - } - Locus locus = locusData.getLocus(); - if (locus == null) { - return participants; + + boolean isRemoteLeft() { + if (isGroup()) { + return false; } - for (LocusParticipant p : locus.getParticipants()) { - if (p.getType() == LocusParticipant.Type.USER || p.getType() == LocusParticipant.Type.RESOURCE_ROOM) { - participants.add(p); + for (CallMembershipImpl membership : memberships) { + if (!membership.isSelf() && membership.getState() != CallMembership.State.LEFT) { + return false; } } - return participants; + return true; } - protected List getRemoteParticipants() { - List participants = getParticipants(); - LocusSelfRepresentation self = getSelf(); - if (self == null) { - return participants; + boolean isRemoteDeclined() { + if (isGroup()) { + return false; } - List ret = new ArrayList<>(participants.size() - 1); - for (LocusParticipant p : participants) { - if (!self.getId().equals(p.getId())) { - ret.add(p); + for (CallMembershipImpl membership : memberships) { + if (!membership.isSelf() && membership.getState() != CallMembership.State.DECLINED) { + return false; } } - return ret; + return true; } - boolean isGroup() { - return _isGroup; - } - - LocusParticipant getSharingSender() { - LocusData locus = _phone.getCallService().getLocusData(getKey()); - if (locus != null && locus.isFloorGranted()) { - return _phone.getCallService().getLocusData(getKey()).getParticipantSharing(); + boolean isRemoteJoined() { + if (isGroup()) { + return true; } - return null; - } - - void updateMedia() { - com.cisco.spark.android.callcontrol.model.Call locus = _phone.getCallService().getCall(getKey()); - if (locus != null) { - _phone.getCallService().updateMediaSession(locus, PhoneImpl.mediaOptionToMediaDirection(_option)); + for (CallMembershipImpl membership : memberships) { + if (!membership.isSelf() && membership.getState() != CallMembership.State.JOINED) { + return false; + } } + return true; } - @Override - // TODO Callback - public void letIn(@NonNull CallMembership membership) { - String personId = WebexId.translate(membership.getPersonId()); - List participants = getRemoteParticipants(); - for (LocusParticipant participant : participants) { - if (participant.isInLobby() && personId.equals(participant.getPerson().getId())) { - _phone.getCallService().admitParticipant(participant); - return; + boolean isRemoteNotified() { + if (isGroup()) { + return true; + } + for (CallMembershipImpl membership : memberships) { + if (!membership.isSelf() && (membership.getState() == CallMembership.State.IDLE || membership.getState() == CallMembership.State.NOTIFIED)) { + return true; } } + return false; } - @Override - // TODO Callback - public void letIn(@NonNull List memberships) { - JsonArray jsonArray = new JsonArray(); - List participants = getRemoteParticipants(); - for (LocusParticipant participant : participants) { - if (participant.isInLobby()) { - for (CallMembership membership : memberships) { - String personId = WebexId.translate(membership.getPersonId()); - if (personId.equals(participant.getPerson().getId())) { - jsonArray.add(participant.getId().toString()); - } - } + boolean isStatusIllegal() { + if (!isGroup()) { + if (getStatus() == CallStatus.INITIATED || getStatus() == CallStatus.RINGING) { + return getDirection() == Direction.OUTGOING && isRemoteLeft(); } } - if (jsonArray.size() != 0) { - _phone.getCallService().admitAllParticipant(jsonArray); - } + return false; } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallMembershipImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallMembershipImpl.java index baf38791..14c2cdec 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallMembershipImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallMembershipImpl.java @@ -22,127 +22,149 @@ package com.ciscowebex.androidsdk.phone.internal; -import com.cisco.spark.android.locus.model.LocusParticipant; -import com.cisco.spark.android.locus.model.LocusParticipantInfo; -import com.cisco.spark.android.locus.model.MediaDirection; -import com.ciscowebex.androidsdk.phone.Call; +import com.ciscowebex.androidsdk.internal.model.*; import com.ciscowebex.androidsdk.phone.CallMembership; -import com.ciscowebex.androidsdk.utils.Utils; import com.ciscowebex.androidsdk.utils.WebexId; import com.github.benoitdion.ln.Ln; +import me.helloworld.utils.Checker; import me.helloworld.utils.Objects; -import me.helloworld.utils.annotation.StringPart; +import org.jetbrains.annotations.NotNull; -/** - * Created on 12/06/2017. - */ +import java.util.List; public class CallMembershipImpl implements CallMembership { - private static CallMembership.State fromLocusState(LocusParticipant.State state, boolean isInLobby) { - if (state == LocusParticipant.State.IDLE) { + private static CallMembership.State fromLocusState(LocusParticipantModel.State state, boolean isInLobby) { + if (state == LocusParticipantModel.State.IDLE) { return isInLobby ? State.WAITING : State.IDLE; - } else if (state == LocusParticipant.State.NOTIFIED) { + } else if (state == LocusParticipantModel.State.NOTIFIED) { return State.NOTIFIED; - } else if (state == LocusParticipant.State.JOINED) { + } else if (state == LocusParticipantModel.State.JOINED) { return State.JOINED; - } else if (state == LocusParticipant.State.LEFT) { + } else if (state == LocusParticipantModel.State.LEFT) { return State.LEFT; - } else if (state == LocusParticipant.State.DECLINED) { + } else if (state == LocusParticipantModel.State.DECLINED) { return State.DECLINED; - } else if (state == LocusParticipant.State.LEAVING) { + } else if (state == LocusParticipantModel.State.LEAVING) { return State.LEFT; } else { return State.UNKNOWN; } } - @StringPart - private boolean _isInitiator = false; - - @StringPart - private String _personId; - - @StringPart - private State _state = State.UNKNOWN; + private final CallImpl call; - @StringPart - private String _email; + private LocusParticipantModel model; - @StringPart - private String _sipUrl; + private boolean self; - @StringPart - private String _phoneNumber; + private boolean initiator = false; - @StringPart - private boolean _sendingVideo = false; + private String personId; - @StringPart - private boolean _sendingAudio = false; - - @StringPart - private boolean _sendingSharing = false; + CallMembershipImpl(LocusParticipantModel participant, CallImpl call) { + this.call = call; + setModel(participant); + Ln.d("CallMembership: " + getId() + " person: " + getPersonId() + " email: " + getEmail() + " video: " + isSendingVideo() + " audio: " + isSendingAudio()); + } - CallMembershipImpl(LocusParticipant participant, Call call) { - LocusParticipantInfo person = participant.getPerson(); - _personId = new WebexId(WebexId.Type.PEOPLE_ID, person.getId()).toHydraId(); - _email = person.getEmail(); - _phoneNumber = person.getPhoneNumber(); - _sipUrl = person.getSipUrl(); - _isInitiator = participant.isCreator(); - _state = fromLocusState(participant.getState(), participant.isInLobby()); - MediaDirection videoStatus = participant.getStatus().getVideoStatus(); - MediaDirection audioStatus = participant.getStatus().getAudioStatus(); - Ln.d("CallMembership: " + person.getId() + " email: " + _email + " video: " +videoStatus + " audio: " + audioStatus); - _sendingVideo = videoStatus == null || videoStatus == MediaDirection.SENDRECV || videoStatus == MediaDirection.SENDONLY; - _sendingAudio = audioStatus == null || audioStatus == MediaDirection.SENDRECV || audioStatus == MediaDirection.SENDONLY; - _sendingSharing = false; - if (call instanceof CallImpl && ((CallImpl) call).getSharingSender() != null) { - _sendingSharing = ((CallImpl) call).getSharingSender().getPerson().getId().equalsIgnoreCase(person.getId()); - } + public String getId() { + return model.getId(); + } + public boolean isSelf() { + return self; } public boolean isInitiator() { - return _isInitiator; + return initiator; } public String getPersonId() { - return _personId; + return personId; } public State getState() { - return _state; + return fromLocusState(model.getState(), model.isInLobby()); } public String getEmail() { - return _email; + return model.getPerson() == null ? null : model.getPerson().getEmail(); } public String getSipUrl() { - return _sipUrl; + return model.getPerson() == null ? null : model.getPerson().getSipUrl(); } public String getPhoneNumber() { - return _phoneNumber; + return model.getPerson() == null ? null : model.getPerson().getPhoneNumber(); } public boolean isSendingVideo() { - return _sendingVideo; + return model.getStatus() != null && model.getStatus().getVideoStatus() == LocusMediaDirection.SENDRECV; } public boolean isSendingAudio() { - return _sendingAudio; + return model.getStatus() != null && model.getStatus().getAudioStatus() == LocusMediaDirection.SENDRECV; } public boolean isSendingSharing() { - return _sendingSharing; + LocusModel model = call.getModel(); + FloorModel floor = model.getFloor(); + return floor != null && model.isFloorGranted() + && floor.getBeneficiary() != null && Checker.isEqual(floor.getBeneficiary().getId(), getId()) + && floor.getDisposition() == FloorModel.Disposition.GRANTED; + } + + @Override + public boolean isActiveSpeaker() { + return Checker.isEqual(getId(), ((CallMembershipImpl) call.getActiveSpeaker()).getId()); + } + + public LocusParticipantModel getModel() { + synchronized (this) { + return model; + } + } + + public void setModel(@NotNull LocusParticipantModel model) { + synchronized (this) { + this.model = model; + this.self = Checker.isEqual(model.getId(), call.getModel().getSelfId()); + this.personId = new WebexId(WebexId.Type.PEOPLE_ID, model.getPerson().getId()).toHydraId(); + this.initiator = model.isCreator(); + } + } + + public boolean containsCSI(long csi) { + List CSIs = model.getStatus() == null ? null : model.getStatus().getCsis(); + if (!Checker.isEmpty(CSIs)) { + return CSIs.contains(csi); + } + return false; } public String toString() { - return Objects.toStringByAnnotation(this); + return "CallMembership: " + getId() + + " status: " + getState() + + " isSelf: " + isSelf() + + " person: " + getPersonId() + + " email: " + getEmail() + + " video: " + isSendingVideo() + + " audio: " + isSendingAudio(); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CallMembershipImpl that = (CallMembershipImpl) o; + return getId().equals(that.getId()); + } + + @Override + public int hashCode() { + return java.util.Objects.hash(getId()); + } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallService.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallService.java new file mode 100644 index 00000000..83e45dcd --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/CallService.java @@ -0,0 +1,368 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.phone.internal; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.Device; +import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.model.*; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.people.Person; +import com.ciscowebex.androidsdk.people.internal.PersonClientImpl; +import com.ciscowebex.androidsdk.phone.CallMembership; +import com.ciscowebex.androidsdk.phone.MediaOption; +import com.ciscowebex.androidsdk.utils.EmailAddress; +import com.ciscowebex.androidsdk.utils.Json; +import com.ciscowebex.androidsdk.utils.Lists; +import com.ciscowebex.androidsdk.utils.WebexId; +import com.github.benoitdion.ln.Ln; +import me.helloworld.utils.Checker; +import me.helloworld.utils.collection.Maps; + +import java.util.*; + +public class CallService { + + static class DialTarget { + + private String address; + private AddressType type; + + enum AddressType { + PEOPLE_ID, + PEOPLE_MAIL, + SPACE_ID, + SPACE_MAIL, + OTHER + } + + public boolean isEndpoint() { + return this.type != AddressType.SPACE_ID; + } + + public boolean isGroup() { + return this.type == AddressType.SPACE_ID || this.type == AddressType.SPACE_MAIL; + } + + public static void lookup(@NonNull String address, Authenticator authenticator, CompletionHandler callback) { + WebexId id = WebexId.from(address); + Ln.d("%s, %s", id, address); + if (id != null && id.is(WebexId.Type.PEOPLE_ID)) { + callback.onComplete(ResultImpl.success(new DialTarget(id.getId(), AddressType.PEOPLE_ID))); + } + else if (id != null && id.is(WebexId.Type.ROOM_ID)) { + callback.onComplete(ResultImpl.success(new DialTarget(id.getId(), AddressType.SPACE_ID))); + } + else if (EmailAddress.isValid(address)) { + if (address.toLowerCase().endsWith("@meet.ciscospark.com")) { + callback.onComplete(ResultImpl.success(new DialTarget(address, AddressType.SPACE_MAIL))); + } + else if (address.contains("@") && !address.contains(".")) { + new PersonClientImpl(authenticator).list(address, null, 1, result -> { + List data = result.getData(); + if (!Checker.isEmpty(data)) { + callback.onComplete(ResultImpl.success(new DialTarget(WebexId.from(data.get(0).getId()).getId(), AddressType.PEOPLE_ID))); + } + else { + callback.onComplete(ResultImpl.success(new DialTarget(address, AddressType.PEOPLE_MAIL))); + } + }); + } + else { + callback.onComplete(ResultImpl.success(new DialTarget(address, AddressType.PEOPLE_MAIL))); + } + } + else { + callback.onComplete(ResultImpl.success(new DialTarget(address, AddressType.OTHER))); + } + + } + + private DialTarget(String address, AddressType type) { + this.address = address; + this.type = type; + } + + public String getAddress() { + return address; + } + } + + private Authenticator authenticator; + + public CallService(@NonNull Authenticator authenticator) { + this.authenticator = authenticator; + } + + public void getOrCreatePermanentLocus(String id, Device device, CompletionHandler callback) { + Service.Conv.get("conversations", id, "locus") + .auth(authenticator) + .device(device) + .queue(Queue.main) + .model(LocusUrlResponseModel.class) + .error(callback) + .async((Closure) model -> { + if (model == null || model.getLocusUrl() == null) { + callback.onComplete(ResultImpl.error("No locus uri")); + } + else { + callback.onComplete(ResultImpl.success(model.getLocusUrl())); + } + }); + } + + public void call(@NonNull String address, @NonNull String callId, @NonNull Device device, @NonNull String sdp, @Nullable MediaOption.VideoLayout layout, MediaEngineReachabilityModel reachabilities, @NonNull CompletionHandler callback) { + Service.Locus.post(makeBody(callId, layout, device, sdp, address, reachabilities)).to("loci", "call") + .auth(authenticator) + .device(device) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) model -> { + LocusModel locus = model.getLocus(); + if (locus != null && model.getMediaConnections() != null) { + locus.setMediaConnections(model.getMediaConnections()); + } + if (layout == null) { + callback.onComplete(ResultImpl.success(locus)); + return; + } + if (locus.getSelf() != null){ + layout(locus.getSelf().getUrl(), device, layout, result -> callback.onComplete(ResultImpl.success(locus))); + } + }); + } + + public void join(@NonNull String url, @NonNull String callId, @NonNull Device device, @NonNull String sdp, @Nullable MediaOption.VideoLayout layout, MediaEngineReachabilityModel reachabilities, @NonNull CompletionHandler callback) { + Service.Locus.post(makeBody(callId, layout, device, sdp, null, reachabilities)).url(url).to("participant") + .auth(authenticator) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) model -> { + LocusModel locus = model.getLocus(); + if (locus != null && model.getMediaConnections() != null) { + locus.setMediaConnections(model.getMediaConnections()); + } + if (layout == null) { + callback.onComplete(ResultImpl.success(locus)); + return; + } + if (locus.getSelf() != null){ + layout(locus.getSelf().getUrl(), device, layout, result -> callback.onComplete(ResultImpl.success(locus))); + } + }); + } + + public void leave(@NonNull String participantUrl, @NonNull Device device, @NonNull CompletionHandler callback) { + Service.Locus.put(makeBody(device.getDeviceUrl())).url(participantUrl).to("leave") + .auth(authenticator) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) model -> { + LocusModel locus = model == null ? null : model.getLocus(); + if (locus != null && model.getMediaConnections() != null) { + locus.setMediaConnections(model.getMediaConnections()); + } + callback.onComplete(ResultImpl.success(locus)); + }); + } + + public void decline(@NonNull String url, @NonNull Device device, @NonNull CompletionHandler callback) { + Service.Locus.put(makeBody(device.getDeviceUrl())).url(url).to("participant", "decline") + .auth(authenticator) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) data -> callback.onComplete(ResultImpl.success(null))); + } + + public void alert(@NonNull String url, @NonNull Device device, @NonNull CompletionHandler callback) { + Service.Locus.put(makeBody(device.getDeviceUrl())).url(url).to("participant", "alert") + .auth(authenticator) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) data -> callback.onComplete(ResultImpl.success(null))); + } + + public void update(@NonNull String mediaUrl, @NonNull String mediaId, @NonNull Device device, @NonNull MediaInfoModel media, @NonNull CompletionHandler callback) { + Map json = new HashMap<>(); + MediaConnectionModel mc = new MediaConnectionModel(); + mc.setLocalSdp(Json.get().toJson(media)); + mc.setType(media.getType()); + mc.setMediaId(mediaId); + json.put("localMedias", Lists.asList(mc)); + json.put("deviceUrl", device.getDeviceUrl()); + json.put("respOnlySdp", true); + Service.Locus.put(json).url(mediaUrl) + .auth(authenticator) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) model -> { + LocusModel locus = model == null ? null : model.getLocus(); + if (locus != null && model.getMediaConnections() != null) { + locus.setMediaConnections(model.getMediaConnections()); + } + callback.onComplete(ResultImpl.success(locus)); + }); + } + + public void update(@NonNull MediaShareModel share, @NonNull String url, @NonNull Device device, @NonNull CompletionHandler callback) { + Map floor = new HashMap<>(); + floor.put("disposition", share.getDisposition()); + floor.put("requester", Maps.makeMap("url", share.getRequesterUrl())); + floor.put("beneficiary", Maps.makeMap("url", share.getBeneficiaryUrl(), "devices", Maps.makeMap("url", device.getDeviceUrl()))); + Service.Locus.put(Maps.makeMap("floor", floor)).url(url) + .auth(authenticator) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) data -> callback.onComplete(ResultImpl.success(null))); + } + + public void get(@NonNull String callUrl, @NonNull CompletionHandler callback) { + Service.Locus.get().url(callUrl) + .auth(authenticator) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) model -> { + LocusModel locus = model == null ? null : model.getLocus(); + if (locus != null && model.getMediaConnections() != null) { + locus.setMediaConnections(model.getMediaConnections()); + } + callback.onComplete(ResultImpl.success(locus)); + }); + } + + public void list(@NonNull Device device, @NonNull CompletionHandler> callback) { + Service.Locus.get("loci") + .auth(authenticator) + .device(device) + .queue(Queue.main) + .model(LocusListResponseModel.class) + .error(callback) + .async((Closure) model -> callback.onComplete(ResultImpl.success(model == null ? Collections.emptyList() : model.getLoci()))); + } + + public void admit(@NonNull String url, @NonNull List memberships, @NonNull CompletionHandler callback) { + List ids = new ArrayList<>(memberships.size()); + for (CallMembership membership : memberships) { + ids.add(((CallMembershipImpl)membership).getId()); + } + Map params = Maps.makeMap("admit", Maps.makeMap("participantIds", ids)); + Service.Locus.patch(params).url(url).to("controls") + .auth(authenticator) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) model -> { + LocusModel locus = model == null ? null : model.getLocus(); + if (locus != null && model.getMediaConnections() != null) { + locus.setMediaConnections(model.getMediaConnections()); + } + callback.onComplete(ResultImpl.success(locus)); + }); + } + + public void layout(@NonNull String participantUrl, @NonNull Device device, @NonNull MediaOption.VideoLayout layout, @NonNull CompletionHandler callback) { + String type = "ActivePresence"; + if (layout == MediaOption.VideoLayout.SINGLE) { + type = "Single"; + } + else if (layout == MediaOption.VideoLayout.GRID) { + type = "Equal"; + } + Map params = Maps.makeMap("layout", Maps.makeMap("deviceUrl", device.getDeviceUrl(), "type", type)); + Service.Locus.patch(params).url(participantUrl).to("controls") + .auth(authenticator) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) model -> { + LocusModel locus = model == null ? null : model.getLocus(); + if (locus != null && model.getMediaConnections() != null) { + locus.setMediaConnections(model.getMediaConnections()); + } + callback.onComplete(ResultImpl.success(locus)); + }); + } + + public void keepalive(@NonNull String url, @NonNull CompletionHandler callback) { + Service.Locus.get().url(url).auth(authenticator).queue(Queue.main).error(callback).async((Closure) data -> callback.onComplete(ResultImpl.success(null))); + } + + public void dtmf(@NonNull String participantUrl, @NonNull Device device, int correlation, @NonNull String event, @Nullable Integer volume, @Nullable Integer durationMillis, @NonNull CompletionHandler callback) { + Map dtmf = new HashMap<>(); + dtmf.put("tones", event); + dtmf.put("correlationId", correlation); + if (volume != null) { + dtmf.put("volume", volume); + } + if (durationMillis != null) { + dtmf.put("durationMillis", durationMillis); + } + Map json = new HashMap<>(); + json.put("deviceUrl", device.getDeviceUrl()); + json.put("respOnlySdp", true); + json.put("dtmf", dtmf); + Service.Locus.post(json).url(participantUrl).to("sendDtmf") + .auth(authenticator) + .queue(Queue.main) + .model(LocusMediaResponseModel.class) + .error(callback) + .async((Closure) data -> callback.onComplete(ResultImpl.success(null))); + } + + private Object makeBody(String callId, MediaOption.VideoLayout layout, Device device, String sdp, String callee, MediaEngineReachabilityModel reachabilities) { + Map json = new HashMap<>(); + MediaConnectionModel mc = new MediaConnectionModel(); + mc.setLocalSdp(Json.get().toJson(new MediaInfoModel(sdp, reachabilities == null ? null : reachabilities.reachability))); + mc.setType("SDP"); + json.put("localMedias", Lists.asList(mc)); + json.put("device", device.toJsonMap(layout == MediaOption.VideoLayout.SINGLE ? null : Device.WEB_DEVICE_TYPE)); + json.put("respOnlySdp", true); + json.put("correlationId", callId); + if (callee != null) { + json.put("invitee", Maps.makeMap("address", callee)); + json.put("supportsNativeLobby", true); + json.put("moderator", false); + } + return json; + } + + private Object makeBody(String deviceUrl) { + Map json = new HashMap<>(); + json.put("deviceUrl", deviceUrl); + json.put("respOnlySdp", true); + return json; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/H264LicensePrompter.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/H264LicensePrompter.java index a0da5b28..230ea863 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/H264LicensePrompter.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/H264LicensePrompter.java @@ -25,19 +25,12 @@ import android.app.AlertDialog; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.net.Uri; import android.support.annotation.NonNull; +import com.ciscowebex.androidsdk.internal.Settings; import com.github.benoitdion.ln.Ln; -/** - * Created with IntelliJ IDEA. - * User: zhiyuliu - * Date: 15/09/2017 - * Time: 6:42 PM - */ - public class H264LicensePrompter { private static final String STR_ENABLE_HINT = "To enable video calls, activate a free video license (H.264 AVC) from Cisco. By selecting 'Activate', you accept the Cisco End User License Agreement and Notices."; @@ -47,10 +40,7 @@ public interface CompletionHandler { void onComplete(T result); } - private SharedPreferences _preferences; - - H264LicensePrompter(SharedPreferences preferences) { - _preferences = preferences; + H264LicensePrompter() { } String getLicense() { @@ -93,11 +83,11 @@ void check(@NonNull AlertDialog.Builder builder, @NonNull CompletionHandler callback; + + public Call(boolean isGroup, + Device device, + MediaSession session, + LocusModel model, + CompletionHandler callback) { + this.group = isGroup; + this.device = device; + this.session = session; + this.locus = model; + this.callback = callback; + } + + public boolean isGroup() { + return group; + } + + public Device getDevice() { + return device; + } + + public MediaSession getSession() { + return session; + } + + public LocusModel getLocus() { + return locus; + } + + public CompletionHandler getCallback() { + return callback; + } + } + + class Answer extends WithResult { + + public Answer(CallImpl call, LocusModel result, CompletionHandler callback) { + super(call, result, callback); + } + } + + class Leave extends WithResult { + + public Leave(CallImpl call, LocusModel result, CompletionHandler callback) { + super(call, result, callback); + } + } + + class Update extends WithResult { + + public Update(CallImpl call, LocusModel result, CompletionHandler callback) { + super(call, result, callback); + } + } + + class Reject extends WithoutResult { + + public Reject(CallImpl call, CompletionHandler callback) { + super(call, callback); + } + } + + class Ack extends WithoutResult { + + public Ack(CallImpl call, CompletionHandler callback) { + super(call, callback); + } + } + + class MediaShare extends WithoutResult { + + private Intent sharing; + private FloorModel.Disposition disposition; + + public MediaShare(CallImpl call, FloorModel.Disposition disposition, Intent sharing, CompletionHandler callback) { + super(call, callback); + this.sharing = sharing; + this.disposition = disposition; + } + + public Intent getIntent() { + return sharing; + } + + public FloorModel.Disposition getDisposition() { + return disposition; + } + } + + abstract class WithoutResult extends CallRelated { + + public WithoutResult(CallImpl call, CompletionHandler callback) { + super(call, callback); + } + + } + + abstract class WithResult extends CallRelated { + + private LocusModel result; + + public WithResult(CallImpl call, LocusModel result, CompletionHandler callback) { + super(call, callback); + this.result = result; + } + + public LocusModel getResult() { + return result; + } + + } + + abstract class CallRelated implements LocusResponse { + + private CallImpl call; + private CompletionHandler callback; + + public CallRelated(CallImpl call, CompletionHandler callback) { + this.call = call; + this.callback = callback; + } + + public CallImpl getCall() { + return call; + } + + public CompletionHandler getCallback() { + return callback; + } + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaEngine.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaEngine.java new file mode 100644 index 00000000..1a9e7a7e --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaEngine.java @@ -0,0 +1,82 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.phone.internal; + +import android.content.Context; +import android.view.View; +import com.ciscowebex.androidsdk.Webex; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.media.MediaCapability; +import com.ciscowebex.androidsdk.internal.media.WMEngine; +import com.ciscowebex.androidsdk.internal.media.WmeSession; +import com.ciscowebex.androidsdk.internal.model.MediaEngineReachabilityModel; +import com.ciscowebex.androidsdk.phone.MediaOption; +import com.ciscowebex.androidsdk.utils.Utils; + +import java.util.List; +import java.util.Map; + +public class MediaEngine { + + private final WMEngine engine; + + public MediaEngine(Context context, Webex.LogLevel level) { + engine = new WMEngine(context, Utils.toTraceLevelMask(level)); + } + + public void release() { + engine.release(); + } + + public MediaSession createSession(MediaCapability capability, MediaOption option) { + WmeSession session = engine.createSession(capability, option); + return new MediaSession(session, false); + } + + public MediaSession createPreviveSession(MediaCapability capability, View view) { + WmeSession session = engine.createPreviveSession(capability, view); + return new MediaSession(session, true); + } + + public void setLoggingLevel(Webex.LogLevel level) { + engine.setLoggingLevel(Utils.toTraceLevelMask(level)); + } + + public void setDisplayRotation(int rotation) { + engine.setDisplayRotation(rotation); + } + + public String getVersion() { + return engine.getVersion(); + } + + public void performReachabilityCheck(Map>> clusterInfo, Closure callback) { + engine.performStunReachabilityCheck(clusterInfo, callback::invoke); + } + + public void clearReachability() { + engine.clearReachabilityData(); + } + + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaObserver.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaObserver.java new file mode 100644 index 00000000..b7227500 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaObserver.java @@ -0,0 +1,246 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.phone.internal; + +import android.util.Size; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.internal.media.MediaError; +import com.ciscowebex.androidsdk.internal.media.WMEngine; +import com.ciscowebex.androidsdk.internal.media.WmeObserver; +import com.ciscowebex.androidsdk.internal.media.WmeTrack; +import com.ciscowebex.androidsdk.phone.AuxStream; +import com.ciscowebex.androidsdk.phone.CallMembership; +import com.ciscowebex.androidsdk.phone.CallObserver; +import com.ciscowebex.androidsdk.phone.MultiStreamObserver; +import com.github.benoitdion.ln.Ln; +import me.helloworld.utils.Checker; + +class MediaObserver implements WmeObserver { + + private final CallImpl call; + + public MediaObserver(CallImpl call) { + this.call = call; + } + + @Override + public void onRemoteVideoAvailable(boolean available) { + Queue.main.run(() -> { + if (call != null && call.getObserver() != null) { + call.getObserver().onMediaChanged(new CallObserver.RemoteSendingVideoEvent(call, available)); + } + }); + } + + @Override + public void onAuxVideoAvailable(int vid, boolean available) { + Queue.main.run(() -> { + if (call != null && call.getMultiStreamObserver() != null) { + AuxStream stream = call.getAuxStream(vid); + if (stream != null) { + call.getMultiStreamObserver().onAuxStreamChanged(new MultiStreamObserver.AuxStreamSendingVideoEvent(call, stream)); + } + } + }); + } + + @Override + public void onRemoteSharingAvailable(boolean available) { + Queue.main.run(() -> { + if (call != null && call.getObserver() != null) { + call.getObserver().onMediaChanged(new CallObserver.RemoteSendingSharingEvent(call, available)); + } + }); + } + + @Override + public void onActiveSpeakerChanged(long[] oldCSIs, long[] newCSIs) { + Queue.main.run(() -> { + if (call != null && newCSIs != null) { + CallMembershipImpl membership = null; + boolean done = false; + if (newCSIs.length < 1) { + done = true; + } + else { + loop: for (long csi : newCSIs) { + for (CallMembership member : call.getMemberships()) { + if (((CallMembershipImpl)member).containsCSI(csi)) { + membership = (CallMembershipImpl) member; + done = true; + break loop; + } + } + } + } + if (done) { + CallMembershipImpl old = (CallMembershipImpl) call.getActiveSpeaker(); + if (membership != null && old != null && Checker.isEqual(membership.getId(), old.getId())) { + return; + } + call.setActiveSpeaker(membership); + if (call.getObserver() != null) { + call.getObserver().onMediaChanged(new CallObserver.ActiveSpeakerChangedEvent(call, old, membership)); + } + } + } + }); + } + + @Override + public void onCSIChanged(long vid, long[] oldCSIs, long[] newCSIs) { + Queue.main.run(() -> { + if (call != null && newCSIs != null) { + AuxStreamImpl stream = (AuxStreamImpl) call.getAuxStream(vid); + if (stream != null) { + CallMembershipImpl membership = null; + boolean done = false; + if (newCSIs.length < 1) { + done = true; + } + else { + loop: for (long csi : newCSIs) { + for (CallMembership member : call.getMemberships()) { + if (((CallMembershipImpl)member).containsCSI(csi)) { + membership = (CallMembershipImpl) member; + done = true; + break loop; + } + } + } + } + if (done) { + CallMembershipImpl old = (CallMembershipImpl) stream.getPerson(); + if (membership != null && old != null && Checker.isEqual(membership.getId(), old.getId())) { + return; + } + stream.setPerson(membership); + if (call.getMultiStreamObserver() != null) { + call.getMultiStreamObserver().onAuxStreamChanged(new MultiStreamObserver.AuxStreamPersonChangedEvent(call, stream, old, membership)); + } + } + } + } + }); + } + + @Override + public void onAvailableMediaChanged(int count) { + Queue.main.run(() -> { + if (call != null) { + call.updateAuxStreamCount(); + } + }); + } + + @Override + public void onMediaDecodeSizeChanged(WMEngine.Media media, long vid, Size size) { + if (media == WMEngine.Media.Video) { + Queue.main.run(() -> { + if (call != null) { + if (vid == WMEngine.MAIN_VID && call.getObserver() != null) { + call.getObserver().onMediaChanged(new CallObserver.RemoteVideoViewSizeChanged(call)); + } + else if (vid >= 0 && call.getMultiStreamObserver() != null){ + AuxStream stream = call.getAuxStream(vid); + if (stream != null) { + call.getMultiStreamObserver().onAuxStreamChanged(new MultiStreamObserver.AuxStreamSizeChangedEvent(call, stream)); + } + } + } + }); + } + else if (media == WMEngine.Media.Sharing) { + Queue.main.run(() -> { + if (call != null && call.getObserver() != null) { + call.getObserver().onMediaChanged(new CallObserver.RemoteSharingViewSizeChanged(call)); + } + }); + } + } + + @Override + public void onMediaRenderSizeChanged(WMEngine.Media media, long vid, Size size) { + if (media == WMEngine.Media.Video) { + Queue.main.run(() -> { + if (call != null && call.getObserver() != null) { + call.getObserver().onMediaChanged(new CallObserver.LocalVideoViewSizeChanged(call)); + } + }); + } + if (media == WMEngine.Media.Sharing) { + Queue.main.run(() -> { + if (call != null && call.getObserver() != null) { + call.getObserver().onMediaChanged(new CallObserver.LocalSharingViewSizeChanged(call)); + } + }); + } + } + + @Override + public void onTrackMuted(WmeTrack.Type track, long vid, boolean mute) { + Ln.d("onTrackMuted: %s, %s, %s", track, vid, mute); + Queue.main.run(() -> { + if (call != null) { + CallObserver.MediaChangedEvent event = null; + if (track == WmeTrack.Type.LocalVideo) { + call.updateMedia(call.isSendingAudio(), !mute); + event = new CallObserver.SendingVideo(call, !mute); + } + else if (track == WmeTrack.Type.RemoteVideo) { + event = new CallObserver.ReceivingVideo(call, !mute); + } + else if (track == WmeTrack.Type.LocalAudio) { + call.updateMedia(!mute, call.isSendingVideo()); + event = new CallObserver.SendingAudio(call, !mute); + } + else if (track == WmeTrack.Type.RemoteAudio) { + event = new CallObserver.ReceivingAudio(call, !mute); + } + else if (track == WmeTrack.Type.LocalSharing) { + event = new CallObserver.SendingSharingEvent(call, !mute); + } + else if (track == WmeTrack.Type.RemoteSharing) { + event = new CallObserver.ReceivingSharing(call, !mute); + } + if (call.getObserver() != null && event != null) { + call.getObserver().onMediaChanged(event); + } + } + }); + } + + @Override + public void onCameraSwitched() { + Queue.main.run(() -> { + if (call != null && call.getObserver() != null) { + call.getObserver().onMediaChanged(new CallObserver.CameraSwitched(call)); + } + }); + } + + @Override + public void onError(MediaError error) { + Ln.e("Media Error: " + error); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaSession.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaSession.java new file mode 100644 index 00000000..8d5b7d6c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/MediaSession.java @@ -0,0 +1,361 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.phone.internal; + +import android.support.annotation.Nullable; +import android.util.Pair; +import android.util.Size; +import android.view.View; +import com.ciscowebex.androidsdk.internal.media.*; +import com.ciscowebex.androidsdk.internal.media.WmeTrack; +import com.ciscowebex.androidsdk.phone.Phone; +import com.github.benoitdion.ln.Ln; +import com.webex.wme.MediaConnection; +import com.webex.wme.MediaTrack; + +public class MediaSession { + + interface MediaType {} + + static class MediaTypeVideo implements MediaType { + + private View localView; + private View remoteView; + + public MediaTypeVideo(@Nullable Pair views) { + if (views != null) { + localView = views.first; + remoteView = views.second; + } + } + } + + static class MediaTypeSharing implements MediaType { + + private View view; + + public MediaTypeSharing(@Nullable View view) { + this.view = view; + } + + } + + private interface SdpCallback { + void onSdp(String sdp); + } + + private final WmeSession session; + + private boolean localOnly; + + MediaSession(WmeSession session, boolean localOnly) { + this.session = session; + this.localOnly = localOnly; + } + + public MediaCapability getCapability() { + return session.getCapability(); + } + + public boolean isRunning() { + return session.getState() == WmeSession.State.CONNECTED; + } + + public void startPreview() { + if (localOnly) { + WmeTrack track = session.getTrack(WmeTrack.Type.Preview, WMEngine.MAIN_VID); + track.setRemoteSDPDirection(MediaConnection.MediaDirection.SendRecv); + track.start(); + } + } + + public void stopPreview() { + if (localOnly) { + WmeTrack track = session.getTrack(WmeTrack.Type.Preview, WMEngine.MAIN_VID); + track.stop(true); + session.destroy(); + } + } + + public void startCloud(CallImpl call) { + if (!localOnly) { + session.launch(new MediaObserver(call)); + } + } + + public void stopCloud() { + if (!localOnly) { + session.destroy(); + } + } + + public void joinSharing(String id, boolean send) { + if (hasSharing()) { + session.joinSharing(id, send); + } + } + + public void leaveSharing(boolean send) { + if (hasSharing()) { + session.leaveSharing(send); + } + } + + public int subscribeAuxVideo(View view) { + if (isRunning()) { + return session.subscribeAuxVideo(view); + } + return -1; + } + + public void unsubscribeAuxVideo(int vid) { + if (vid >= 0) { + session.unsubscribeAuxVideo(vid); + } + } + + public void addAuxVideoView(View view, int vid) { + session.addRenderView(view, WmeTrack.Type.AuxVideo, vid); + } + + public void removeAuxVideoView(View view, int vid) { + session.removeRenderView(view, WmeTrack.Type.AuxVideo, vid); + } + + public Size getAuxVideoViewSize(int vid) { + return session.getRenderViewSize(WmeTrack.Type.AuxVideo, vid); + } + + public boolean isAuxVideoLocalMuted(int vid) { + return session.isMutedByLocal(WmeTrack.Type.AuxVideo, vid); + } + + public boolean isAuxVideoRemoteMuted(int vid) { + return session.isMutedByRemote(WmeTrack.Type.AuxVideo, vid); + } + + public void muteAuxVideo(int vid) { + session.mute(WmeTrack.Type.AuxVideo, vid); + } + + public void unmuteAuxVideo(int vid) { + session.unmute(WmeTrack.Type.AuxVideo, vid); + } + + public int getAuxStreamCount() { + return session.getAuxStreamCount(); + } + + public void update(MediaType type) { + if (type instanceof MediaTypeVideo) { + session.updateVideoTracks(((MediaTypeVideo) type).localView, ((MediaTypeVideo) type).remoteView); + } + else if (type instanceof MediaTypeSharing) { + session.updateSharingTracks(((MediaTypeSharing) type).view); + } + } + + public synchronized String getLocalSdp() { + session.createLocalSdpOffer(sdp -> { + synchronized (this) { + this.notifyAll(); + } + }); + while (session.getLocalSdpOffer() == null) { + try { + this.wait(); + } catch (InterruptedException e) { + Ln.e(e); + } + } + return session.getLocalSdpOffer(); + } + + public void setRemoteSdp(String sdp) { + session.receiveRemoteAnswer(sdp); + } + + public boolean hasAudio() { + return session.getCapability().hasAudio(); + } + + public boolean hasVideo() { + return session.getCapability().hasVideo(); + } + + public boolean hasSharing() { + return session.getCapability().hasSharing(); + } + + public Size getLocalVideoViewSize() { + return session.getRenderViewSize(WmeTrack.Type.LocalVideo); + } + + public Size getRemoteVideoViewSize() { + return session.getRenderViewSize(WmeTrack.Type.RemoteVideo); + } + + public Size getLocalSharingViewSize() { + return session.getRenderViewSize(WmeTrack.Type.LocalSharing); + } + + public Size getRemoteSharingViewSize() { + return session.getRenderViewSize(WmeTrack.Type.RemoteSharing); + } + + public Pair getVideoViews() { + View local = session.getRenderView(WmeTrack.Type.LocalVideo); + View remote = session.getRenderView(WmeTrack.Type.RemoteVideo); + return (local == null || remote == null) ? null : new Pair<>(local, remote); + } + + public View getSharingView() { + return session.getRenderView(WmeTrack.Type.RemoteSharing); + } + + public void setLocalAudioSending(boolean sending) { + if (sending) { + session.unmute(WmeTrack.Type.LocalAudio); + } else { + session.mute(WmeTrack.Type.LocalAudio); + } + } + + public void setRemoteAudioReceiving(boolean receiving) { + if (receiving) { + session.unmute(WmeTrack.Type.RemoteAudio); + } else { + session.mute(WmeTrack.Type.RemoteAudio); + } + } + + public boolean isLocalAudioSending() { + return !session.isMutedByLocal(WmeTrack.Type.LocalAudio); + } + + public boolean isRemoteAudioReceiving() { + return !session.isMutedByLocal(WmeTrack.Type.RemoteAudio); + } + + public boolean isRemoteAudioSending() { + return !session.isMutedByRemote(WmeTrack.Type.RemoteAudio); + } + + public void setLocalVideoSending(boolean sending) { + if (sending) { + session.unmute(WmeTrack.Type.LocalVideo); + } else { + session.mute(WmeTrack.Type.LocalVideo); + } + } + + public void setRemoteVideoReceiving(boolean receiving) { + if (receiving) { + session.unmute(WmeTrack.Type.RemoteVideo); + } else { + session.mute(WmeTrack.Type.RemoteVideo); + } + } + + public boolean isLocalVideoSending() { + return !session.isMutedByLocal(WmeTrack.Type.LocalVideo); + } + + public boolean isRemoteVideoReceiving() { + return !session.isMutedByLocal(WmeTrack.Type.RemoteVideo); + } + + public boolean isRemoteVideoSending() { + return !session.isMutedByRemote(WmeTrack.Type.RemoteVideo); + } + + public void setLocalSharingSending(boolean sending) { + if (sending) { + session.unmute(WmeTrack.Type.LocalSharing); + } else { + session.mute(WmeTrack.Type.LocalSharing); + } + } + + public void setRemoteSharingReceiving(boolean receiving) { + if (receiving) { + session.unmute(WmeTrack.Type.RemoteSharing); + } else { + session.mute(WmeTrack.Type.RemoteSharing); + } + } + + public boolean isLocalSharingSending() { + return !session.isMutedByLocal(WmeTrack.Type.LocalSharing); + } + + public boolean isRemoteSharingReceiving() { + return !session.isMutedByLocal(WmeTrack.Type.RemoteSharing); + } + + public boolean isRemoteSharingSending() { + return !session.isMutedByRemote(WmeTrack.Type.RemoteSharing); + } + + public void setFacingMode(Phone.FacingMode facingMode) { + session.setCamera(WMEngine.Camera.fromFaceMode(facingMode)); + } + + public Phone.FacingMode getFacingMode() { + return session.getCamera().toFaceMode(); + } + + public void prepareToEnterVideoInterruption() { + WmeTrack localVideo = session.getTrack(WmeTrack.Type.LocalVideo, WMEngine.MAIN_VID); + if (localVideo != null) { + localVideo.stop(true); + } + WmeTrack remoteVideo = session.getTrack(WmeTrack.Type.RemoteVideo, WMEngine.MAIN_VID); + if (remoteVideo != null) { + remoteVideo.stop(true); + } + WmeTrack remoteShare = session.getTrack(WmeTrack.Type.RemoteSharing, WMEngine.MAIN_VID); + if (remoteShare != null) { + remoteShare.stop(true); + } + } + + public void prepareToLeaveVideoInterruption() { + WmeTrack localVideo = session.getTrack(WmeTrack.Type.LocalVideo, WMEngine.MAIN_VID); + if (localVideo != null) { + localVideo.stop(true); + localVideo.start(); + } + WmeTrack remoteVideo = session.getTrack(WmeTrack.Type.RemoteVideo, WMEngine.MAIN_VID); + if (remoteVideo != null) { + remoteVideo.stop(true); + remoteVideo.start(); + } + WmeTrack remoteShare = session.getTrack(WmeTrack.Type.RemoteSharing, WMEngine.MAIN_VID); + if (remoteShare != null) { + remoteShare.stop(true); + remoteShare.start(); + } + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java index 07323729..292e85d7 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java @@ -22,330 +22,503 @@ package com.ciscowebex.androidsdk.phone.internal; -import java.util.*; - -import javax.inject.Inject; - -import android.Manifest; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Parcelable; import android.support.annotation.NonNull; -import android.util.Base64; -import android.view.SurfaceHolder; -import android.view.SurfaceView; +import android.support.annotation.Nullable; +import android.util.Pair; import android.view.View; - -import com.cisco.spark.android.authenticator.AuthenticatedUserTask; -import com.cisco.spark.android.callcontrol.CallContext; -import com.cisco.spark.android.callcontrol.CallControlService; -import com.cisco.spark.android.callcontrol.events.*; -import com.cisco.spark.android.core.ApiClientProvider; -import com.cisco.spark.android.core.ApplicationController; -import com.cisco.spark.android.core.Settings; -import com.cisco.spark.android.events.ApplicationControllerStateChangedEvent; -import com.cisco.spark.android.events.CallNotificationEvent; -import com.cisco.spark.android.events.CallNotificationType; -import com.cisco.spark.android.events.DeviceRegistrationChangedEvent; -import com.cisco.spark.android.events.RequestCallingPermissions; -import com.cisco.spark.android.locus.events.*; -import com.cisco.spark.android.locus.model.Locus; -import com.cisco.spark.android.locus.model.LocusData; -import com.cisco.spark.android.locus.model.LocusKey; -import com.cisco.spark.android.locus.model.LocusMeetingInfo; -import com.cisco.spark.android.locus.model.LocusParticipant; -import com.cisco.spark.android.locus.model.LocusParticipantDevice; -import com.cisco.spark.android.locus.model.LocusSelfRepresentation; -import com.cisco.spark.android.locus.responses.LocusUrlResponse; -import com.cisco.spark.android.media.MediaCapabilityConfig; -import com.cisco.spark.android.media.MediaEngine; -import com.cisco.spark.android.media.MediaSession; -import com.cisco.spark.android.media.events.MediaAvailabilityChangeEvent; -import com.cisco.spark.android.media.events.MediaBlockedChangeEvent; -import com.cisco.spark.android.meetings.GetMeetingInfoType; -import com.cisco.spark.android.meetings.LocusMeetingInfoProvider; -import com.cisco.spark.android.metrics.CallAnalyzerReporter; -import com.cisco.spark.android.sync.operationqueue.core.Operations; -import com.cisco.spark.android.sync.queue.ConversationSyncQueue; -import com.cisco.spark.android.util.Action; -import com.cisco.spark.android.wdm.DeviceRegistration; import com.cisco.wme.appshare.ScreenShareContext; import com.ciscowebex.androidsdk.CompletionHandler; -import com.ciscowebex.androidsdk.Result; -import com.ciscowebex.androidsdk.Webex; import com.ciscowebex.androidsdk.WebexError; import com.ciscowebex.androidsdk.auth.Authenticator; -import com.ciscowebex.androidsdk.internal.AcquirePermissionActivity; -import com.ciscowebex.androidsdk.internal.MetricsClient; -import com.ciscowebex.androidsdk.internal.ResultImpl; -import com.ciscowebex.androidsdk.people.Person; -import com.ciscowebex.androidsdk.people.internal.PersonClientImpl; -import com.ciscowebex.androidsdk.phone.AuxStream; -import com.ciscowebex.androidsdk.phone.Call; -import com.ciscowebex.androidsdk.phone.CallMembership; -import com.ciscowebex.androidsdk.phone.CallObserver; -import com.ciscowebex.androidsdk.phone.MediaOption; -import com.ciscowebex.androidsdk.phone.MultiStreamObserver; -import com.ciscowebex.androidsdk.phone.Phone; +import com.ciscowebex.androidsdk.internal.*; +import com.ciscowebex.androidsdk.internal.crypto.KeyManager; +import com.ciscowebex.androidsdk.internal.mercury.*; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.internal.media.MediaCapability; +import com.ciscowebex.androidsdk.internal.media.WMEngine; +import com.ciscowebex.androidsdk.internal.model.*; +import com.ciscowebex.androidsdk.internal.reachability.BackgroundChecker; +import com.ciscowebex.androidsdk.phone.*; import com.ciscowebex.androidsdk.utils.Utils; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; -import com.ciscowebex.androidsdk_commlib.SDKCommonInjector; import com.github.benoitdion.ln.Ln; -import me.helloworld.utils.Checker; - -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.NoSubscriberEvent; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; - -import retrofit2.Callback; -import retrofit2.Response; - -public class PhoneImpl implements Phone { - - @Inject - LocusMeetingInfoProvider _locusMeetingInfoProvider; +import java.util.*; - @Inject - ApplicationController _applicationController; +public class PhoneImpl implements Phone, UIEventHandler.EventObserver, MercuryService.MecuryListener, BackgroundChecker.BackgroundListener { - @Inject - ApiClientProvider _apiClientProvider; + enum State { + REGISTERING, REGISTERED, UNREGISTERING, UNREGISTERED + } - @Inject - CallControlService _callControlService; + private FacingMode facingMode = FacingMode.USER; - @Inject - Operations _operations; + private IncomingCallListener incomingCallListener; - @Inject - MediaEngine _mediaEngine; + private final Context context; - @Inject - EventBus _bus; + private final Authenticator authenticator; - @Inject - CallAnalyzerReporter _callAnalyzerReporter; + private Device device; - @Inject - volatile Settings settings; + private Credentials credentials; - private CallContext _callContext; + private MercuryService mercury; - private IncomingCallListener _incomingCallListener; + private final H264LicensePrompter prompter = new H264LicensePrompter(); - private Authenticator _authenticator; + private State state = State.UNREGISTERED; - private DeviceRegistration _device; + private MediaEngine engine; - private Handler _registerTimer; + private Map calls = new HashMap<>(); - public Handler getHandler() { - return _registerTimer; - } + private CallContext callContext; - private Runnable _registerTimeoutTask; + private int audioMaxBandwidth = Phone.DefaultBandwidth.MAX_BANDWIDTH_AUDIO.getValue(); - private CompletionHandler _registerCallback; + private int videoMaxBandwidth = Phone.DefaultBandwidth.MAX_BANDWIDTH_720P.getValue(); - private Map _calls = new HashMap<>(); + private int sharingMaxBandwidth = Phone.DefaultBandwidth.MAX_BANDWIDTH_SESSION.getValue(); - private Map _callTags = new HashMap<>(); + private String hardwareVideoSetting = null; - public CallImpl getCall(LocusKey key) { - return _calls.get(key); - } + private boolean hardwareCodecEnable = false; - private CompletionHandler _dialCallback; + private List audioEnhancementModels = null; - private MediaOption _dialOption; + private final CallService service; - private MediaSession _preview; + private final ReachabilityService reachability; - private H264LicensePrompter _prompter; + private final MetricsService metrics; - private MetricsClient _metrics; + private MediaSession previewSession; - private Context _context; + private List listeners = new ArrayList<>(); - private Intent _screenSharingIntent; + private BackgroundChecker checker; - private LocusKey _screenSharingKey; + public PhoneImpl(Context context, Authenticator authenticator, MediaEngine engine) { + this.context = context; + this.authenticator = authenticator; + this.engine = engine; + this.service = new CallService(authenticator); + this.reachability = new ReachabilityService(this); + this.metrics = new MetricsService(authenticator); + } - private LocusParticipant _lostSharingParticipant; + public void addActivityListener(ActivityListener listener) { + listeners.add(listener); + } - private Uri _currentSharingUri; + public Context getContext() { + return this.context; + } - private boolean _isRemoteSendingVideo; + public Device getDevice() { + return device; + } - public boolean getRemoteSendingVideo() { - return _isRemoteSendingVideo; + public Credentials getCredentials() { + return credentials; } - private boolean _isRemoteSendingAudio; + public Authenticator getAuthenticator() { + return authenticator; + } - private LocusKey _activeCallLocusKey; + public MediaEngine getEngine() { + return engine; + } - private int _availableMediaCount; + public void setChecker(BackgroundChecker checker) { + this.checker = checker; + } - private int audioMaxBandwidth = DefaultBandwidth.MAX_BANDWIDTH_AUDIO.getValue(); + @Override + public void register(@NonNull CompletionHandler callback) { + Queue.main.run(() -> { + if (state == State.REGISTERING) { + Ln.w("Already registering"); + callback.onComplete(ResultImpl.error("Already registering")); + return; + } + if (state == State.UNREGISTERING) { + Ln.w("Already unregistering"); + callback.onComplete(ResultImpl.error("Already unregistering")); + return; + } + state = State.REGISTERING; + Ln.i("Registering"); + UIEventHandler.get().registerUIEventHandler(context, this); + Queue.serial.run(new RegisterOperation(authenticator, result -> { + Pair data = result.getData(); + if (data == null) { + Ln.i("Register failed, " + result.getError()); + state = State.UNREGISTERED; + ResultImpl.errorInMain(callback, result); + Queue.serial.yield(); + } + else { + device = data.first; + credentials = data.second; + Ln.i("Registered %s with %s", device.getDeviceUrl(), credentials.getPerson()); + state = State.REGISTERED; + Settings.shared.store(Device.DEVICE_URL, device.getDeviceUrl()); + mercury = new MercuryService(authenticator, this); + mercury.connect(device.getWebSocketUrl(), error -> { + if (error != null) { + Ln.e("Register failed: " + error); + } + Queue.serial.underlying().run(() -> { + listActiveCalls(); + Queue.main.run(() -> { + reachability.fetch(); + if (checker != null) { + checker.start(); + } + callback.onComplete(error == null ? ResultImpl.success(null) : ResultImpl.error(error)); + }); + Queue.serial.yield(); + }); + }); + } + })); - private int videoMaxBandwidth = DefaultBandwidth.MAX_BANDWIDTH_720P.getValue(); + }); + } - private int sharingMaxBandwidth = DefaultBandwidth.MAX_BANDWIDTH_SESSION.getValue(); + @Override + public void onConnected(@Nullable WebexError error) { + Ln.d("Mercury connected %s", error); + } - private boolean isEnableHardwareAcceleration = true; + @Override + public void onDisconnected(@Nullable WebexError error) { + Ln.d("Mercury disconnected %s", error); + } - private String hardwareVideoSettings = null; + @Override + public void onEvent(@NonNull MercuryEvent event) { + if (event instanceof MercuryActivityEvent) { + ActivityModel model = ((MercuryActivityEvent) event).getActivity(); + if (model != null) { + for (ActivityListener listener : listeners) { + listener.processActivity(model); + } + } + } + else if (event instanceof MercuryLocusEvent) { + LocusModel model = ((MercuryLocusEvent) event).getLocus(); + if (model != null) { + doLocusEvent(model); + } + } + else if (event instanceof MercuryKmsMessageEvent) { + KmsMessageModel model = ((MercuryKmsMessageEvent) event).getEncryptionKmsMessage(); + if (model != null) { + KeyManager.shared.processKmsMessage(model); + } + } + } - private static final String STR_PERMISSION_DENIED = "permission deined"; - private static final String STR_OTHER_ACTIVE_CALLS = "There are other active calls"; - private static final String STR_UNSUPPORTED_FOR_OUTGOING_CALL = "Unsupport function for outgoing call"; - private static final String STR_ALREADY_CONNECTED = "Already connected"; - private static final String STR_ALREADY_DISCONNECTED = "Already disconnected"; - private static final String STR_FIND_CALLIMPL = "Find callImpl "; - private static final String STR_FAILURE_CALL = "Failure call: "; + @Override + public void onTransition(boolean foreground) { + Ln.d("Status transition: " + foreground); + Queue.serial.run(() -> { + if (mercury != null && calls.size() == 0) { + if (foreground) { + mercury.tryReconnect(); + } else { + mercury.disconnect(); + } + } + for (CallImpl call : calls.values()) { + MediaSession session = call.getMedia(); + if (session != null && session.isRunning()) { + if (foreground) { + session.prepareToLeaveVideoInterruption(); + } + else { + session.prepareToEnterVideoInterruption(); + } + } + } + Queue.serial.yield(); + }); + } - private static class DialTarget { - private String address; - private AddressType type; + @Override + public void deregister(@NonNull CompletionHandler callback) { + Queue.main.run(() -> { + if (state == State.REGISTERING) { + Ln.w("Already registering"); + callback.onComplete(ResultImpl.error("Already registering")); + return; + } + if (state == State.UNREGISTERING) { + Ln.w("Already unregistering"); + callback.onComplete(ResultImpl.error("Already unregistering")); + return; + } + state = State.UNREGISTERED; + Ln.i("Unregistering"); + UIEventHandler.get().unregisterUIEventHandler(context); + Queue.serial.run(new UnregisterOperation(authenticator, device, result -> { + Ln.i("Unregistered"); + mercury.disconnect(); + Queue.main.run(() -> { + reachability.clear(); + if (checker != null) { + checker.stop(); + } + }); + device = null; + credentials = null; + Settings.shared.clear(Device.DEVICE_URL); + state = State.UNREGISTERED; + callback.onComplete(result); + Queue.serial.yield(); + })); + }); + } - enum AddressType { - PEOPLE_ID, - PEOPLE_MAIL, - SPACE_ID, - SPACE_MAIL, - OTHER - } + @Override + public void onScreenRotation(int rotation) { + Ln.d("Screen rotation is changed to " + rotation); + engine.setDisplayRotation(rotation); + } - public boolean isEndpoint() { - switch (this.type) { - case OTHER: - case PEOPLE_ID: - case SPACE_MAIL: - case PEOPLE_MAIL: - return true; - case SPACE_ID: - return false; - default: - return true; + @Override + public void dial(@NonNull String dialString, @NonNull MediaOption option, @NonNull CompletionHandler callback) { + Ln.d("Dialing: " + dialString + ", " + option.hasVideo()); + Queue.serial.run(() -> { + stopPreview(); + if (callContext != null) { + Ln.w("Already calling"); + callback.onComplete(ResultImpl.error("Already calling")); + Queue.serial.yield(); + return; } - } - - public boolean isGroup() { - switch (this.type) { - case OTHER: - case PEOPLE_ID: - case PEOPLE_MAIL: - return false; - case SPACE_MAIL: - case SPACE_ID: - return true; - default: - return false; + if (device == null) { + Ln.e("Unregistered device"); + callback.onComplete(ResultImpl.error("Unregistered device")); + Queue.serial.yield(); + return; } - } + for (CallImpl call : getCalls()) { + if (!call.isGroup() || (call.isGroup() && call.getStatus() == Call.CallStatus.CONNECTED)) { + Ln.e("There are other active calls"); + callback.onComplete(ResultImpl.error("There are other active calls")); + Queue.serial.yield(); + return; + } + } + callContext = new CallContext.Outgoing(dialString, option, callback); + Queue.main.run(this::tryAcquirePermission); + Queue.serial.yield(); + }); + } - public DialTarget(@NonNull String address) { - this.address = address; - lookup(); - } + @Override + public void startPreview(View view) { + stopPreview(); + Queue.main.run(() -> { + engine.setDisplayRotation(Utils.getScreenRotation(context)); + previewSession = engine.createPreviveSession(createCapability(), view); + previewSession.startPreview(); + }); + } - private void lookup() { - String target = this.parseHydraId(this.address); - if (!Checker.isEmpty(target)) { - this.address = target; - } else if (this.address.toLowerCase().endsWith("@meet.ciscospark.com")) { - this.type = AddressType.SPACE_MAIL; - } else if (this.address.contains("@") && !this.address.contains(".")) { - this.type = AddressType.PEOPLE_MAIL; - } else { - this.type = AddressType.OTHER; + @Override + public void stopPreview() { + Queue.main.run(() -> { + if (previewSession != null) { + previewSession.stopPreview(); + previewSession = null; } - } + }); + } - private String parseHydraId(String id) { - try { - byte[] bytes = Base64.decode(id, Base64.URL_SAFE); - if (Checker.isEmpty(bytes)) { - return null; + @Override + public void onMediaPermission(boolean permission) { + Queue.serial.run(() -> { + String callId = UUID.randomUUID().toString(); + if (callContext instanceof CallContext.Outgoing) { + CallContext.Outgoing outgoing = (CallContext.Outgoing) callContext; + callContext = null; + if (!permission) { + Ln.w("permission deined"); + Queue.main.run(() -> outgoing.getCallback().onComplete(ResultImpl.error("permission deined"))); + Queue.serial.yield(); + return; } - String decode = new String(bytes, "UTF-8"); - Uri uri = Uri.parse(decode); - if (uri != null && uri.getScheme() != null && uri.getScheme().equalsIgnoreCase("ciscospark")) { - List paths = uri.getPathSegments(); - if (paths != null && paths.size() >= 2) { - String aType = paths.get(paths.size() - 2); - if (aType.equalsIgnoreCase("PEOPLE")) { - this.type = AddressType.PEOPLE_ID; - return paths.get(paths.size() - 1); - } else if (aType.equalsIgnoreCase("ROOM") || aType.equalsIgnoreCase("SPACE")) { - this.type = AddressType.SPACE_ID; - return paths.get(paths.size() - 1); - } + MediaSession session = engine.createSession(createCapability(), outgoing.getOption()); + String localSdp = session.getLocalSdp(); + MediaEngineReachabilityModel reachabilities = reachability.getFeedback(); + CallService.DialTarget.lookup(outgoing.getTarget(), authenticator, lookupResult -> { + CallService.DialTarget target = lookupResult.getData(); + if (target == null) { + Ln.e("Cannot find dial target. " + lookupResult.getError()); + Queue.main.run(() -> outgoing.getCallback().onComplete(ResultImpl.error(lookupResult.getError()))); + Queue.serial.yield(); + return; + } + if (target.isEndpoint()) { + service.call(target.getAddress(), callId, device, localSdp, outgoing.getOption().getLayout(), reachabilities, callResult -> { + if (callResult.getError() != null || callResult.getData() == null) { + Queue.main.run(() -> outgoing.getCallback().onComplete(ResultImpl.error(callResult.getError()))); + Queue.serial.yield(); + return; + } + doLocusResponse(new LocusResponse.Call(target.isGroup(), device, session, callResult.getData(), outgoing.getCallback()), Queue.serial); + }); + } + else { + service.getOrCreatePermanentLocus(target.getAddress(), device, convResult -> { + String url = convResult.getData(); + if (url == null) { + Queue.main.run(() -> outgoing.getCallback().onComplete(ResultImpl.error(convResult.getError()))); + Queue.serial.yield(); + return; + } + service.join(url, callId, device, localSdp, outgoing.getOption().getLayout(), reachabilities, joinResult -> { + if (joinResult.getError() != null || joinResult.getData() == null) { + Queue.main.run(() -> outgoing.getCallback().onComplete(ResultImpl.error(joinResult.getError()))); + Queue.serial.yield(); + return; + } + doLocusResponse(new LocusResponse.Call(target.isGroup(), device, session, joinResult.getData(), outgoing.getCallback()), Queue.serial); + }); + }); } + }); + } + else if (callContext instanceof CallContext.Incoming) { + CallContext.Incoming incoming = (CallContext.Incoming) callContext; + callContext = null; + if (!permission) { + Ln.w("permission deined"); + Queue.main.run(() -> incoming.getCallback().onComplete(ResultImpl.error("permission deined"))); + Queue.serial.yield(); + return; } - return null; - } catch (Exception t) { - return null; + MediaSession session = engine.createSession(createCapability(), incoming.getOption()); + incoming.getCall().setMedia(session); + String localSdp = session.getLocalSdp(); + service.join(incoming.getCall().getUrl(), callId, device, localSdp, incoming.getCall().isGroup() ? incoming.getOption().getLayout() : null, reachability.getFeedback(), joinResult -> { + if (joinResult.getError() != null || joinResult.getData() == null) { + Queue.main.run(() -> incoming.getCallback().onComplete(ResultImpl.error(joinResult.getError()))); + Queue.serial.yield(); + return; + } + doLocusResponse(new LocusResponse.Answer(incoming.getCall(), joinResult.getData(), incoming.getCallback()), Queue.serial); + }); } - - } - + else { + Ln.e("No call context: " + callContext); + Queue.serial.yield(); + } + }); } - public PhoneImpl(Context context, Authenticator authenticator, SDKCommonInjector injector) { - injector.inject(this); - _authenticator = authenticator; - _bus.register(this); - _registerTimer = new Handler(); - _context = context; - _prompter = new H264LicensePrompter(context.getSharedPreferences(Webex.class.getPackage().getName(), Context.MODE_PRIVATE)); + @Override + public void onScreenCapturePermission(Intent permission) { + Ln.d("StartSharing " + callContext); + Queue.serial.run(() -> { + if (callContext instanceof CallContext.Sharing) { + CallImpl call = ((CallContext.Sharing) callContext).getCall(); + CompletionHandler callback = ((CallContext.Sharing) callContext).getCallback(); + callContext = null; + if (call.getMedia() == null || !call.getMedia().hasSharing()) { + Ln.e("Media option unsupport content share"); + callback.onComplete(ResultImpl.error("Media option unsupport content share")); + Queue.serial.yield(); + return; + } + if (call.isSharingFromThisDevice()) { + Ln.e("Already shared by self"); + callback.onComplete(ResultImpl.error("Already shared by self")); + Queue.serial.yield(); + return; + } + if (call.getStatus() != Call.CallStatus.CONNECTED) { + Ln.e("No active call"); + callback.onComplete(ResultImpl.error("No active call")); + Queue.serial.yield(); + return; + } + FloorModel floor = new FloorModel(call.getModel().getSelf(), call.getModel().getSelf(), FloorModel.Disposition.GRANTED); + MediaShareModel mediaShare = new MediaShareModel(MediaShareModel.SHARE_CONTENT_TYPE, call.getModel().getMediaShareUrl(), floor); + String url = mediaShare.getUrl(); + if (url == null) { + Ln.e("Unsupport media share"); + Queue.serial.yield(); + return; + } + service.update(mediaShare, url, device, result -> { + if (result.getError() != null) { + callback.onComplete(ResultImpl.error(result.getError())); + Queue.serial.yield(); + return; + } + doLocusResponse(new LocusResponse.MediaShare(call, FloorModel.Disposition.GRANTED, permission, callback), Queue.serial); + }); + } + else { + Queue.serial.yield(); + } + }); + } + @Override public IncomingCallListener getIncomingCallListener() { - return _incomingCallListener; + return incomingCallListener; } + @Override public void setIncomingCallListener(IncomingCallListener listener) { - _incomingCallListener = listener; - } - - public void close() { - if (_bus.isRegistered(this)) { - _bus.unregister(this); - } + this.incomingCallListener = listener; } + @Override public FacingMode getDefaultFacingMode() { - return toFacingMode(_callControlService.getDefaultCamera()); + return facingMode; } + @Override public void setDefaultFacingMode(FacingMode mode) { - _callControlService.setDefaultCamera(fromFacingMode(mode)); + facingMode = mode; } + @Override public void requestVideoCodecActivation(@NonNull AlertDialog.Builder builder, @NonNull CompletionHandler callback) { - _prompter.check(builder, result -> callback.onComplete(ResultImpl.success(result))); + prompter.check(builder, result -> callback.onComplete(ResultImpl.success(result))); + } + + @Override + public void disableVideoCodecActivation() { + prompter.setVideoLicenseActivationDisabled(true); } + @Override public String getVideoCodecLicense() { - return _prompter.getLicense(); + return prompter.getLicense(); } + @Override public String getVideoCodecLicenseURL() { - return _prompter.getLicenseURL(); + return prompter.getLicenseURL(); } @Override public void setAudioMaxBandwidth(int bandwidth) { - audioMaxBandwidth = bandwidth <= 0 ? DefaultBandwidth.MAX_BANDWIDTH_AUDIO.getValue() : bandwidth; + audioMaxBandwidth = bandwidth; } @Override @@ -355,7 +528,7 @@ public int getAudioMaxBandwidth() { @Override public void setVideoMaxBandwidth(int bandwidth) { - videoMaxBandwidth = bandwidth <= 0 ? DefaultBandwidth.MAX_BANDWIDTH_720P.getValue() : bandwidth; + videoMaxBandwidth = bandwidth; } @Override @@ -365,7 +538,7 @@ public int getVideoMaxBandwidth() { @Override public void setSharingMaxBandwidth(int bandwidth) { - sharingMaxBandwidth = bandwidth <= 0 ? DefaultBandwidth.MAX_BANDWIDTH_SESSION.getValue() : bandwidth; + sharingMaxBandwidth = bandwidth; } @Override @@ -375,1497 +548,506 @@ public int getSharingMaxBandwidth() { @Override public boolean isHardwareAccelerationEnabled() { - return isEnableHardwareAcceleration; + return hardwareCodecEnable; } @Override public void setHardwareAccelerationEnabled(boolean enable) { - isEnableHardwareAcceleration = enable; + hardwareCodecEnable = true; } public String getHardwareVideoSettings() { - return hardwareVideoSettings; + return hardwareVideoSetting; } public void setHardwareVideoSettings(String settings) { - hardwareVideoSettings = settings; + hardwareVideoSetting = settings; } @Override public void enableAudioEnhancementForModels(List models) { - if (_callControlService != null) { - _callControlService.setAudioEnhancementModels(models); - } - } - - public void disableVideoCodecActivation() { - _prompter.setVideoLicenseActivationDisabled(true); + audioEnhancementModels = models; } - public void register(@NonNull CompletionHandler callback) { - Ln.i("Registering"); - if (_registerCallback != null) { - Ln.w("Already registering"); - callback.onComplete(ResultImpl.error("Already registering")); - return; - } - _registerCallback = callback; - RotationHandler.registerRotationReceiver(_context, this); - - ServiceBuilder.async(_authenticator, callback, true, s -> { - if (s == null) { - RotationHandler.unregisterRotationReceiver(_context); - _registerCallback = null; - } else { - _registerTimeoutTask = () -> { - Ln.i("Register timeout"); - if (_device == null && _registerCallback != null) { - _registerCallback.onComplete(ResultImpl.error("Register timeout")); - } - }; - _registerTimer.postDelayed(_registerTimeoutTask, 60L * 1000); - new AuthenticatedUserTask(_applicationController).execute(); + void acknowledge(CallImpl call, CompletionHandler callback) { + Queue.serial.run(() -> { + for (CallImpl already : getCalls()) { + if (!call.getUrl().equals(already.getUrl())) { + Ln.e("There are other active calls"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("There are other active calls"))); + Queue.serial.yield(); + return; + } } - return null; - }, null); - } - - public void deregister(@NonNull CompletionHandler callback) { - Ln.i("Deregistering"); - resetDialStatus(null); - RotationHandler.unregisterRotationReceiver(_context); - _applicationController.logout(null, false, false, false); - _mediaEngine.uninitialize(); - _device = null; - _registerCallback = null; - _registerTimer.removeCallbacks(_registerTimeoutTask); - callback.onComplete(ResultImpl.success(null)); - Ln.i("Deregistered"); - } - - public void startPreview(View view) { - stopPreview(); - _preview = _mediaEngine.createMediaSession(UUID.randomUUID().toString()); - if (!_preview.getSelectedCamera().equals(_callControlService.getDefaultCamera())) { - _preview.switchCamera(); - } - _preview.setPreviewWindow(view); - _preview.startSelfView(); - setDisplayRotation(RotationHandler.getRotation(_context)); - } - - public void stopPreview() { - if (_preview != null) { - _preview.endSession(); - _preview = null; - } - } - - public void setDisplayRotation(int rotation) { - if (_preview != null) { - _preview.setDisplayRotation(rotation); - } - for (CallImpl call : _calls.values()) { - if (call.getStatus() == Call.CallStatus.CONNECTED) { - _callControlService.setDisplayRotation(call.getKey(), rotation); + if (call.getDirection() == Call.Direction.OUTGOING) { + Ln.e("Unsupport function for outgoing call"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Unsupport function for outgoing call"))); + Queue.serial.yield(); return; } - } + if (call.getDirection() == Call.Direction.INCOMING && call.getStatus() != Call.CallStatus.INITIATED) { + Ln.e("Not initialted call"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Not initialted call"))); + Queue.serial.yield(); + return; + } + String url = call.getUrl(); + if (url == null) { + Ln.e("Missing call URL"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Missing call URL"))); + Queue.serial.yield(); + return; + } + service.alert(url, device, result -> { + if (result.getError() != null) { + Queue.main.run(() -> callback.onComplete(ResultImpl.error(result.getError()))); + Queue.serial.yield(); + return; + } + doLocusResponse(new LocusResponse.Ack(call, callback), Queue.serial); + }); + }); } - void makeCall(Bundle data, boolean permission) { - if (data == null) { - Ln.e("makeCall data is null!"); - return; - } - String tag = data.getString(AcquirePermissionActivity.CALL_TAG); - if (tag == null) { - Ln.w("Duplicated call, ignore it"); - return; - } - if (!_callTags.containsKey(tag)) { - Ln.w("Not found call tag, ignore it"); - return; - } - int direction = data.getInt(AcquirePermissionActivity.CALL_DIRECTION); - if (direction == Call.Direction.INCOMING.ordinal()) { - Ln.d("make incoming call"); - LocusKey key = data.getParcelable(AcquirePermissionActivity.CALL_KEY); - CallImpl call = _calls.get(key); - if (call != null) { - Result result = null; - if (permission) { - CallContext.Builder builder = new CallContext.Builder(call.getKey()).setIsAnsweringCall(true).setIsOneOnOne(!call.isGroup()); - builder = builder.setMediaDirection(mediaOptionToMediaDirection(call.getOption())); - if (!doDial(builder.build())) { - result = ResultImpl.error(STR_FAILURE_CALL + "cannot dial"); - } - } else { - Ln.w(STR_PERMISSION_DENIED); - result = ResultImpl.error(STR_PERMISSION_DENIED); - } - CompletionHandler handler = call.getAnswerCallback(); - if (handler != null && result != null) { - handler.onComplete(result); + void answer(CallImpl call, MediaOption option, CompletionHandler callback) { + Queue.serial.run(() -> { + for (CallImpl already : getCalls()) { + if (already.getUrl().equals(call.getUrl()) && already.getStatus() == Call.CallStatus.CONNECTED) { + Ln.e("There are other active calls"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("There are other active calls"))); + Queue.serial.yield(); + return; } - } else { - Ln.d("Cannot find call for key: " + key); } - } else if (direction == Call.Direction.OUTGOING.ordinal()) { - Ln.d("make outgoing call"); - String dialString = data.getString(AcquirePermissionActivity.CALL_STRING); - if (permission && dialString != null) { - DialTarget target = new DialTarget(dialString); - if (target.type == DialTarget.AddressType.PEOPLE_MAIL) { - new PersonClientImpl(_authenticator).list(dialString, null, 1, result -> { - List persons = result.getData(); - if (!Checker.isEmpty(persons)) { - Person person = persons.get(0); - Ln.d("Lookup target: " + person.getId()); - doDial(new DialTarget(person.getId()).address, _dialOption); - } else { - doDial(target.address, _dialOption); - } - }); - } else if (target.isEndpoint()) { - doDial(target.address, _dialOption); - } else { - doDialSpaceID(target.address, _dialOption); + if (call.getDirection() == Call.Direction.OUTGOING) { + Ln.e("Unsupport function for outgoing call"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Unsupport function for outgoing call"))); + Queue.serial.yield(); + return; + } + if (call.getDirection() == Call.Direction.INCOMING) { + if (call.getStatus() == Call.CallStatus.CONNECTED) { + Ln.e("Already connected"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Already connected"))); + Queue.serial.yield(); + return; + } + else if (call.getStatus() == Call.CallStatus.DISCONNECTED) { + Ln.e("Already disconnected"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Already disconnected"))); + Queue.serial.yield(); + return; } - } else { - Ln.w(STR_PERMISSION_DENIED); - resetDialStatus(ResultImpl.error(STR_PERMISSION_DENIED)); } - } - _callTags.remove(tag); + callContext = new CallContext.Incoming(call, option, callback); + Queue.main.run(this::tryAcquirePermission); + Queue.serial.yield(); + }); } - public void dial(@NonNull String dialString, @NonNull MediaOption option, @NonNull CompletionHandler callback) { - Ln.i("Dialing: " + dialString + ", " + option.hasVideo()); - if (_device == null) { - Ln.e("Unregistered device"); - callback.onComplete(ResultImpl.error("Unregistered device")); - return; - } - if (_dialCallback != null) { - Ln.w("Already calling"); - callback.onComplete(ResultImpl.error("Already calling")); - return; - } - for (CallImpl call : _calls.values()) { - if (!call.isGroup() || (call.isGroup() && call.getStatus() == Call.CallStatus.CONNECTED)) { - Ln.e(STR_OTHER_ACTIVE_CALLS); - callback.onComplete(ResultImpl.error(STR_OTHER_ACTIVE_CALLS)); + void reject(CallImpl call, CompletionHandler callback) { + Queue.serial.run(() -> { + if (call.getDirection() == Call.Direction.OUTGOING) { + Ln.e("Unsupport function for outgoing call"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Unsupport function for outgoing call"))); + Queue.serial.yield(); return; } - } - stopPreview(); - _dialOption = option; - _dialCallback = callback; - tryAcquirePermission(Call.Direction.OUTGOING, dialString); - } - - void answer(@NonNull CallImpl call) { - Ln.i("Answer " + call); - for (CallImpl exist : _calls.values()) { - Ln.d("answer exist.getStatus(): " + exist.getStatus()); - if (!exist.getKey().equals(call.getKey()) && exist.getStatus() == Call.CallStatus.CONNECTED) { - Ln.e(STR_OTHER_ACTIVE_CALLS); - if (call.getAnswerCallback() != null) { - call.getAnswerCallback().onComplete(ResultImpl.error(STR_OTHER_ACTIVE_CALLS)); + if (call.getDirection() == Call.Direction.INCOMING) { + if (call.getStatus() == Call.CallStatus.CONNECTED) { + Ln.e("Already connected"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Already connected"))); + Queue.serial.yield(); + return; + } + else if (call.getStatus() == Call.CallStatus.DISCONNECTED) { + Ln.e("Already disconnected"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Already disconnected"))); + Queue.serial.yield(); + return; } - return; } - } - if (call.getDirection() == Call.Direction.OUTGOING) { - Ln.e(STR_UNSUPPORTED_FOR_OUTGOING_CALL); - if (call.getAnswerCallback() != null) { - call.getAnswerCallback().onComplete(ResultImpl.error(STR_UNSUPPORTED_FOR_OUTGOING_CALL)); + String url = call.getUrl(); + if (url == null) { + Ln.e("Missing call URL"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Missing call URL"))); + Queue.serial.yield(); + return; } - return; - } - if (call.getDirection() == Call.Direction.INCOMING) { - if (call.getStatus() == Call.CallStatus.CONNECTED) { - Ln.e(STR_ALREADY_CONNECTED); - if (call.getAnswerCallback() != null) { - call.getAnswerCallback().onComplete(ResultImpl.error(STR_ALREADY_CONNECTED)); + service.decline(url, device, result -> { + if (result.getError() != null) { + Queue.main.run(() -> callback.onComplete(ResultImpl.error(result.getError()))); + Queue.serial.yield(); + return; } + doLocusResponse(new LocusResponse.Reject(call, callback), Queue.serial); + }); + }); + } + + void hangup(CallImpl call, CompletionHandler callback) { + Queue.serial.run(() -> { + if (call.getStatus() == Call.CallStatus.DISCONNECTED) { + Ln.e("Already disconnected"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Already disconnected"))); + Queue.serial.yield(); return; - } else if (call.getStatus() == Call.CallStatus.DISCONNECTED) { - Ln.e(STR_ALREADY_DISCONNECTED); - if (call.getAnswerCallback() != null) { - call.getAnswerCallback().onComplete(ResultImpl.error(STR_ALREADY_DISCONNECTED)); - } + } + String url = call.getModel().getSelf().getUrl(); + if (url == null) { + Ln.e("Missing self participant URL"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Missing self participant URL"))); + Queue.serial.yield(); return; } - } - stopPreview(); - tryAcquirePermission(Call.Direction.INCOMING, call.getKey()); - } + Queue.main.run(() -> { + if (call.isSendingSharing()) { + stopSharing(call, result -> Ln.d("Stop sharing when call is endded.")); + call.getMedia().leaveSharing(true); + } + service.leave(url, device, result -> { + if (result.getError() != null) { + Queue.main.run(() -> callback.onComplete(ResultImpl.error(result.getError()))); + Queue.serial.yield(); + return; + } + doLocusResponse(new LocusResponse.Leave(call, result.getData(), callback), Queue.serial); + }); + }); - private void tryAcquirePermission(Call.Direction direction, Object callParam) { - String tag = UUID.randomUUID().toString(); - _callTags.put(tag, tag); - - Bundle bundle = new Bundle(); - bundle.putString(AcquirePermissionActivity.CALL_TAG, tag); - bundle.putInt(AcquirePermissionActivity.CALL_DIRECTION, direction.ordinal()); - if (callParam instanceof Parcelable) { - bundle.putParcelable(AcquirePermissionActivity.CALL_KEY, (Parcelable) callParam); - } else if (callParam instanceof String) { - bundle.putString(AcquirePermissionActivity.CALL_STRING, (String) callParam); - } - final Intent intent = new Intent(_context, AcquirePermissionActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(AcquirePermissionActivity.PERMISSION_TYPE, AcquirePermissionActivity.PERMISSION_CAMERA_MIC); - intent.putExtra(AcquirePermissionActivity.CALL_DATA, bundle); - _context.startActivity(intent); + }); } - void reject(@NonNull CallImpl call) { - Ln.i("Reject " + call); - if (call.getDirection() == Call.Direction.OUTGOING) { - Ln.e(STR_UNSUPPORTED_FOR_OUTGOING_CALL); - if (call.getRejectCallback() != null) { - call.getRejectCallback().onComplete(ResultImpl.error(STR_UNSUPPORTED_FOR_OUTGOING_CALL)); + void update(CallImpl call, boolean audio, boolean video, String localSdp, CompletionHandler callback) { + Queue.serial.run(() -> { + String url = call.getModel().getSelf().getMediaBaseUrl(); + String sdp = call.getModel().getLocalSdp(); + if (sdp == null) { + sdp = localSdp; } - return; - } - if (call.getDirection() == Call.Direction.INCOMING) { - if (call.getStatus() == Call.CallStatus.CONNECTED) { - Ln.e(STR_ALREADY_CONNECTED); - if (call.getRejectCallback() != null) { - call.getRejectCallback().onComplete(ResultImpl.error(STR_ALREADY_CONNECTED)); - } - return; - } else if (call.getStatus() == Call.CallStatus.DISCONNECTED) { - Ln.e(STR_ALREADY_DISCONNECTED); - if (call.getRejectCallback() != null) { - call.getRejectCallback().onComplete(ResultImpl.error(STR_ALREADY_DISCONNECTED)); - } + String mediaId = call.getModel().getMediaId(device.getDeviceUrl()); + if (url == null || sdp == null || mediaId == null) { + Ln.e("Missing media data"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Missing media data"))); + Queue.serial.yield(); return; } - } - _callControlService.declineCall(call.getKey()); + MediaInfoModel media = new MediaInfoModel(localSdp == null ? sdp : localSdp, !audio, !video, reachability.getFeedback().reachability); + service.update(url, mediaId, device, media, result -> { + if (result.getError() != null && result.getData() == null) { + Queue.main.run(() -> callback.onComplete(ResultImpl.error(result.getError()))); + Queue.serial.yield(); + return; + } + doLocusResponse(new LocusResponse.Update(call, result.getData(), callback), Queue.serial); + }); + }); } - void hangup(@NonNull CallImpl call) { - Ln.i("Hangup " + call); - resetDialStatus(null); - if (call.getStatus() == Call.CallStatus.DISCONNECTED) { - Ln.e(STR_ALREADY_DISCONNECTED); - if (call.getHangupCallback() != null) { - call.getHangupCallback().onComplete(ResultImpl.error(STR_ALREADY_DISCONNECTED)); + void fetch(CallImpl call, boolean full) { + Queue.serial.run(() -> { + String sync = null; + LocusSequenceModel sequence = call.getModel().getSequence(); + if (!full && (sequence == null || sequence.isEmpty())) { + sync = call.getModel().getSyncUrl(); + Ln.d("Requesting delta sync for locus: " + sync); } - return; - } - if (call.getStatus() == Call.CallStatus.INITIATED || call.getStatus() == Call.CallStatus.RINGING) { - _callControlService.cancelCall(call.getKey(), CallControlService.CancelReason.LOCAL_CANCELLED); - } else { - _callControlService.leaveCall(call.getKey()); - } + if (sync == null) { + sync = call.getUrl(); + Ln.d("Requesting full sync for locus: " + sync); + } + service.get(sync, result -> { + if (result.getError() != null) { + Queue.serial.yield(); + return; + } + doLocusResponse(new LocusResponse.Update(call, result.getData(), null), Queue.serial); + }); + }); } - void sendFeedback(Map feedback) { - if (_metrics != null) { - feedback.put("key", "meetup_call_user_rating"); - feedback.put("time", Utils.timestampUTC()); - feedback.put("type", "GENERIC"); - List> list = new ArrayList<>(); - list.add(feedback); - _metrics.post(list); - } + void dtmf(CallImpl call, String tones, int correlationId, CompletionHandler callback) { + Queue.serial.run(() -> { + if (call.isSendingDTMFEnabled() && call.getModel().getSelf() != null) { + String url = call.getModel().getSelf().getUrl(); + service.dtmf(url, device, correlationId, tones, null, null, result -> { + Queue.main.run(() -> callback.onComplete(result)); + Queue.serial.yield(); + }); + } + else { + Queue.main.run(() -> callback.onComplete(ResultImpl.error("unsupported DTMF"))); + Queue.serial.yield(); + } + }); + } - CallControlService getCallService() { - return _callControlService; + void admit(CallImpl call, List memberships, CompletionHandler callback) { + Queue.serial.run(() -> { + String url = call.getUrl(); + if (url == null) { + Ln.e("Missing call URL"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Missing call URL"))); + Queue.serial.yield(); + return; + } + service.admit(url, memberships, result -> { + if (result.getError() != null) { + Queue.main.run(() -> callback.onComplete(ResultImpl.error(result.getError()))); + Queue.serial.yield(); + return; + } + doLocusResponse(new LocusResponse.Update(call, result.getData(), callback), Queue.serial); + }); + }); } - Operations getOperations() { - return _operations; + void feedback(Map feedback) { + feedback.put("key", "meetup_call_user_rating"); + feedback.put("time", String.valueOf(System.currentTimeMillis())); + feedback.put("type", "GENERIC"); + List> list = new ArrayList<>(); + list.add(feedback); + metrics.post(list); } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(DeviceRegistrationChangedEvent event) { - Ln.i("DeviceRegistrationChangedEvent is received "); - _device = settings.getDeviceRegistration(); - Uri uri = _device.getMetricsServiceUrl(); - if (uri != null) { - String url = uri.toString(); - if (!url.endsWith("/")) { - url = url + "/"; - } - _metrics = new MetricsClient(_authenticator, url); - } - if (_registerCallback == null) { - Ln.w("Register callback is null "); + void keepAlive(CallImpl call) { + String url = call.getModel().getKeepAliveUrl(device.getDeviceUrl()); + if (url == null) { + Ln.e("Missing keepAlive URL"); return; } - _registerCallback.onComplete(ResultImpl.success(null)); - _registerCallback = null; - _registerTimer.removeCallbacks(_registerTimeoutTask); - Ln.i("Registered: " + _device.getId()); + service.keepalive(url, result -> {}); } - // Locus has create call,waiting remote to accept - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlLocusCreatedEvent event) { - Ln.i("CallControlLocusCreatedEvent is received " + event.getLocusKey()); - LocusKey key = event.getLocusKey(); - CallImpl call = _calls.get(key); - if (call == null) { - com.cisco.spark.android.callcontrol.model.Call locus = _callControlService.getCall(key); - if (locus == null) { - Ln.e("Internal callImpl isn't exist " + event.getLocusKey()); - resetDialStatus(ResultImpl.error("Internal callImpl isn't exist")); - } else { - call = new CallImpl(this, _dialOption, CallImpl.Direction.OUTGOING, key, locus.getLocusData().isMeeting()); - Ln.d("Call is created: " + call); - } - } else { - Ln.d("Call already exist " + call + ", " + call.getStatus()); - } - if (call != null && !call.getStatus().equals(Call.CallStatus.CONNECTED)) { - if (!_bus.isRegistered(call)) { - _bus.register(call); + void startSharing(CallImpl call, CompletionHandler callback) { + callContext = new CallContext.Sharing(call, callback); + final Intent intent = new Intent(context, AcquirePermissionActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(AcquirePermissionActivity.PERMISSION_TYPE, AcquirePermissionActivity.PERMISSION_SCREEN_SHOT); + context.startActivity(intent); + } + + void stopSharing(CallImpl call, CompletionHandler callback) { + Ln.d("StopSharing " + call.getUrl()); + Queue.serial.run(() -> { + if (call.getMedia() == null || !call.getMedia().hasSharing()) { + Ln.e("Media option unsupport content share"); + callback.onComplete(ResultImpl.error("Media option unsupport content share")); + Queue.serial.yield(); + return; } - _calls.put(key, call); - if (_dialCallback != null) { - _dialCallback.onComplete(ResultImpl.success(call)); - _dialCallback = null; + if (!call.isSharingFromThisDevice()) { + Ln.e("Local share screen not start"); + callback.onComplete(ResultImpl.error("Local share screen not start")); + Queue.serial.yield(); + return; } - if (call.isGroup()) { - setCallOnRinging(call); - setCallOnConnected(call, event.getLocusKey()); + FloorModel floor = new FloorModel(call.getModel().getSelf(), call.getModel().getSelf(), FloorModel.Disposition.RELEASED); + MediaShareModel mediaShare = new MediaShareModel(MediaShareModel.SHARE_CONTENT_TYPE, call.getModel().getMediaShareUrl(), floor); + String url = mediaShare.getUrl(); + if (url == null) { + Ln.e("Unsupport media share"); + Queue.serial.yield(); + return; } - } + service.update(mediaShare, url, device, result -> { + if (result.getError() != null) { + Queue.main.run(() -> callback.onComplete(ResultImpl.error(result.getError()))); + Queue.serial.yield(); + return; + } + doLocusResponse(new LocusResponse.MediaShare(call, FloorModel.Disposition.RELEASED, null, callback), Queue.serial); + }); + }); } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlJoinedLobbyEvent event) { - Ln.i("CallControlJoinedLobbyEvent is received " + event.getLocusKey()); - updateCallLobbyStatus(event.getLocusKey(), true); - LocusKey key = event.getLocusKey(); - CallImpl call = _calls.get(key); - if (call == null) { - com.cisco.spark.android.callcontrol.model.Call locus = _callControlService.getCall(event.getLocusKey()); - if (locus == null) { - Ln.e("Internal callImpl isn't exist " + event.getLocusKey()); - resetDialStatus(ResultImpl.error("Internal callImpl isn't exist")); - } else { - call = new CallImpl(this, _dialOption, CallImpl.Direction.OUTGOING, key, locus.getLocusData().isMeeting()); - Ln.d("Call is created: " + call); - _bus.register(call); - _calls.put(call.getKey(), call); - if (_dialCallback != null) { - _dialCallback.onComplete(ResultImpl.success(call)); - _dialCallback = null; - } - } - } else { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - } - if (call != null && call.isGroup() && call.getDirection() == Call.Direction.OUTGOING) { - setCallOnWaiting(call, event.isActive() ? Call.WaitReason.WAITING_FOR_ADMITTING : Call.WaitReason.MEETING_NOT_START); - } + Collection getCalls() { + return Collections.unmodifiableCollection(calls.values()); } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlJoinedMeetingFromLobbyEvent event) { - Ln.i("CallControlJoinedMeetingFromLobbyEvent is received " + event.getLocusKey()); - updateCallLobbyStatus(event.getLocusKey(), false); - CallImpl call = _calls.get(event.getLocusKey()); - if (call == null) { - //group call self join. - com.cisco.spark.android.callcontrol.model.Call locus = _callControlService.getCall(event.getLocusKey()); - if (locus == null) { - Ln.e("Internal callImpl isn't exist " + event.getLocusKey()); - resetDialStatus(ResultImpl.error("Internal callImpl isn't exist")); - } else { - call = new CallImpl(this, _dialOption, CallImpl.Direction.OUTGOING, event.getLocusKey(), locus.getLocusData().isMeeting()); - _bus.register(call); - _calls.put(call.getKey(), call); - if (_dialCallback != null) { - _dialCallback.onComplete(ResultImpl.success(call)); - _dialCallback = null; - } - setCallOnConnected(call, event.getLocusKey()); + private void tryAcquirePermission() { + final Intent intent = new Intent(context, AcquirePermissionActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(AcquirePermissionActivity.PERMISSION_TYPE, AcquirePermissionActivity.PERMISSION_CAMERA_MIC); + context.startActivity(intent); + } + + private void doLocusResponse(LocusResponse response, Queue queue) { + Ln.d("doLocusResponse: " + response); + if (response instanceof LocusResponse.Call) { + LocusModel model = ((LocusResponse.Call) response).getLocus(); + Ln.d("Connecting call: " + model.getCallUrl()); + CallImpl call = new CallImpl(model, this, device, ((LocusResponse.Call) response).getSession(), Call.Direction.OUTGOING, ((LocusResponse.Call) response).isGroup()); + if (call.isStatusIllegal()) { + Ln.d("The previous session did not end"); + Queue.main.run(() -> { + WebexError error = new WebexError(WebexError.ErrorCode.UNEXPECTED_ERROR, "The previous session did not end"); + ((LocusResponse.Call) response).getCallback().onComplete(ResultImpl.error(error)); + call.end(new CallObserver.CallErrorEvent(call, error)); + queue.yield(); + }); + return; } - } else { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - if (call.getStatus() != Call.CallStatus.CONNECTED) { - if (call.getAnswerCallback() != null) { - call.getAnswerCallback().onComplete(ResultImpl.success(null)); + addCall(call); + Queue.main.run(() -> { + if (call.getModel().isSelfInLobby()) { + call.startKeepAlive(); } - if (_dialCallback != null) { - _dialCallback.onComplete(ResultImpl.success(call)); - _dialCallback = null; + else { + call.startMedia(); } - if (call.getOption() == null && _dialOption != null) { - call.setMediaOption(_dialOption); + ((LocusResponse.Call) response).getCallback().onComplete(ResultImpl.success(call)); + queue.yield(); + }); + } + else if (response instanceof LocusResponse.Answer) { + LocusResponse.Answer res = (LocusResponse.Answer) response; + res.getCall().update(res.getResult()); + if (res.getCallback() != null) { + Queue.main.run(() -> res.getCallback().onComplete(ResultImpl.success(null))); + } + queue.yield(); + } + else if (response instanceof LocusResponse.Leave) { + LocusResponse.Leave res = (LocusResponse.Leave) response; + LocusModel model = res.getResult(); + if (model != null) { + res.getCall().update(model); + } + if (res.getCallback() != null) { + Queue.main.run(() -> res.getCallback().onComplete(ResultImpl.success(null))); + } + queue.yield(); + } + else if (response instanceof LocusResponse.Reject) { + LocusResponse.Reject res = (LocusResponse.Reject) response; + res.getCall().end(new CallObserver.LocalDecline(res.getCall())); + if (res.getCallback() != null) { + Queue.main.run(() -> res.getCallback().onComplete(ResultImpl.success(null))); + } + queue.yield(); + } + else if (response instanceof LocusResponse.Ack) { + LocusResponse.Ack res = (LocusResponse.Ack) response; + res.getCall().setStatus(Call.CallStatus.RINGING); + Queue.main.run(() -> { + CallObserver observer = res.getCall().getObserver(); + if (observer != null) { + res.getCall().getObserver().onRinging(res.getCall()); } - setCallOnConnected(call, event.getLocusKey()); - } - resetDialStatus(null); - } - } - - // Remoted send acknowledge and it means it is RINGING - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(ParticipantNotifiedEvent event) { - Ln.i("ParticipantNotifiedEvent is received " + event.getLocusKey()); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - if (call.isGroup()) { - if (call.getDirection() == Call.Direction.INCOMING) { - setCallOnRinging(call); - } - } else { - if (call.getDirection() == Call.Direction.INCOMING) { - for (LocusParticipant participant : call.getRemoteParticipants()) { - Ln.d("participant State: " + participant.getState()); - if (participant.getState() == LocusParticipant.State.JOINED) { - setCallOnRinging(call); - break; - } - } - } else { - setCallOnRinging(call); + if (res.getCallback() != null) { + res.getCallback().onComplete(ResultImpl.success(null)); } - } - } - } - - // Remote accept call, call will be setup - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlParticipantJoinedEvent event) { - Ln.i("CallControlParticipantJoinedEvent is received " + event.getLocusKey()); - CallImpl call = _calls.get(event.getLocusKey()); - if (call == null) { - //group call self join. - com.cisco.spark.android.callcontrol.model.Call locus = _callControlService.getCall(event.getLocusKey()); - for (LocusParticipant locusParticipant : event.getJoinedParticipants()) { - if (locus != null - && locusParticipant.getDeviceUrl().equals(_device.getUrl()) - && locus.getLocusData().isMeeting()) { - call = new CallImpl(this, _dialOption, CallImpl.Direction.OUTGOING, event.getLocusKey(), locus.getLocusData().isMeeting()); - _bus.register(call); - _calls.put(call.getKey(), call); - if (_dialCallback != null) { - _dialCallback.onComplete(ResultImpl.success(call)); - _dialCallback = null; - } - if (!locusParticipant.isInLobby()) { - setCallOnRinging(call); - setCallOnConnected(call, event.getLocusKey()); - } - } - } - } else { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - if (!call.isGroup()) { - resetDialStatus(null); - if (call.getAnswerCallback() != null && (call.getStatus() == Call.CallStatus.INITIATED || call.getStatus() == Call.CallStatus.RINGING)) { - call.getAnswerCallback().onComplete(ResultImpl.success(null)); - } - setCallOnConnected(call, event.getLocusKey()); - } else if (call.getStatus() != Call.CallStatus.CONNECTED) { - for (LocusParticipant locusParticipant : event.getJoinedParticipants()) { - if (locusParticipant != null && locusParticipant.getDeviceUrl() != null && locusParticipant.getDeviceUrl().equals(_device.getUrl())) { - if (_dialCallback != null) { - _dialCallback.onComplete(ResultImpl.success(call)); - _dialCallback = null; - } - if (!locusParticipant.isInLobby()) { - if (call.getAnswerCallback() != null) { - call.getAnswerCallback().onComplete(ResultImpl.success(null)); - } - setCallOnRinging(call); - if (call.getOption() == null && _dialOption != null) { - call.setMediaOption(_dialOption); - } - setCallOnConnected(call, event.getLocusKey()); - } - } - } - resetDialStatus(null); - } else { - resetDialStatus(null); - } - } - //call membership changed - List events = new ArrayList<>(); - for (LocusParticipant locusParticipant : event.getJoinedParticipants()) { - if (locusParticipant != null && locusParticipant.getDeviceUrl() != null && !locusParticipant.getDeviceUrl().equals(_device.getUrl())) { - events.add(new CallObserver.MembershipJoinedEvent(call, new CallMembershipImpl(locusParticipant, call))); - } - } - doCallMembershipChanged(call, events); - doParticipantCountChanged(call); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlParticipantJoinedLobbyEvent event) { - Ln.i("CallControlParticipantJoinedLobbyEvent is received " + event.getLocusKey()); - CallImpl call = _calls.get(event.getLocusKey()); - if (call == null) { - return; - } - //call membership changed - List events = new ArrayList<>(); - for (LocusParticipant locusParticipant : event.getWaitingInLobbyParticipants()) { - if (locusParticipant != null && locusParticipant.getDeviceUrl() != null && !locusParticipant.getDeviceUrl().equals(_device.getUrl())) { - events.add(new CallObserver.MembershipWaitingEvent(call, new CallMembershipImpl(locusParticipant, call), event.isActive() ? Call.WaitReason.WAITING_FOR_ADMITTING : Call.WaitReason.MEETING_NOT_START)); - } - } - doCallMembershipChanged(call, events); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(RetrofitErrorEvent event) { - Ln.e("RetrofitErrorEvent is received"); - resetDialStatus(ResultImpl.error("Retrofit error: " + Utils.toMap(event))); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlCallJoinErrorEvent event) { - Ln.e("CallControlCallJoinErrorEvent is received "); - resetDialStatus(ResultImpl.error("Join Error: " + Utils.toMap(event))); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(ConflictErrorJoiningLocusEvent event) { - Ln.e("ConflictErrorJoiningLocusEvent is received "); - resetDialStatus(ResultImpl.error("Join Error: " + Utils.toMap(event))); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(HighVolumeErrorJoiningLocusEvent event) { - Ln.e("HighVolumeErrorJoiningLocusEvent is received "); - resetDialStatus(ResultImpl.error("Join Error: " + Utils.toMap(event))); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(LocusUserIsNotAuthorized event) { - Ln.e("LocusUserIsNotAuthorized is received "); - resetDialStatus(ResultImpl.error("Join Error: " + Utils.toMap(event))); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(LocusInviteesExceedMaxSizeEvent event) { - Ln.e("LocusInviteesExceedMaxSizeEvent is received "); - resetDialStatus(ResultImpl.error("Join Error: " + Utils.toMap(event))); - } - -// @Subscribe(threadMode = ThreadMode.MAIN) -// public void onEventMainThread(LocusMeetingLockedEvent event) { -// Ln.e("LocusMeetingLockedEvent is received "); -// resetDialStatus(ResultImpl.error("Join Error: " + Utils.toMap(event))); -// } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlLocusRequiresModeratorPINOrGuest event) { - Ln.d("CallControlLocusRequiresModeratorPINOrGuest is received"); - callAsGuest(); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlLocusRequiresModeratorPINorGuestPIN event) { - Ln.d("CallControlLocusRequiresModeratorPINorGuestPIN is received"); - callAsGuest(); - } - - private void callAsGuest() { - if (_callContext != null) { - String invitee = _callContext.getInvitee(); - if (invitee != null && !invitee.isEmpty()) { - _locusMeetingInfoProvider.callWithLocusMeetingInfo(invitee, GetMeetingInfoType.SIP_URI, new Action() { - @Override - public void call(LocusMeetingInfo item) { - Ln.d("Dial " + invitee); - _callContext.setModerator(false); - doDial(_callContext); - } - }); - } + queue.yield(); + }); } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(InvalidLocusEvent event) { - Ln.e("InvalidLocusEvent is received "); - resetDialStatus(ResultImpl.error("Join Error: " + Utils.toMap(event))); - } - - // Local hangup - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlSelfParticipantLeftEvent event) { - Ln.i("CallControlSelfParticipantLeftEvent is received " + event.getLocusKey()); - resetDialStatus(null); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - if (call.getHangupCallback() != null) { - call.getHangupCallback().onComplete(ResultImpl.success(null)); + else if (response instanceof LocusResponse.Update) { + LocusResponse.Update res = (LocusResponse.Update) response; + LocusModel model = res.getResult(); + if (model != null) { + res.getCall().update(model); } - removeCall(new CallObserver.LocalLeft(call)); - } - } - - // Local declined - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(LocusDeclinedEvent event) { - Ln.i("LocusDeclinedEvent is received " + event.getLocusKey()); - resetDialStatus(null); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - if (call.getRejectCallback() != null) { - call.getRejectCallback().onComplete(ResultImpl.success(null)); - } - removeCall(new CallObserver.LocalDecline(call)); - } - } - - // Local & Remote cancel - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlCallCancelledEvent event) { - Ln.i("CallControlCallCancelledEvent is received " + event.getLocusKey()); - resetDialStatus(null); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - if (event.getReason() == CallControlService.CancelReason.REMOTE_CANCELLED) { - removeCall(new CallObserver.RemoteCancel(call)); - } else { - if (call.getHangupCallback() != null) { - call.getHangupCallback().onComplete(ResultImpl.success(null)); - } - removeCall(new CallObserver.LocalCancel(call)); + if (res.getCallback() != null) { + Queue.main.run(() -> res.getCallback().onComplete(ResultImpl.success(null))); } + queue.yield(); } - } - - // Remote hangup - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlParticipantLeftEvent event) { - Ln.i("CallControlParticipantLeftEvent is received " + event.getLocusKey()); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - if (!call.isGroup()) { - resetDialStatus(null); - removeCall(new CallObserver.RemoteLeft(call)); - } else if (call.getStatus() == Call.CallStatus.INITIATED || call.getStatus() == Call.CallStatus.RINGING) { - boolean meetingIsOpen = false; - for (CallMembership membership : call.getMemberships()) { - if (membership.getState() == CallMembership.State.JOINED) { - meetingIsOpen = true; - } + else if (response instanceof LocusResponse.MediaShare) { + LocusResponse.MediaShare res = (LocusResponse.MediaShare) response; + Queue.main.run(() -> { + if (res.getIntent() != null && FloorModel.Disposition.GRANTED == res.getDisposition()) { + ScreenShareContext.getInstance().init(context, Activity.RESULT_OK, res.getIntent()); } - if (!meetingIsOpen) { - resetDialStatus(null); - removeCall(new CallObserver.RemoteCancel(call)); - } - } - List events = new ArrayList<>(); - for (LocusParticipant locusParticipant : event.getLeftParticipants()) { - events.add(new CallObserver.MembershipLeftEvent(call, new CallMembershipImpl(locusParticipant, call))); - } - doCallMembershipChanged(call, events); - doParticipantCountChanged(call); - } - } - - // Remote declined - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlLeaveLocusEvent event) { - Ln.i("CallControlLeaveLocusEvent is received " + event.locusData().getKey()); - resetDialStatus(null); - CallImpl call = _calls.get(event.locusData().getKey()); - // if (call != null && (event.wasCallDeclined() && !(event.wasMediaFlowing() || event.wasUCCall() || event.wasRoomCall() || event.wasRoomCallConnected()))) { - if (call == null) { - Ln.d("Cannot find the call " + event.locusData().getKey()); - } else { - Ln.d(STR_FIND_CALLIMPL + event.locusData().getKey()); - removeCall(new CallObserver.RemoteDecline(call)); - } - } - - // Space remote declined - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(ParticipantRoomDeclinedEvent event) { - Ln.i("ParticipantRoomDeclinedEvent is received " + event.getLocusKey()); - resetDialStatus(null); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - List events = new ArrayList<>(); - for (LocusParticipant locusParticipant : event.getDeclinedParticipants()) { - events.add(new CallObserver.MembershipDeclinedEvent(call, new CallMembershipImpl(locusParticipant, call))); - } - doCallMembershipChanged(call, events); - } - - } - - // Incoming Call - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallNotificationEvent event) { - Ln.i("CallNotificationEvent is received " + event.getType()); - if (event.getType() == CallNotificationType.INCOMING) { - Ln.i("InComing Call " + event.getLocusKey()); - LocusData locusData = _callControlService.getLocusData(event.getLocusKey()); - boolean isGroup = locusData != null && locusData.isMeeting(); - CallImpl call = new CallImpl(this, null, CallImpl.Direction.INCOMING, event.getLocusKey(), isGroup); - _bus.register(call); - _calls.put(call.getKey(), call); - IncomingCallListener listener = getIncomingCallListener(); - if (listener != null) { - listener.onIncomingCall(call); - } - } - } - - // mutiple device hangup - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(ParticipantSelfChangedEvent event) { - Ln.i("ParticipantSelfChangedEvent is received " + event.getLocusKey()); - CallImpl call = _calls.get(event.getLocusKey()); - Locus locus = event.getLocus(); - if (call != null && locus != null && locus.getSelf() != null) { - Uri deviceUrl = locus.getSelf().getDeviceUrl(); - Ln.d("ParticipantSelfChangedEvent device url: " + deviceUrl + " self: " + _device.getUrl() + " state: " + locus.getSelf().getState()); - if (call.getStatus() == Call.CallStatus.CONNECTED && !isJoinedFromThisDevice(locus.getSelf().getDevices())) { - Ln.d("Local device left locusKey: " + event.getLocusKey()); - resetDialStatus(null); - if (call.getHangupCallback() != null) { - call.getHangupCallback().onComplete(ResultImpl.success(null)); - } - removeCall(new CallObserver.LocalLeft(call)); - } else if (call.getStatus() != Call.CallStatus.CONNECTED - && deviceUrl != null && !deviceUrl.equals(_device.getUrl()) - && locus.getSelf().getState() == LocusParticipant.State.JOINED) { - com.cisco.spark.android.callcontrol.model.Call aCall = _callControlService.getCall(event.getLocusKey()); - if (aCall == null || !aCall.isActive()) { - Ln.d("other device connected locusKey: " + event.getLocusKey()); - resetDialStatus(null); - removeCall(new CallObserver.OtherConnected(call)); - } else { - Ln.d("Self device has already connected, ignore other device connect"); - } - } else if (call.getStatus() != Call.CallStatus.CONNECTED - && deviceUrl != null && !deviceUrl.equals(_device.getUrl()) - && locus.getSelf().getState() == LocusParticipant.State.DECLINED) { - com.cisco.spark.android.callcontrol.model.Call aCall = _callControlService.getCall(event.getLocusKey()); - if (aCall == null || !aCall.isActive()) { - Ln.d("other device declined locusKey: " + event.getLocusKey()); - resetDialStatus(null); - removeCall(new CallObserver.OtherDeclined(call)); - } else { - Ln.d("Self device has already connected, ignore other device decline"); - } - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(DismissCallNotificationEvent event) { - Ln.i("DismissCallNotificationEvent is received " + event.getLocusKey()); - final LocusData call = _callControlService.getLocusData(event.getLocusKey()); - if (call != null) { - call.setIsToasting(false); - } - _callAnalyzerReporter.reportCallAlertRemoved(event.getLocusKey()); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlLocalAudioMutedEvent event) { - Ln.i("CallControlLocalAudioMutedEvent is received " + event.getLocusKey()); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - CallObserver observer = call.getObserver(); - if (observer != null) { - observer.onMediaChanged(new CallObserver.SendingAudio(call, !event.isMuted())); - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlLocalVideoMutedEvent event) { - Ln.i("CallControlLocalVideoMutedEvent is received " + event.getLocusKey()); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - CallObserver observer = call.getObserver(); - if (observer != null) { - observer.onMediaChanged(new CallObserver.SendingVideo(call, !event.isMuted())); - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlParticipantAudioMuteEvent event) { - Ln.i("CallControlParticipantAudioMuteEvent is received " + event.getLocusKey()); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - LocusSelfRepresentation self = call.getSelf(); - if (self == null || !self.getUrl().equals(event.getParticipant().getUrl())) { - CallObserver observer = call.getObserver(); - boolean isSending = call.isRemoteSendingAudio(); - Ln.d("_isRemoteSendingAudio: " + _isRemoteSendingAudio + " isSending: " + isSending); - if (observer != null && _isRemoteSendingAudio != isSending) { - observer.onMediaChanged(new CallObserver.RemoteSendingAudioEvent(call, isSending)); - _isRemoteSendingAudio = isSending; - } - } else { - // TODO for local ?? - } - List events = new ArrayList<>(); - events.add(new CallObserver.MembershipSendingAudioEvent(call, new CallMembershipImpl(event.getParticipant(), call))); - doCallMembershipChanged(call, events); - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlParticipantVideoMutedEvent event) { - Ln.i("CallControlRemoteVideoMutedEvent is received " + event.getLocusKey()); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - Ln.d(STR_FIND_CALLIMPL + event.getLocusKey()); - LocusSelfRepresentation self = call.getSelf(); - if (!call.isGroup() && (self == null || !self.getUrl().equals(event.getParticipant().getUrl()))) { - CallObserver observer = call.getObserver(); - boolean isSending = !event.isMuted(); - Ln.d("_isRemoteSendingVideo: " + _isRemoteSendingVideo + " isSending: " + isSending); - if (observer != null && _isRemoteSendingVideo != isSending) { - observer.onMediaChanged(new CallObserver.RemoteSendingVideoEvent(call, isSending)); - } - _isRemoteSendingVideo = isSending; - } - - List events = new ArrayList<>(); - events.add(new CallObserver.MembershipSendingVideoEvent(call, new CallMembershipImpl(event.getParticipant(), call))); - doCallMembershipChanged(call, events); - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlLocusChangedEvent event) { - Ln.i("CallControlLocusChangedEvent is received "); - // TODO DO THIS FOR PSTN/SIP - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(RequestCallingPermissions event) { - Ln.i("RequestCallingPermissions is received"); - List permissions = new ArrayList<>(); - permissions.add(Manifest.permission.RECORD_AUDIO); - permissions.add(Manifest.permission.CAMERA); - resetDialStatus(ResultImpl.error(new WebexError<>(WebexError.ErrorCode.PERMISSION_ERROR, "Permissions Error", permissions))); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlFloorGrantedEvent event) { - Ln.i("CallControlFloorGrantedEvent is received "); - List events = new ArrayList<>(); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null) { - LocusParticipant beneficiary = _callControlService.getLocus(event.getLocusKey()).getFloorBeneficiary(); - if (beneficiary != null) { - _currentSharingUri = beneficiary.getDeviceUrl(); - } - for (CallMembership membership : call.getMemberships()) { - if (membership.isSendingSharing()) { - events.add(new CallObserver.MembershipSendingSharingEvent(call, membership)); - break; - } - } - doCallMembershipChanged(call, events); - - CallObserver observer = call.getObserver(); - if (observer != null) { - if (call.isSendingSharing()) { - observer.onMediaChanged(new CallObserver.SendingSharingEvent(call, true)); - } else if (call.isRemoteSendingSharing() && _lostSharingParticipant == null) { - observer.onMediaChanged(new CallObserver.RemoteSendingSharingEvent(call, true)); - } - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlFloorReleasedEvent event) { - Ln.i("CallControlFloorReleasedEvent is received "); - List events = new ArrayList<>(); - CallImpl call = _calls.get(event.getLocusKey()); - LocusData locusData = _callControlService.getLocusData(event.getLocusKey()); - LocusParticipant beneficiary = locusData.getReleasedParticipantSharing(); - if (beneficiary == null) { - Ln.w("getReleasedParticipantSharing is null!"); - beneficiary = _lostSharingParticipant; - } - if (call != null && locusData != null && beneficiary != null) { - for (CallMembership membership : call.getMemberships()) { - if (beneficiary.getPerson() != null - && beneficiary.getPerson().getId() != null - && membership.getPersonId().equals(Utils.encode(beneficiary.getPerson().getId()))) { - events.add(new CallObserver.MembershipSendingSharingEvent(call, membership)); - break; - } - } - doCallMembershipChanged(call, events); - - CallObserver observer = call.getObserver(); - if (observer != null) { - if (_currentSharingUri != null && _currentSharingUri.equals(_device.getUrl())) { - observer.onMediaChanged(new CallObserver.SendingSharingEvent(call, false)); - _lostSharingParticipant = null; - } else if (!locusData.isFloorGranted() || isSharingFromThisDevice(locusData)) { - observer.onMediaChanged(new CallObserver.RemoteSendingSharingEvent(call, false)); - _lostSharingParticipant = null; - } - } - } - } - - // ------------------------------------------------------------------------ - // MultiStream - // ------------------------------------------------------------------------ - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(MediaBlockedChangeEvent event) { - Ln.d("MediaBlockedChangeEvent is received mid: " + event.getMediaId() + " vid: " + event.getVideoId() + " isBlocked: " + event.isBlocked()); - if (_activeCallLocusKey == null) { - return; - } - CallImpl activeCall = _calls.get(_activeCallLocusKey); - if (activeCall != null && activeCall.isGroup()) { - int vid = event.getVideoId(); - switch (event.getMediaId()) { - case MediaEngine.VIDEO_MID: - // If 'blocked' is changed, publish blocked change event. - if (vid == 0) { - CallObserver observer = activeCall.getObserver(); - boolean isSending = !event.isBlocked(); - Ln.d("_isRemoteSendingVideo: " + _isRemoteSendingVideo + " isSending: " + isSending); - if (observer != null && _isRemoteSendingVideo != isSending) { - observer.onMediaChanged(new CallObserver.RemoteSendingVideoEvent(activeCall, isSending)); - } - _isRemoteSendingVideo = isSending; - } else if (vid > 0) { - AuxStreamImpl auxStream = activeCall.getAuxStream(vid); - if (auxStream != null && auxStream.isSendingVideo() == event.isBlocked()) { - auxStream.setSendingVideo(!event.isBlocked()); - if (activeCall.getMultiStreamObserver() != null) { - activeCall.getMultiStreamObserver().onAuxStreamChanged(new MultiStreamObserver.AuxStreamSendingVideoEvent(activeCall, auxStream)); - } - } - } - break; - case MediaEngine.SHARE_MID: - // If 'blocked' is changed, publish blocked change event. - break; - default: - break; - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlActiveSpeakerChangedEvent event) { - Ln.d("CallControlActiveSpeakerChangedEvent is received vid: " + event.getVideoId() + " participant: " + event.getParticipant()); - doActiveSpeakerChanged(_calls.get(event.getLocusKey()), event.getParticipant(), event.getVideoId()); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlMediaVideoMutedEvent event) { - Ln.d("CallControlMediaVideoMutedEvent is received participant: " + event.getLocusParticipant().getPerson().getDisplayName() + " vid: " + event.getVid() + " mute: " + event.isMuted()); - doActiveSpeakerChanged(_calls.get(event.getLocusKey()), event.getLocusParticipant(), event.getVid()); - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(MediaAvailabilityChangeEvent event) { - Ln.d("AvailableMediaChangeEvent is received mid: " + event.getMediaId() + " count: " + event.getCount()); - if (_activeCallLocusKey != null) { - CallImpl activeCall = _calls.get(_activeCallLocusKey); - if (activeCall != null && event.getMediaId() == MediaEngine.VIDEO_MID) { - _availableMediaCount = event.getCount(); - doParticipantCountChanged(activeCall); - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(CallControlMediaDecodeSizeChangedEvent event) { - Ln.d("CallControlMediaDecodeSizeChangedEvent is received mid: " + event.getMediaId() + " size: " + event.getSize()); - if (_activeCallLocusKey == null) { - return; - } - CallImpl activeCall = _calls.get(_activeCallLocusKey); - if (activeCall != null && activeCall.isGroup()) { - switch (event.getMediaId()) { - case MediaEngine.VIDEO_MID: - AuxStreamImpl auxStream = activeCall.getAuxStream(event.getVideoId()); - if (auxStream != null) { - auxStream.setSize(event.getSize()); - if (activeCall.getMultiStreamObserver() != null) - activeCall.getMultiStreamObserver().onAuxStreamChanged(new MultiStreamObserver.AuxStreamSizeChangedEvent(activeCall, auxStream)); - } - break; - case MediaEngine.SHARE_MID: - break; - default: - break; - } - } - } - - private void doActiveSpeakerChanged(CallImpl call, LocusParticipant participant, long vid) { - Ln.d("doActiveSpeakerChanged: " + call + " person: " + participant); - if (call == null) { - return; - } - for (CallMembership membership : call.getMemberships()) { - if (membership.getPersonId().equals(Utils.encode(participant.getPerson().getId()))) { - if (vid == 0) { - CallMembership old = call.getActiveSpeaker(); - if (old == null || !old.getPersonId().equals(membership.getPersonId())) { - call.setActiveSpeaker(membership); - if (call.getObserver() != null) { - call.getObserver().onMediaChanged(new CallObserver.ActiveSpeakerChangedEvent(call, old, call.getActiveSpeaker())); - } - } - } else if (vid > 0 && call.isGroup()) { - AuxStreamImpl auxStream = call.getAuxStream(vid); - if (auxStream != null && (auxStream.getPerson() == null || !auxStream.getPerson().getPersonId().equals(membership.getPersonId()))) { - CallMembership old = auxStream.getPerson(); - auxStream.setPerson(membership); - if (call.getMultiStreamObserver() != null) { - call.getMultiStreamObserver().onAuxStreamChanged(new MultiStreamObserver.AuxStreamPersonChangedEvent(call, auxStream, old, auxStream.getPerson())); - } - } + if (res.getCallback() != null) { + res.getCallback().onComplete(ResultImpl.success(null)); } - break; - } + queue.yield(); + }); } } - private void doParticipantCountChanged(CallImpl call) { - if (call == null || !call.getKey().equals(_activeCallLocusKey) || !call.isGroup()) { + private void doLocusEvent(LocusModel model) { + if (model == null) { + Ln.d("No CallModel"); return; } - int oldCount = call.getAvailableAuxStreamCount(); - int newCount = Math.min(call.getJoinedMemberships().size() - 2, _availableMediaCount - 1); - Ln.d("doParticipantCountChanged old: " + oldCount + " new: " + newCount); - newCount = Math.min(newCount, MediaEngine.MAX_NUMBER_STREAMS); - if (newCount >= 0 && oldCount != newCount) { - call.setAvailableAuxStreamCount(newCount); - if (call.getMultiStreamObserver() == null) { - for (int i = oldCount; i > newCount; i--) { - call.closeAuxStream(); - } - } else if (newCount > oldCount) { - for (int i = oldCount; i < newCount; i++) { - View view = call.getMultiStreamObserver().onAuxStreamAvailable(); - if (view != null) { - call.openAuxStream(view); - } - } - } else { - for (int i = oldCount; i > newCount; i--) { - View view = call.getMultiStreamObserver().onAuxStreamUnavailable(); - AuxStream auxStream = call.getAuxStream(view); - if (auxStream != null) { - call.closeAuxStream(auxStream, view); - } else { - call.closeAuxStream(); - } - } - } - } else if (_availableMediaCount == 0 && call.getActiveSpeaker() != null) { - CallMembership old = call.getActiveSpeaker(); - call.setActiveSpeaker(null); - if (call.getObserver() != null) { - call.getObserver().onMediaChanged(new CallObserver.ActiveSpeakerChangedEvent(call, old, call.getActiveSpeaker())); - } - } - } - - // ------------------------------------------------------------------------ - // Screen Sharing - // ------------------------------------------------------------------------ - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(FloorRequestAcceptedEvent event) { - Ln.d("FloorRequestAcceptedEvent is received: " + event.isContent()); - if (event.isContent() && event.getLocusKey().equals(_screenSharingKey)) { - ScreenShareContext.getInstance().init(_context, Activity.RESULT_OK, _screenSharingIntent); - CallImpl call = _calls.get(_screenSharingKey); - if (call != null && call.getShareRequestCallback() != null) { - call.getShareRequestCallback().onComplete(ResultImpl.success(null)); - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(FloorRequestDeniedEvent event) { - Ln.d("FloorRequestDeniedEvent is received: " + event.isContent()); - if (event.isContent() && event.getLocusKey().equals(_screenSharingKey)) { - CallImpl call = _calls.get(_screenSharingKey); - if (call != null && call.getShareRequestCallback() != null) { - call.getShareRequestCallback().onComplete(ResultImpl.error("Share request is deined")); - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(FloorReleasedAcceptedEvent event) { - Ln.d("FloorReleasedAcceptedEvent is received: " + event.isContent()); - if (event.isContent() && event.getLocusKey().equals(_screenSharingKey)) { - CallImpl call = _calls.get(_screenSharingKey); - if (call != null && call.getShareReleaseCallback() != null) { - call.getShareReleaseCallback().onComplete(ResultImpl.success(null)); - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(FloorReleasedDeniedEvent event) { - Ln.d("FloorReleasedDeniedEvent is received: " + event.isContent()); - if (event.isContent() && event.getLocusKey().equals(_screenSharingKey)) { - CallImpl call = _calls.get(_screenSharingKey); - if (call != null && call.getShareReleaseCallback() != null) { - call.getShareReleaseCallback().onComplete(ResultImpl.error("Share release is deined")); - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(FloorLostEvent event) { - Ln.d("FloorLostEvent is received"); - CallImpl call = _calls.get(event.getLocusKey()); - if (call != null && call.getStatus() == Call.CallStatus.CONNECTED) { - LocusParticipant beneficiary = event.getLocalMediaShare().getFloor().getBeneficiary(); - if (beneficiary != null) { - LocusData locusData = _callControlService.getLocusData(event.getLocusKey()); - if (locusData != null) { - _lostSharingParticipant = locusData.getParticipant(beneficiary.getUrl()); - if (_lostSharingParticipant.getPerson() == null) - Ln.w("_lostSharingParticipant getPerson is null"); - else - Ln.d("_lostSharingParticipant email: " + _lostSharingParticipant.getPerson().getEmail()); - } - } - } - } - - public void setScreenshotPermission(final Intent permissionIntent) { - if (permissionIntent != null) { - _screenSharingIntent = permissionIntent; - _callControlService.shareScreen(_screenSharingKey); - } else { - Ln.w("permission for sharing screen is deined"); - CallImpl call = _calls.get(_screenSharingKey); - if (call != null && call.getShareRequestCallback() != null) { - call.getShareRequestCallback().onComplete(ResultImpl.error(STR_PERMISSION_DENIED)); - } - } - } - - public void startSharing(LocusKey key) { - Ln.d("startSharing: " + key); - _screenSharingKey = key; - final Intent intent = new Intent(_context, AcquirePermissionActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(AcquirePermissionActivity.PERMISSION_TYPE, AcquirePermissionActivity.PERMISSION_SCREEN_SHOT); - _context.startActivity(intent); - } - - public void stopSharing(LocusKey key) { - _callControlService.unshareScreen(key); - } - - protected boolean isSharingFromThisDevice(LocusData locusData) { - return locusData != null && locusData.isFloorMineThisDevice(_device.getUrl()); - } - - private void removeCall(@NonNull CallObserver.CallDisconnectedEvent event) { - CallImpl call = (CallImpl) event.getCall(); - Ln.i("Remove " + call); - if (call != null) { - call.setStatus(Call.CallStatus.DISCONNECTED); - CallObserver observer = call.getObserver(); - if (observer != null) { - observer.onDisconnected(event); - } - _calls.remove(call.getKey()); - if (_bus.isRegistered(call)) { - _bus.unregister(call); - } - if (call.getKey().equals(_activeCallLocusKey)) { - _lostSharingParticipant = null; - _currentSharingUri = null; - _availableMediaCount = 0; - } - } - } - - private void setCallOnConnected(@NonNull CallImpl call, @NonNull LocusKey key) { - if (call.getStatus() == Call.CallStatus.CONNECTED) { - Ln.d("Already has been connected, return"); + String url = model.getCallUrl(); + if (url == null) { + Ln.d("CallModel is missing call url"); return; } - if (call.getOption() != null) { - if (call.getOption().hasVideo() && call.getVideoRenderViews() != null) { - _callControlService.setPreviewWindow(key, call.getVideoRenderViews().first); - if (call.getVideoRenderViews().first instanceof SurfaceView) { - ((SurfaceView) call.getVideoRenderViews().first).getHolder().addCallback(new SurfaceHolder.Callback() { - @Override - public void surfaceCreated(SurfaceHolder surfaceHolder) { - Ln.d("preview surfaceCreated !!!"); - if (!_callControlService.isPreviewWindowAttached(key, call.getVideoRenderViews().first)) - _callControlService.setPreviewWindow(key, call.getVideoRenderViews().first); - } - - @Override - public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { - Ln.d("preview surfaceChanged !!!"); - } - - @Override - public void surfaceDestroyed(SurfaceHolder surfaceHolder) { - Ln.d("preview surfaceDestroyed !!!"); - _registerTimer.post(() -> _callControlService.removePreviewWindow(key, call.getVideoRenderViews().first)); + Ln.d("doLocusEvent: " + url); + Queue.serial.run(() -> { + CallImpl call = calls.get(url); + if (call == null) { + if (device != null && model.isIncomingCall() && model.isValid()) { + CallImpl incoming = new CallImpl(model, this, device, null, Call.Direction.INCOMING, !model.isOneOnOne()); + addCall(incoming); + Ln.d("Receive incoming call: " + incoming.getUrl()); + Queue.main.run(() -> { + IncomingCallListener listener = getIncomingCallListener(); + if (listener != null) { + listener.onIncomingCall(incoming); } }); } - - _callControlService.setRemoteWindow(key, call.getVideoRenderViews().second); - if (call.getVideoRenderViews().second instanceof SurfaceView) { - ((SurfaceView) call.getVideoRenderViews().second).getHolder().addCallback(new SurfaceHolder.Callback() { - @Override - public void surfaceCreated(SurfaceHolder surfaceHolder) { - Ln.d("remote surfaceCreated !!!"); - if (!_callControlService.isRemoteWindowAttached(key, 0, call.getVideoRenderViews().second)) - _callControlService.setRemoteWindow(key, call.getVideoRenderViews().second); - } - - @Override - public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { - Ln.d("remote surfaceChanged !!!"); - } - - @Override - public void surfaceDestroyed(SurfaceHolder surfaceHolder) { - Ln.d("remote surfaceDestroyed !!!"); - _registerTimer.post(() -> _callControlService.removeRemoteWindow(key, call.getVideoRenderViews().second)); - } - }); + else { + Ln.d("Receive incoming call with invalid model"); } + Queue.serial.yield(); + return; } - if (call.getOption().hasSharing() && call.getSharingRenderView() != null) { - _callControlService.setShareWindow(key, call.getSharingRenderView()); - if (call.getSharingRenderView() instanceof SurfaceView) { - ((SurfaceView) call.getSharingRenderView()).getHolder().addCallback(new SurfaceHolder.Callback() { - @Override - public void surfaceCreated(SurfaceHolder surfaceHolder) { - Ln.d("share surfaceCreated !!!"); - _registerTimer.postDelayed(() -> _callControlService.setShareWindow(key, call.getSharingRenderView()), 100); - } - - @Override - public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { - Ln.d("share surfaceChanged !!!"); - } - - @Override - public void surfaceDestroyed(SurfaceHolder surfaceHolder) { - Ln.d("share surfaceDestroyed !!!"); - if (_callControlService.isShareRendering()) { - _registerTimer.post(() -> _callControlService.removeShareWindow(key)); - } - } - }); - } - } - // Avoid updateMediaSession twice - // call.updateMedia(); - } - call.setStatus(Call.CallStatus.CONNECTED); - - CallObserver observer = call.getObserver(); - if (observer != null) { - observer.onConnected(call); - } else { - Ln.d("call observer is null"); - } - _isRemoteSendingVideo = true; - _isRemoteSendingAudio = call.isRemoteSendingAudio(); - _activeCallLocusKey = key; - } - - private void setCallOnRinging(@NonNull CallImpl call) { - if (call.getStatus() == Call.CallStatus.INITIATED) { - call.setStatus(Call.CallStatus.RINGING); - CallObserver observer = call.getObserver(); - if (observer != null) { - observer.onRinging(call); - } - } else { - Ln.w("Do not setCallOnRinging, because current state is: " + call.getStatus()); - } - } - - private void setCallOnWaiting(@NonNull CallImpl call, Call.WaitReason waitReason) { - if (call.getStatus() == Call.CallStatus.CONNECTED || call.getStatus() == Call.CallStatus.DISCONNECTED) { - Ln.w("Already connected or disconnected, do nothing"); - return; - } - call.setStatus(Call.CallStatus.WAITING); - CallObserver observer = call.getObserver(); - if (observer != null) { - observer.onWaiting(call, waitReason); - } - } - - private void doCallMembershipChanged(CallImpl call, @NonNull List events) { - if (call == null) { - return; - } - CallObserver observer = call.getObserver(); - if (observer != null) { - for (CallObserver.CallMembershipChangedEvent event : events) { - observer.onCallMembershipChanged(event); - } - } else { - Ln.d("call observer is null"); - } - } - - private void resetDialStatus(Result result) { - Ln.d("Try to reset dial status for " + result + ", callback " + _dialCallback); - _dialOption = null; - _callContext = null; - if (_dialCallback != null) { - CompletionHandler callback = _dialCallback; - _dialCallback = null; - if (result != null) { - callback.onComplete(result); - } - } - } - - private void doDial(String target, MediaOption option) { - Ln.d("Dial " + target); - CallContext.Builder builder = new CallContext.Builder(target); - builder = builder.setMediaDirection(mediaOptionToMediaDirection(option)); - doDial(builder.build()); - } - - private void doDialSpaceID(String target, MediaOption option) { - Ln.d("Dial " + target); - _apiClientProvider.getConversationClient().getOrCreatePermanentLocus(target).enqueue(new Callback() { - @Override - public void onResponse(retrofit2.Call call, Response response) { - if (response.isSuccessful()) { - LocusKey key = LocusKey.fromUri(response.body().getLocusUrl()); - CallContext.Builder builder = new CallContext.Builder(key); - builder = builder.setMediaDirection(mediaOptionToMediaDirection(option)); - doDial(builder.build()); - } else { - Ln.w(STR_FAILURE_CALL + response.errorBody().toString()); - resetDialStatus(ResultImpl.error(STR_FAILURE_CALL + response.errorBody().toString())); - } - } - - @Override - public void onFailure(retrofit2.Call call, Throwable t) { - resetDialStatus(ResultImpl.error(STR_FAILURE_CALL + t.getMessage())); - } + call.update(model); + Queue.serial.yield(); }); - } - private boolean doDial(CallContext context) { - if (this._callContext == null) { - this._callContext = context; - } - MediaCapabilityConfig config = new MediaCapabilityConfig(audioMaxBandwidth, videoMaxBandwidth, sharingMaxBandwidth); - config.setHardwareCodecEnable(isEnableHardwareAcceleration); - config.setHwVideoSetting(hardwareVideoSettings); - _mediaEngine.setMediaConfig(config); - if (_callControlService.joinCall(context, false) == null) { - resetDialStatus(ResultImpl.error(STR_FAILURE_CALL + "cannot dial")); - return false; - } - return true; } - private boolean isJoinedFromThisDevice(List devices) { - if (_device == null || _device.getUrl() == null) { - Ln.w("isJoinedFromThisDevice: self device is null, register device first."); - return false; - } - - for (LocusParticipantDevice device : devices) { - if (device.getUrl().equals(_device.getUrl()) - && device.getState() == LocusParticipant.State.JOINED) { - return true; - } - } - - return false; + void addCall(CallImpl call) { + Ln.d("Add call for call url: " + call.getUrl()); + this.calls.put(call.getUrl(), call); } - static FacingMode toFacingMode(String s) { - if (MediaEngine.WME_BACK_CAMERA.equals(s)) { - return FacingMode.ENVIROMENT; - } - return FacingMode.USER; + void removeCall(CallImpl call) { + Ln.d("Remove call for call url: " + call.getUrl()); + this.calls.remove(call.getUrl()); } - static String fromFacingMode(FacingMode mode) { - if (mode == FacingMode.ENVIROMENT) { - return MediaEngine.WME_BACK_CAMERA; - } - return MediaEngine.WME_FRONT_CAMERA; + CallService getService() { + return service; } - static MediaEngine.MediaDirection mediaOptionToMediaDirection(MediaOption option) { - MediaEngine.MediaDirection direction; - if (option.hasVideo() && option.hasSharing()) { - direction = MediaEngine.MediaDirection.SendReceiveAudioVideoShare; - } else if (option.hasVideo() && !option.hasSharing()) { - direction = MediaEngine.MediaDirection.SendReceiveAudioVideo; - } else if (!option.hasVideo() && option.hasSharing()) { - direction = MediaEngine.MediaDirection.SendReceiveShareOnly; - } else { - direction = MediaEngine.MediaDirection.SendReceiveAudioOnly; + void listActiveCalls() { + Ln.d("Fetch call infos"); + if (device != null) { + service.list(device, result -> { + List models = result.getData(); + if (models == null) { + Ln.d("Failure: " + result.getError()); + return; + } + for (LocusModel model : models) { + doLocusEvent(model); + } + Ln.d("Success: fetch call infos"); + }); } - - return direction; - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(NoSubscriberEvent event) { - // -- Ignore Event - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(ConversationSyncQueue.ConversationSyncStartedEvent event) { - // -- Ignore Event - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(ApplicationControllerStateChangedEvent event) { - // -- Ignore Event } - private void updateCallLobbyStatus(LocusKey locusKey, boolean inLobby) { - com.cisco.spark.android.callcontrol.model.Call call = _callControlService.getCall(locusKey); - if (call != null) { - call.setLeavingCallBeforeMediaStarted(inLobby); + private MediaCapability createCapability() { + MediaCapability capability = new MediaCapability(); + capability.setAudioMaxBandwidth(getAudioMaxBandwidth()); + capability.setVideoMaxBandwidth(getVideoMaxBandwidth()); + capability.setSharingMaxBandwidth(getSharingMaxBandwidth()); + capability.setHardwareCodecEnable(isHardwareAccelerationEnabled()); + capability.setHardwareVideoSetting(getHardwareVideoSettings()); + capability.setAudioEnhancementModels(audioEnhancementModels); + if (device != null) { + capability.setDeviceSettings(device.getDeviceSettings()); } + capability.setDefaultCamera(WMEngine.Camera.fromFaceMode(getDefaultFacingMode())); + return capability; } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/ReachabilityService.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/ReachabilityService.java new file mode 100644 index 00000000..cbffd42a --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/ReachabilityService.java @@ -0,0 +1,82 @@ +package com.ciscowebex.androidsdk.phone.internal; + +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.model.CalliopeClusterModel; +import com.ciscowebex.androidsdk.internal.model.MediaEngineReachabilityModel; +import com.ciscowebex.androidsdk.internal.model.ReachabilityModel; +import com.ciscowebex.androidsdk.utils.Json; +import com.ciscowebex.androidsdk.utils.NetworkUtils; +import com.github.benoitdion.ln.Ln; +import com.google.gson.reflect.TypeToken; +import me.helloworld.utils.Checker; + +import java.util.List; +import java.util.Map; + +public class ReachabilityService { + + private PhoneImpl phone; + private String ipAddress; + private long lastUpdate; + private MediaEngineReachabilityModel feedback; + + public ReachabilityService(PhoneImpl phone) { + this.phone = phone; + } + + public MediaEngineReachabilityModel getFeedback() { + return feedback; + } + + public void fetch() { + boolean isIpAddressChanged = isIpAddressChanged(); + boolean isMaxAgeReached = isDataExpired(); + if (isIpAddressChanged || isMaxAgeReached) { + Ln.d("Fetch scheduled, isAddressChanged = %s, isMaxAgeReached = %s", isIpAddressChanged, isMaxAgeReached); + performReachabilityCheck(data -> { + if (data != null) { + feedback = data; + ipAddress = NetworkUtils.getLocalIpAddress(); + lastUpdate = System.currentTimeMillis(); + Ln.d("Fetch done: " + feedback); + } + }); + } + else { + Ln.d("Fetch skipped, isAddressChanged = %s, isMaxAgeReached = %s", isIpAddressChanged, isMaxAgeReached); + } + } + + public void clear() { + ipAddress = null; + phone.getEngine().clearReachability(); + } + + private boolean isIpAddressChanged() { + String currentIpAddress = NetworkUtils.getLocalIpAddress(); + return !Checker.isEqual(ipAddress, currentIpAddress); + } + + private boolean isDataExpired() { + return System.currentTimeMillis() - lastUpdate > 7200000; + } + + private void performReachabilityCheck(Closure callback) { + if (phone.getDevice() == null) { + Ln.e("Failure: Not register!"); + return; + } + Service.CalliopeDiscorey.get("clusters") + .auth(phone.getAuthenticator()).device(phone.getDevice()).model(CalliopeClusterModel.class) + .error((CompletionHandler) error -> Ln.e("Failure: " + error)) + .async((Closure) model -> { + Map>> group = model.getClusterInfo(); + if (group != null) { + phone.getEngine().performReachabilityCheck(group, callback); + } + }); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/RegisterOperation.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/RegisterOperation.java new file mode 100644 index 00000000..4221ebac --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/RegisterOperation.java @@ -0,0 +1,92 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.phone.internal; + +import android.os.Build; +import android.util.Pair; +import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.*; +import com.ciscowebex.androidsdk.internal.model.DeviceModel; +import com.ciscowebex.androidsdk.internal.model.RegionModel; +import com.github.benoitdion.ln.Ln; +import me.helloworld.utils.Objects; +import me.helloworld.utils.collection.Maps; +import okhttp3.Request; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class RegisterOperation implements Runnable { + + private Authenticator authenticator; + + private CompletionHandler> callback; + + public RegisterOperation(Authenticator authenticator, CompletionHandler> callback) { + this.authenticator = authenticator; + this.callback = callback; + } + + @Override + public void run() { + Service.Region.get("region").model(RegionModel.class).error(callback).async((Closure) region -> { + String countryCode = Objects.defaultIfNull(region.getCountryCode(), "US"); + String regionCode = Objects.defaultIfNull(region.getRegionCode(), "US-WEST"); + Map deviceInfo = new HashMap<>(); + deviceInfo.put("deviceType", Device.ANDROID_DEVICE_TYPE); + deviceInfo.put("countryCode", countryCode); + deviceInfo.put("regionCode", regionCode); + deviceInfo.put("ttl", String.valueOf(TimeUnit.DAYS.toSeconds(180))); + deviceInfo.put("name", Build.DEVICE); + deviceInfo.put("model", Build.MODEL); + deviceInfo.put("localizedModel", Build.MODEL); + deviceInfo.put("systemName", Build.PRODUCT); + deviceInfo.put("systemVersion", Build.VERSION.RELEASE); + deviceInfo.put("capabilities", Maps.makeMap("groupCallSupported", Boolean.TRUE, "sdpSupported", Boolean.TRUE)); + + String deviceUrl = Settings.shared.get(Device.DEVICE_URL, null); + Ln.d("Saved deviceUrl: " + deviceUrl); + ServiceReqeust reqeust = Service.Wdm.post(deviceInfo); + Request deviceRequest; + if (deviceUrl == null) { + Ln.d("Creating new device"); + reqeust.to("devices"); + } + else { + Ln.d("Updating device"); + reqeust.url(deviceUrl); + } + reqeust.auth(authenticator).model(DeviceModel.class).error(callback).async((Closure) model -> Credentials.auth(authenticator, userResult -> { + Credentials credentials = userResult.getData(); + if (credentials == null) { + callback.onComplete(ResultImpl.error(userResult.getError())); + } + else { + callback.onComplete(ResultImpl.success(new Pair<>(new Device(model, region), credentials))); + } + })); + }); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/RotationHandler.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/UIEventHandler.java similarity index 51% rename from sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/RotationHandler.java rename to sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/UIEventHandler.java index 142064a8..289a4ad9 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/RotationHandler.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/UIEventHandler.java @@ -22,63 +22,86 @@ package com.ciscowebex.androidsdk.phone.internal; - import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.os.Bundle; -import android.view.WindowManager; +import com.ciscowebex.androidsdk.utils.Utils; + +public class UIEventHandler { -public class RotationHandler { - private static BroadcastReceiver receiver; + interface EventObserver { - private RotationHandler(){} + void onScreenRotation(int rotation); - static int getRotation(Context context) { - WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - return windowManager.getDefaultDisplay().getRotation(); + void onMediaPermission(boolean permission); + + void onScreenCapturePermission(Intent permission); } + static class UIEventBroadcastReceiver extends BroadcastReceiver { + + private int rotation; - static class RotationBroadcastReceiver extends BroadcastReceiver { - PhoneImpl phoneImpl; + private EventObserver observer; - public RotationBroadcastReceiver(PhoneImpl phoneImpl) { + public UIEventBroadcastReceiver(EventObserver observer) { super(); - this.phoneImpl = phoneImpl; + this.observer = observer; + } + + EventObserver getObserver() { + return observer; } @Override public void onReceive(Context context, Intent intent) { - phoneImpl.setDisplayRotation(getRotation(context)); + int rotation = Utils.getScreenRotation(context); + if (this.rotation != rotation) { + this.rotation = rotation; + if (observer != null) { + observer.onScreenRotation(rotation); + } + } } } - static void registerRotationReceiver(Context context, PhoneImpl phoneImpl) { + private UIEventBroadcastReceiver receiver; + + private static UIEventHandler handler = new UIEventHandler(); + + public static UIEventHandler get() { + return handler; + } + + private UIEventHandler(){} + + void registerUIEventHandler(Context context, EventObserver observer) { if (receiver == null) { - receiver = new RotationBroadcastReceiver(phoneImpl); - context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED)); + receiver = new UIEventBroadcastReceiver(observer); } + context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED)); } - static void unregisterRotationReceiver(Context context) { + void unregisterUIEventHandler(Context context) { if (receiver != null) { context.unregisterReceiver(receiver); receiver = null; } } - public static void setScreenshotPermission(final Intent permissionIntent) { + public void doMediaPermission(boolean permssion) { if (receiver != null) { - ((RotationBroadcastReceiver) receiver).phoneImpl.setScreenshotPermission(permissionIntent); + receiver.getObserver().onMediaPermission(permssion); } } - public static void makeCall(Bundle data, boolean permission) { + public void doScreenCapturePermission(Intent intent) { if (receiver != null) { - ((RotationBroadcastReceiver) receiver).phoneImpl.makeCall(data, permission); + receiver.getObserver().onScreenCapturePermission(intent); } } + + } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ObjectCallback.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/UnregisterOperation.java similarity index 60% rename from sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ObjectCallback.java rename to sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/UnregisterOperation.java index 9b55b45b..f96f0268 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ObjectCallback.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/UnregisterOperation.java @@ -20,37 +20,33 @@ * THE SOFTWARE. */ -package com.ciscowebex.androidsdk.utils.http; +package com.ciscowebex.androidsdk.phone.internal; import com.ciscowebex.androidsdk.CompletionHandler; +import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.Device; import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.Service; -import retrofit2.Call; -import retrofit2.Response; +public class UnregisterOperation implements Runnable { -/** - * Created by zhiyuliu on 02/09/2017. - */ + private Authenticator authenticator; -public class ObjectCallback extends ListenerCallback { + private Device device; - private CompletionHandler _handler; + private CompletionHandler callback; - public ObjectCallback(CompletionHandler handler) { - _handler = handler; + public UnregisterOperation(Authenticator authenticator, Device device, CompletionHandler callback) { + this.authenticator = authenticator; + this.device = device; + this.callback = callback; } @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - _handler.onComplete(ResultImpl.success(response.body())); - } else if (!checkUnauthError(response)) { - _handler.onComplete(ResultImpl.error(response)); + public void run() { + String deviceUrl = device.getDeviceUrl(); + if (deviceUrl != null) { + Service.Wdm.delete().url(deviceUrl).auth(authenticator).error(callback).async(data -> callback.onComplete(ResultImpl.success(null))); } } - - @Override - public void onFailure(Call call, Throwable t) { - _handler.onComplete(ResultImpl.error(t)); - } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/space/Space.java b/sdk/src/main/java/com/ciscowebex/androidsdk/space/Space.java index eeff3b5e..fbe11f9f 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/space/Space.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/space/Space.java @@ -24,10 +24,9 @@ import java.util.Date; -import com.cisco.spark.android.model.Verb; -import com.cisco.spark.android.model.conversation.Activity; -import com.cisco.spark.android.model.conversation.ActivityObject; -import com.cisco.spark.android.model.conversation.Conversation; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; +import com.ciscowebex.androidsdk.internal.model.ConversationModel; +import com.ciscowebex.androidsdk.internal.model.ObjectModel; import com.ciscowebex.androidsdk.utils.WebexId; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; @@ -97,13 +96,13 @@ public String serializedName() { @SerializedName("sipAddress") private String _sipAddress; - protected Space(Activity activity) { + protected Space(ActivityModel activity) { _lastActivity = activity.getPublished(); - ActivityObject object = activity.getVerb().equals(Verb.create) ? activity.getObject() : activity.getTarget(); - if (object instanceof Conversation) { + ObjectModel object = activity.getVerb().equals(ActivityModel.Verb.create) ? activity.getObject() : activity.getTarget(); + if (object instanceof ConversationModel) { _id = new WebexId(WebexId.Type.ROOM_ID, object.getId()).toHydraId(); - _isLocked = ((Conversation) object).isLocked(); - _type = ((Conversation) object).isOneOnOne() ? Space.SpaceType.DIRECT : Space.SpaceType.GROUP; + _isLocked = ((ConversationModel) object).isLocked(); + _type = ((ConversationModel) object).isOneOnOne() ? Space.SpaceType.DIRECT : Space.SpaceType.GROUP; } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/space/SpaceObserver.java b/sdk/src/main/java/com/ciscowebex/androidsdk/space/SpaceObserver.java index f441fcca..9bb34511 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/space/SpaceObserver.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/space/SpaceObserver.java @@ -22,8 +22,8 @@ package com.ciscowebex.androidsdk.space; -import com.cisco.spark.android.model.conversation.Activity; import com.ciscowebex.androidsdk.WebexEvent; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; /** * Callback to receive the events from a {@link SpaceClient}. @@ -45,7 +45,7 @@ class SpaceCreated extends WebexEvent.Base implements SpaceEvent { private Space space; - protected SpaceCreated(Space space, Activity activity) { + protected SpaceCreated(Space space, ActivityModel activity) { super(activity); this.space = space; } @@ -66,7 +66,7 @@ class SpaceUpdated extends WebexEvent.Base implements SpaceEvent { private Space space; - protected SpaceUpdated(Space space, Activity activity) { + protected SpaceUpdated(Space space, ActivityModel activity) { super(activity); this.space = space; } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/space/SpaceReadStatus.java b/sdk/src/main/java/com/ciscowebex/androidsdk/space/SpaceReadStatus.java index 9069046f..61292ebb 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/space/SpaceReadStatus.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/space/SpaceReadStatus.java @@ -22,7 +22,7 @@ package com.ciscowebex.androidsdk.space; -import com.cisco.spark.android.model.conversation.Conversation; +import com.ciscowebex.androidsdk.internal.model.ConversationModel; import com.ciscowebex.androidsdk.utils.WebexId; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; @@ -50,7 +50,7 @@ public class SpaceReadStatus { @SerializedName("lastSeenActivityDate") private Date _lastSeenActivityDate; - protected SpaceReadStatus(Conversation conversation) { + protected SpaceReadStatus(ConversationModel conversation) { _id = new WebexId(WebexId.Type.ROOM_ID, conversation.getId()).toHydraId(); _type = conversation.isOneOnOne() ? Space.SpaceType.DIRECT : Space.SpaceType.GROUP; _lastSeenActivityDate = conversation.getLastSeenActivityDate(); diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/InternalSpace.java b/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/InternalSpace.java index f5f05fcf..e499a188 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/InternalSpace.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/InternalSpace.java @@ -1,24 +1,46 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.space.internal; -import com.cisco.spark.android.model.conversation.Activity; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; import com.ciscowebex.androidsdk.space.Space; import com.ciscowebex.androidsdk.space.SpaceObserver; class InternalSpace extends Space { static class InternalSpaceCeated extends SpaceObserver.SpaceCreated { - InternalSpaceCeated(Space space, Activity activity) { + InternalSpaceCeated(Space space, ActivityModel activity) { super(space, activity); } } static class InternalSpaceUpdated extends SpaceObserver.SpaceUpdated { - InternalSpaceUpdated(Space space, Activity activity) { + InternalSpaceUpdated(Space space, ActivityModel activity) { super(space, activity); } } - InternalSpace(Activity activity) { + InternalSpace(ActivityModel activity) { super(activity); } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/InternalSpaceReadStatus.java b/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/InternalSpaceReadStatus.java index 9d0d37ce..47feceda 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/InternalSpaceReadStatus.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/InternalSpaceReadStatus.java @@ -1,11 +1,33 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.space.internal; -import com.cisco.spark.android.model.conversation.Conversation; +import com.ciscowebex.androidsdk.internal.model.ConversationModel; import com.ciscowebex.androidsdk.space.SpaceReadStatus; class InternalSpaceReadStatus extends SpaceReadStatus { - InternalSpaceReadStatus(Conversation conversation) { + InternalSpaceReadStatus(ConversationModel conversation) { super(conversation); } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/SpaceClientImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/SpaceClientImpl.java index 6526c649..a46f13d9 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/SpaceClientImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/SpaceClientImpl.java @@ -24,212 +24,173 @@ import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import java.util.Map; -import android.content.Context; -import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.cisco.spark.android.authenticator.ApiTokenProvider; -import com.cisco.spark.android.core.ApiClientProvider; -import com.cisco.spark.android.model.ItemCollection; -import com.cisco.spark.android.model.Verb; -import com.cisco.spark.android.model.conversation.Activity; -import com.cisco.spark.android.model.conversation.Conversation; -import com.cisco.spark.android.processing.ActivityListener; import com.ciscowebex.androidsdk.CompletionHandler; -import com.ciscowebex.androidsdk.auth.Authenticator; -import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.*; +import com.ciscowebex.androidsdk.internal.model.ActivityModel; +import com.ciscowebex.androidsdk.internal.model.ConversationModel; +import com.ciscowebex.androidsdk.internal.queue.Queue; +import com.ciscowebex.androidsdk.phone.internal.PhoneImpl; import com.ciscowebex.androidsdk.utils.WebexId; import com.ciscowebex.androidsdk.space.*; -import com.ciscowebex.androidsdk.utils.http.ListBody; -import com.ciscowebex.androidsdk.utils.http.ListCallback; -import com.ciscowebex.androidsdk.utils.http.ObjectCallback; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; +import com.ciscowebex.androidsdk.internal.model.ItemsModel; -import com.ciscowebex.androidsdk_commlib.SDKCommonInjector; -import com.github.benoitdion.ln.Ln; +import com.google.gson.reflect.TypeToken; import me.helloworld.utils.collection.Maps; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.GET; -import retrofit2.http.Header; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; -import retrofit2.http.Query; -import javax.inject.Inject; +public class SpaceClientImpl implements SpaceClient, ActivityListener { -public class SpaceClientImpl implements SpaceClient { + private final PhoneImpl phone; + private SpaceObserver observer; - private Authenticator _authenticator; - - private SpaceService _service; - - private SpaceObserver _observer; - - private Context _context; - - @Inject - ActivityListener activityListener; - - @Inject - ApiTokenProvider _provider; - - @Inject - ApiClientProvider _client; - - public SpaceClientImpl(Context context, Authenticator authenticator, SDKCommonInjector injector) { - injector.inject(this); - _authenticator = authenticator; - _service = new ServiceBuilder().build(SpaceService.class); - _context = context; - activityListener.register(activity -> { - processorActivity(activity); - return null; - }); + public SpaceClientImpl(PhoneImpl phone) { + this.phone = phone; } @Override public void setSpaceObserver(SpaceObserver observer) { - _observer = observer; + this.observer = observer; + } + + public void processActivity(@NonNull ActivityModel activity) { + if (observer == null) { + return; + } + final SpaceObserver.SpaceEvent event; + if (activity.getVerb() == ActivityModel.Verb.create) { + event = new InternalSpace.InternalSpaceCeated(new InternalSpace(activity), activity); + } + else if (activity.getVerb() == ActivityModel.Verb.update) { + event = new InternalSpace.InternalSpaceUpdated(new InternalSpace(activity), activity); + } + else { + event = null; + } + if (event != null) { + Queue.main.run(() -> observer.onEvent(event)); + } } @Override public void list(@Nullable String teamId, int max, @Nullable Space.SpaceType type, @Nullable SortBy sortBy, @NonNull CompletionHandler> handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.list(s, teamId, type != null ? type.serializedName() : null, sortBy != null ? sortBy.serializedName() : null, max <= 0 ? null : max), new ListCallback(handler)); + Service.Hydra.get("room") + .with("teamId", teamId) + .with("type", type == null ? null : type.serializedName()) + .with("sortBy", sortBy == null ? null : sortBy.serializedName()) + .with("max", max <= 0 ? null : String.valueOf(max)) + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .queue(Queue.main) + .model(new TypeToken>(){}.getType()) + .error(handler) + .async((Closure>) result -> handler.onComplete(ResultImpl.success(result.getItems()))); } @Override - public void create(@NonNull String title, @Nullable String teamId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.create(s, Maps.makeMap("title", title, "teamId", teamId)), new ObjectCallback<>(handler)); + public void get(@NonNull String spaceId, @NonNull CompletionHandler handler) { + Service.Hydra.get("rooms", spaceId) + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .queue(Queue.main) + .model(Space.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override - public void get(@NonNull String spaceId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.get(s, spaceId), new ObjectCallback<>(handler)); + public void create(@NonNull String title, @Nullable String teamId, @NonNull CompletionHandler handler) { + Service.Hydra.post(Maps.makeMap("title", title, "teamId", teamId)).to("rooms") + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .queue(Queue.main) + .model(Space.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override public void update(@NonNull String spaceId, @NonNull String title, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.update(s, spaceId, Maps.makeMap("title", title)), new ObjectCallback<>(handler)); + Service.Hydra.put(Maps.makeMap("title", title)).to("rooms", spaceId) + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .queue(Queue.main) + .model(Space.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override public void delete(@NonNull String spaceId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.delete(s, spaceId), new ObjectCallback<>(handler)); + Service.Hydra.delete("rooms", spaceId) + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .queue(Queue.main) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override public void getMeetingInfo(@NonNull String spaceId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.getMeeting(s, spaceId), new ObjectCallback<>(handler)); + Service.Hydra.get("rooms", spaceId, "meetingInfo") + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .queue(Queue.main) + .model(SpaceMeetingInfo.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override public void getWithReadStatus(@NonNull String spaceId, @NonNull CompletionHandler handler) { - _client.getConversationClient().getConversationReadStatus(WebexId.translate(spaceId)).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - handler.onComplete(ResultImpl.success(new InternalSpaceReadStatus(response.body()))); - } else { - handler.onComplete(ResultImpl.error(response)); - } - } - - @Override - public void onFailure(Call call, Throwable throwable) { - handler.onComplete(ResultImpl.error(throwable)); - } - }); + Service.Conv.get("conversations", WebexId.translate(spaceId)) + .with("uuidEntryFormat", "true") + .with("personRefresh", "true") + .with("includeParticipants", "false") + .with("activitiesLimit", "0") + .with("includeConvWithDeletedUserUUID", "false") + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .queue(Queue.main) + .model(ConversationModel.class) + .error(handler) + .async((Closure) model -> { + if (model == null) { + handler.onComplete(ResultImpl.success(null)); + return; + } + handler.onComplete(ResultImpl.success(new InternalSpaceReadStatus(model))); + }); } @Override public void listWithReadStatus(int max, @NonNull CompletionHandler> handler) { - _client.getConversationClient().getConversationsReadStatus(max).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { + Service.Conv.get("conversations") + .with("uuidEntryFormat", "true") + .with("personRefresh", "true") + .with("participantsLimit", "0") + .with("activitiesLimit", "0") + .with("includeConvWithDeletedUserUUID", "false") + .with("conversationsLimit", String.valueOf(max)) + .auth(phone.getAuthenticator()) + .device(phone.getDevice()) + .queue(Queue.main) + .model(new TypeToken>(){}.getType()) + .error(handler) + .async((Closure>) model -> { + if (model == null || model.size() == 0) { + handler.onComplete(ResultImpl.success(Collections.emptyList())); + return; + } List result = new ArrayList<>(); - for (Conversation conversation : response.body().getItems()) { + for (ConversationModel conversation : model.getItems()) { result.add(new InternalSpaceReadStatus(conversation)); } handler.onComplete(ResultImpl.success(result)); - } else { - handler.onComplete(ResultImpl.error(response)); - } - } - - @Override - public void onFailure(Call> call, Throwable throwable) { - handler.onComplete(ResultImpl.error(throwable)); - } - }); - } - - private void processorActivity(Activity activity) { - if (null == _observer) { - return; - } - if (null == activity) { - Ln.e("SpaceClientImpl.processorActivity() activity is null"); - return; - } - Space space = new InternalSpace(activity); - SpaceObserver.SpaceEvent event; - switch (activity.getVerb()) { - case Verb.create: - event = new InternalSpace.InternalSpaceCeated(space, activity); - break; - case Verb.update: - event = new InternalSpace.InternalSpaceUpdated(space, activity); - break; - default: - return; - } - runOnUiThread(() -> _observer.onEvent(event), _observer); - } - - private void runOnUiThread(Runnable r, Object conditioner) { - if (conditioner == null) return; - Handler handler = new Handler(_context.getMainLooper()); - handler.post(r); - } - - private interface SpaceService { - @GET("rooms") - Call> list(@Header("Authorization") String authorization, - @Query("teamId") String teamId, - @Query("type") String type, - @Query("sortBy") String sortBy, - @Query("max") Integer max); - - @POST("rooms") - Call create(@Header("Authorization") String authorization, @Body Map parameters); - - @GET("rooms/{spaceId}") - Call get(@Header("Authorization") String authorization, @Path("spaceId") String spaceId); - - @PUT("rooms/{spaceId}") - Call update(@Header("Authorization") String authorization, @Path("spaceId") String spaceId, @Body Map parameters); - - @DELETE("rooms/{spaceId}") - Call delete(@Header("Authorization") String authorization, @Path("spaceId") String spaceId); - - @GET("rooms/{spaceId}/meetingInfo") - Call getMeeting(@Header("Authorization") String authorization, @Path("spaceId") String spaceId); - + }); } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/team/internal/TeamClientImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/team/internal/TeamClientImpl.java index 941ef7d9..05d6a234 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/team/internal/TeamClientImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/team/internal/TeamClientImpl.java @@ -22,83 +22,70 @@ package com.ciscowebex.androidsdk.team.internal; - import java.util.List; -import java.util.Map; import android.support.annotation.NonNull; - import com.ciscowebex.androidsdk.CompletionHandler; import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.queue.Queue; import com.ciscowebex.androidsdk.team.Team; import com.ciscowebex.androidsdk.team.TeamClient; -import com.ciscowebex.androidsdk.utils.http.ListBody; -import com.ciscowebex.androidsdk.utils.http.ListCallback; -import com.ciscowebex.androidsdk.utils.http.ObjectCallback; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; - +import com.ciscowebex.androidsdk.internal.model.ItemsModel; +import com.google.gson.reflect.TypeToken; import me.helloworld.utils.collection.Maps; -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.GET; -import retrofit2.http.Header; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; -import retrofit2.http.Query; public class TeamClientImpl implements TeamClient { - private Authenticator _authenticator; - - private TeamService _service; + private Authenticator authenticator; public TeamClientImpl(Authenticator authenticator) { - _authenticator = authenticator; - _service = new ServiceBuilder().build(TeamService.class); + this.authenticator = authenticator; } public void list(int max, @NonNull CompletionHandler> handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.list(s, max <= 0 ? null : max), new ListCallback<>(handler)); + Service.Hydra.get("teams").with("max", max <= 0 ? null : String.valueOf(max)) + .auth(authenticator) + .queue(Queue.main) + .model(new TypeToken>(){}.getType()) + .error(handler) + .async((Closure>) result -> handler.onComplete(ResultImpl.success(result.getItems()))); } - public void create(@NonNull String name, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.create(s, Maps.makeMap("name", name)), new ObjectCallback<>(handler)); + public void get(@NonNull String teamId, @NonNull CompletionHandler handler) { + Service.Hydra.get("teams", teamId) + .auth(authenticator) + .queue(Queue.main) + .model(Team.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } - public void get(@NonNull String teamId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.get(s, teamId), new ObjectCallback<>(handler)); + public void create(@NonNull String name, @NonNull CompletionHandler handler) { + Service.Hydra.post(Maps.makeMap("name", name)).to("teams") + .auth(authenticator) + .queue(Queue.main) + .model(Team.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } public void update(@NonNull String teamId, String name, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.update(s, teamId, Maps.makeMap("name", name)), new ObjectCallback<>(handler)); + Service.Hydra.put(Maps.makeMap("name", name)).to("teams", teamId) + .auth(authenticator) + .queue(Queue.main) + .model(Team.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } public void delete(@NonNull String teamId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.delete(s, teamId), new ObjectCallback<>(handler)); + Service.Hydra.delete("teams", teamId) + .auth(authenticator) + .queue(Queue.main) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } - - private interface TeamService { - @GET("teams") - Call> list(@Header("Authorization") String authorization, @Query("max") Integer max); - - @POST("teams") - Call create(@Header("Authorization") String authorization, @Body Map parameters); - - @GET("teams/{teamId}") - Call get(@Header("Authorization") String authorization, @Path("teamId") String teamId); - - @PUT("teams/{teamId}") - Call update(@Header("Authorization") String authorization, @Path("teamId") String teamId, @Body Map parameters); - - @DELETE("teams/{teamId}") - Call delete(@Header("Authorization") String authorization, @Path("teamId") String teamId); - } - } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/team/internal/TeamMembershipClientImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/team/internal/TeamMembershipClientImpl.java index ec31afb3..c98e0821 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/team/internal/TeamMembershipClientImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/team/internal/TeamMembershipClientImpl.java @@ -22,83 +22,77 @@ package com.ciscowebex.androidsdk.team.internal; - import java.util.List; -import java.util.Map; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.ciscowebex.androidsdk.CompletionHandler; import com.ciscowebex.androidsdk.auth.Authenticator; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.queue.Queue; import com.ciscowebex.androidsdk.team.TeamMembership; import com.ciscowebex.androidsdk.team.TeamMembershipClient; -import com.ciscowebex.androidsdk.utils.http.ListBody; -import com.ciscowebex.androidsdk.utils.http.ListCallback; -import com.ciscowebex.androidsdk.utils.http.ObjectCallback; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; +import com.ciscowebex.androidsdk.internal.model.ItemsModel; +import com.google.gson.reflect.TypeToken; import me.helloworld.utils.collection.Maps; -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.GET; -import retrofit2.http.Header; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; -import retrofit2.http.Query; public class TeamMembershipClientImpl implements TeamMembershipClient { - private Authenticator _authenticator; - - private TeamMembershipService _service; + private Authenticator authenticator; public TeamMembershipClientImpl(Authenticator authenticator) { - _authenticator = authenticator; - _service = new ServiceBuilder().build(TeamMembershipService.class); + this.authenticator = authenticator; } public void list(@Nullable String teamId, int max, @NonNull CompletionHandler> handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.list(s, teamId, max <= 0 ? null : max), new ListCallback<>(handler)); + Service.Hydra.get("team", "memberships") + .with("teamId", teamId) + .with("max", max <= 0 ? null : String.valueOf(max)) + .auth(authenticator) + .queue(Queue.main) + .model(new TypeToken>(){}.getType()) + .error(handler) + .async((Closure>) result -> handler.onComplete(ResultImpl.success(result.getItems()))); } - public void create(@NonNull String teamId, @Nullable String personId, @Nullable String personEmail, boolean isModerator, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.create(s, Maps.makeMap("teamId", teamId, "personId", personId, "personEmail", personEmail, "isModerator", isModerator)), new ObjectCallback<>(handler)); + public void get(@NonNull String membershipId, @NonNull CompletionHandler handler) { + Service.Hydra.get("team", "memberships", membershipId) + .auth(authenticator) + .queue(Queue.main) + .model(TeamMembership.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } - public void get(@NonNull String membershipId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.get(s, membershipId), new ObjectCallback<>(handler)); + public void create(@NonNull String teamId, @Nullable String personId, @Nullable String personEmail, boolean isModerator, @NonNull CompletionHandler handler) { + Service.Hydra.post(Maps.makeMap("teamId", teamId, "personId", personId, "personEmail", personEmail, "isModerator", isModerator)) + .to("team", "memberships") + .auth(authenticator) + .queue(Queue.main) + .model(TeamMembership.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } public void update(@NonNull String membershipId, boolean isModerator, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.update(s, membershipId, Maps.makeMap("isModerator", isModerator)), new ObjectCallback<>(handler)); + Service.Hydra.put(Maps.makeMap("isModerator", isModerator)) + .to("team", "memberships", membershipId) + .auth(authenticator) + .queue(Queue.main) + .model(TeamMembership.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } public void delete(@NonNull String membershipId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.delete(s, membershipId), new ObjectCallback<>(handler)); - } - - private interface TeamMembershipService { - @GET("team/memberships") - Call> list(@Header("Authorization") String authorization, @Query("teamId") String teamId, @Query("max") Integer max); - - @POST("team/memberships") - Call create(@Header("Authorization") String authorization, @Body Map parameters); - - @GET("team/memberships/{membershipId}") - Call get(@Header("Authorization") String authorization, @Path("membershipId") String membershipId); - - @PUT("team/memberships/{membershipId}") - Call update(@Header("Authorization") String authorization, @Path("membershipId") String membershipId, @Body Map parameters); - - @DELETE("team/memberships/{membershipId}") - Call delete(@Header("Authorization") String authorization, @Path("membershipId") String membershipId); + Service.Hydra.delete("team", "memberships", membershipId) + .auth(authenticator) + .queue(Queue.main) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/DateUtils.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/DateUtils.java new file mode 100644 index 00000000..20eb581c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/DateUtils.java @@ -0,0 +1,173 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.utils; + +import android.content.Context; +import com.github.benoitdion.ln.Ln; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; +import java.util.concurrent.TimeUnit; + +import static android.text.format.DateUtils.*; +import static android.text.format.DateUtils.FORMAT_12HOUR; + +public class DateUtils { + private DateUtils() { + } + + private static final int DAYS_IN_A_WEEK = 7; + public static final long SECOND_IN_MILLIS = 1000; + public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60; + public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60; + public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24; + + private static final long SEVEN_DAYS_IN_MILLIS = TimeUnit.DAYS.toMillis(7); + + public static DateFormat buildIso8601Format() { + DateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); + // Force UTC timezone so we can easily format the dates with the Z the same way the server does. + iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC")); + return iso8601Format; + } + + public static String getTimeDifference(long endTimeMillis, long startTimeMillis) { + long millis = endTimeMillis - startTimeMillis; + double seconds = millis / 1000.0; + int minutes = (int) (seconds / 60.0); + double minPlusSecondsSeconds = seconds - (minutes * 60); + return String.format(Locale.US, "%d min %1.2f secs (%1.2f secs) [$PERFTRACE.%s]", minutes, minPlusSecondsSeconds, seconds, millis > 500 ? "WARN" : "OK"); + } + + + public static String formatUTCDateString(Date date) { + if (date == null) { + return ""; + } + + DateFormat iso8601Format = buildIso8601Format(); + return iso8601Format.format(date); + } + + public static boolean isSameDay(final Date date1, final Date date2) { + Calendar cal1 = Calendar.getInstance(); + cal1.setTime(date1); + + Calendar cal2 = Calendar.getInstance(); + cal2.setTime(date2); + + return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && + cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR); + } + + public static boolean isSameWeek(final Calendar calendar1, final Calendar calendar2) { + return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR) && + Math.abs(calendar1.get(Calendar.DAY_OF_YEAR) - calendar2.get(Calendar.DAY_OF_YEAR)) < DAYS_IN_A_WEEK; + } + + public static long getTimestampDaysAgo(int days) { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(System.currentTimeMillis()); + cal.add(Calendar.DATE, -days); + cal.set(Calendar.HOUR, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + return cal.getTimeInMillis(); + } + + public static CharSequence formatTime(Context context, long time) { + long now = System.currentTimeMillis(); + long delta = now - time; + if (delta < 2000) { + return "Now"; + } else if (android.text.format.DateUtils.isToday(time)) { + return android.text.format.DateUtils.formatDateTime(context, time, FORMAT_SHOW_TIME); + } else if (delta < SEVEN_DAYS_IN_MILLIS) { + return android.text.format.DateUtils.formatDateTime(context, time, FORMAT_SHOW_TIME | FORMAT_SHOW_WEEKDAY | android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY); + } else { + return android.text.format.DateUtils.formatDateTime(context, time, FORMAT_SHOW_TIME | FORMAT_SHOW_DATE); + } + } + + public static CharSequence formatTimeToNumericDate(Context context, long time) { + long now = System.currentTimeMillis(); + long delta = now - time; + if (delta < 2000) { + return "Now"; + } else if (android.text.format.DateUtils.isToday(time)) { + return android.text.format.DateUtils.formatDateTime(context, time, FORMAT_SHOW_TIME); + } else if (delta < SEVEN_DAYS_IN_MILLIS) { + return android.text.format.DateUtils.formatDateTime(context, time, FORMAT_SHOW_WEEKDAY); + } else { + return android.text.format.DateUtils.formatDateTime(context, time, android.text.format.DateUtils.FORMAT_NUMERIC_DATE | FORMAT_SHOW_YEAR); + } + } + + public static CharSequence formatDuration(Context context, long millis) { + if (millis >= HOUR_IN_MILLIS) { + final int hours = (int) ((millis + 1800000) / HOUR_IN_MILLIS); + + // TODO need to combine hours and minutes + + return hours + " hour" + (hours > 1 ? "s" : ""); + } else if (millis >= MINUTE_IN_MILLIS) { + final int minutes = (int) ((millis + 30000) / MINUTE_IN_MILLIS); + return minutes + " minute" + (minutes > 1 ? "s" : ""); + } else { + final int seconds = (int) ((millis + 500) / SECOND_IN_MILLIS); + return seconds + " second" + (seconds > 1 ? "s" : ""); + } + } + + public static CharSequence formatTimeForRecordingTime(Context context, Date recordingDate) { + return android.text.format.DateUtils.formatDateTime(context, recordingDate.getTime(), + FORMAT_SHOW_WEEKDAY + | FORMAT_SHOW_DATE + | FORMAT_SHOW_YEAR + | FORMAT_SHOW_TIME + | FORMAT_12HOUR); + } + + public static boolean isTimestampOverdue(long timestamp, long overdueTime) { + return System.currentTimeMillis() - timestamp > overdueTime; + } + + public static Date maxDate(Date date1, Date date2) { + if (date1 == null) + return date2; + if (date2 == null) + return date1; + if (date1.after(date2)) + return date1; + return date2; + } + + public static Date addMinutesToDate(int minutes, Date date) { + long currentMillis = date.getTime(); + return new Date(currentMillis + TimeUnit.MINUTES.toMillis(minutes)); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/EmailAddress.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/EmailAddress.java index da68960e..bbe3a630 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/EmailAddress.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/EmailAddress.java @@ -23,8 +23,6 @@ package com.ciscowebex.androidsdk.utils; import android.support.annotation.NonNull; -import com.ciscowebex.androidsdk.message.Before; -import com.ciscowebex.androidsdk.message.Mention; import java.util.Objects; @@ -35,7 +33,7 @@ */ public class EmailAddress { - private String address = null; + private String address; private EmailAddress(String address) { this.address = address; @@ -79,7 +77,7 @@ public int hashCode() { return Objects.hash(address); } - private static boolean isValid(String address) { + public static boolean isValid(String address) { String ePattern = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$"; java.util.regex.Pattern p = java.util.regex.Pattern.compile(ePattern); java.util.regex.Matcher m = p.matcher(address); diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/GiphyUtils.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/GiphyUtils.java new file mode 100644 index 00000000..cba57b19 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/GiphyUtils.java @@ -0,0 +1,76 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.utils; + +import android.net.Uri; +import android.text.TextUtils; +import com.ciscowebex.androidsdk.internal.model.ImageModel; + +public abstract class GiphyUtils { + public static final String DEFAULT_GIPHY_URL = "https://giphy.com"; + private static final String DEAFULT_GIPHY_API_URL = "https://api.giphy.com/"; + private static final String MIME_TYPE_GIF = "image/gif"; + private static final String URL_PREFIX_GIPHY = "giphy.com"; + private static final String FILE_FORMAT_GIPHY = ".gif"; + + public static boolean isMimeTypeGiphy(String mimeType) { + return MIME_TYPE_GIF.equalsIgnoreCase(mimeType); + } + + public static boolean isImageGiphy(ImageModel image) { + return image != null && isUriGiphy(image.getUrl()); + } + + public static boolean isUriGiphy(Uri uri) { + return uri != null && isUriGiphy(uri.getHost()); + } + + public static boolean isUriGiphy(String host) { + return !TextUtils.isEmpty(host) && host.endsWith(URL_PREFIX_GIPHY); + } + + public static boolean containsGiphyDomain(Uri uri) { + return uri != null && containsGiphyDomain(uri.getHost()); + } + + public static boolean containsGiphyDomain(String host) { + return !TextUtils.isEmpty(host) && host.contains(URL_PREFIX_GIPHY); + } + + public static Uri getDefaultGiphyUrl() { + return Uri.parse(DEFAULT_GIPHY_URL); + } + + public static String getFileFormatGiphy() { + return FILE_FORMAT_GIPHY; + } + + public static String getMimeTypeGif() { + return MIME_TYPE_GIF; + } + + public static String getDefaultGiphyApiUrl() { + return DEAFULT_GIPHY_API_URL; + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Json.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Json.java new file mode 100644 index 00000000..ad3d163b --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Json.java @@ -0,0 +1,101 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.utils; + +import android.net.Uri; +import com.cisco.wx2.diagnostic_events.EventType; +import com.cisco.wx2.diagnostic_events.EventTypeDeserializer; +import com.ciscowebex.androidsdk.internal.adaptor.MercuryEventAdapter; +import com.ciscowebex.androidsdk.internal.adaptor.ObjectModelAdapter; +import com.ciscowebex.androidsdk.internal.adaptor.SimpleAdaptor; +import com.ciscowebex.androidsdk.internal.mercury.MercuryEvent; +import com.ciscowebex.androidsdk.internal.model.LocusKeyModel; +import com.ciscowebex.androidsdk.internal.model.ObjectModel; +import com.github.benoitdion.ln.Ln; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + +import java.lang.reflect.Type; +import java.util.Date; + +public class Json { + + private static Gson gson = buildGson(); + + public static Gson get() { + return gson; + } + + public static T fromJson(String json, Class classOfT) { + try { + return get().fromJson(json, classOfT); + } + catch (Throwable t) { + Ln.e("Parse json error: " + t); + return null; + } + } + + public static T fromJson(String json, Type typeOfT) { + try { + return get().fromJson(json, typeOfT); + } + catch (Throwable t) { + Ln.e("Parse json error: " + t); + return null; + } + } + + public static Gson buildGson() { + return new GsonBuilder() + .registerTypeAdapter(Date.class, new SimpleAdaptor.DateType()) + //.registerTypeAdapter(Instant.class, new SimpleAdaptor.InstantType()) + .registerTypeHierarchyAdapter(Uri.class, new SimpleAdaptor.UriType()) + .registerTypeHierarchyAdapter(LocusKeyModel.class, new SimpleAdaptor.LocusKeyType()) + .registerTypeAdapter(MercuryEvent.class, new MercuryEventAdapter()) + .registerTypeAdapter(MercuryEvent.Type.class, new MercuryEventAdapter.MercuryEventTypeAdapter()) + .registerTypeAdapter(ObjectModel.class, new ObjectModelAdapter()) + .registerTypeAdapter(EventType.class, new EventTypeDeserializer()) + .create(); + } + + public static JsonElement extractJsonObjectFromString(JsonElement jsonElement) { + String replaceString = jsonElement.toString().replace("\\", ""); + replaceString = replaceString.replaceAll("\"\\[", "[").replaceAll("\\]\"", "]"); + jsonElement = new JsonParser().parse(replaceString); + return jsonElement; + } + + public static String stringify(String userIdString) { + if (userIdString == null) { + return null; + } + userIdString = userIdString.replaceAll("\\[", "\\[\""); + userIdString = userIdString.replaceAll("\\]", "\"]"); + userIdString = userIdString.replaceAll(",", "\",\""); + userIdString = userIdString.replaceAll("\\s", ""); + return userIdString; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Lists.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Lists.java index 22e54839..64e773bb 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Lists.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Lists.java @@ -1,5 +1,29 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.utils; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; public final class Lists { @@ -7,6 +31,13 @@ public final class Lists { private Lists() { } + @SafeVarargs + public static ArrayList asList(T... array) { + ArrayList list = new ArrayList<>(); + Collections.addAll(list, array); + return list; + } + /** * Returns the first item in the given list, or null if not found. * diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/LoggingLock.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/LoggingLock.java new file mode 100644 index 00000000..8b9ced7c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/LoggingLock.java @@ -0,0 +1,222 @@ +package com.ciscowebex.androidsdk.utils; + +import android.annotation.SuppressLint; +import android.os.Looper; +import android.text.TextUtils; + +import com.github.benoitdion.ln.Ln; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; + +public class LoggingLock extends ReentrantLock { + + private static final long serialVersionUID = -2955432306737992011L; + + private long lockAcquired; + + // Warn if it takes longer than this to successfully acquire a lock on the main thread. + private static final long MAINTHREAD_LOCKWAIT_WARN_MS = 30; + + // Warn if it takes longer than this to successfully acquire a lock. + private static final long LOCKWAIT_WARN_MS = TimeUnit.SECONDS.toMillis(5); + + // Warn if we are still waiting to acquire a lock after this duration. + private static long deadlockWarnWaitTime = TimeUnit.SECONDS.toMillis(10); + + private long warnWaitTime; + private String lockname; + private LongHoldException lastLongHoldException; + private boolean isMainThreadWaiting; + private boolean isDebug; + + public ArrayList exceptions = new ArrayList<>(); + + // Logging to ensure that locks are always acquired in the same order to avoid deadlocks. + protected static final boolean AUDIT_LOCK_ORDER = true; + @SuppressLint("UseSparseArrays") + private static HashMap> locksByThread = new HashMap<>(); + private static HashMap> locksLockedAfterLock = new HashMap<>(); + + private static long mainThreadId = 1; + + public LoggingLock(boolean isDebug, String name, long warnTimeout) { + super(true); + lockname = name; + warnWaitTime = warnTimeout; + this.isDebug = isDebug; + Ln.d("$PERF LoggingLock initialized in " + (isDebug ? "debug" : "release") + " mode"); + locksLockedAfterLock.put(this, new HashSet<>()); + try { + mainThreadId = Looper.getMainLooper().getThread().getId(); + } catch (Throwable ignored) { + } + } + + public LoggingLock(boolean isDebug, String name) { + this(isDebug, name, LOCKWAIT_WARN_MS); + } + + public static void setDeadlockWarnWaitTime(long deadlockWarnWaitTime) { + LoggingLock.deadlockWarnWaitTime = deadlockWarnWaitTime; + } + + public void lock() { + + if (!isDebug) { + super.lock(); + return; + } + + long lockRequested = System.currentTimeMillis(); + long tid = Thread.currentThread().getId(); + + if (tid == mainThreadId) { + isMainThreadWaiting = true; + } + + // If we can't get the lock within 10 seconds, it might be a deadlock. Log an exception and continue waiting. + try { + boolean gotLock = super.tryLock(deadlockWarnWaitTime, TimeUnit.MILLISECONDS); + if (!gotLock) { + try { + throw new LongWaitException("$PERF Really Long Wait for " + lockname); + } catch (Throwable e) { + if (exceptions.size() < 100) + exceptions.add(e); + Ln.w(e, String.format("$PERF Warning: Really Long Wait for lock %s held by %s", + lockname, getOwner() == null ? "none" : getOwner().getName())); + } + lockRequested = System.currentTimeMillis(); + super.lock(); + } + } catch (InterruptedException e1) { + Ln.e(e1, "InterruptedException: "); + throw new RuntimeException(e1); + } finally { + lockAcquired = System.currentTimeMillis(); + if (tid == mainThreadId) { + isMainThreadWaiting = false; + } + } + + // Ensure that locks are always held in the same order to avoid deadlocks + if (AUDIT_LOCK_ORDER) { + LinkedList alreadyHeldLocks = locksByThread.get(tid); + if (alreadyHeldLocks == null) { + alreadyHeldLocks = new LinkedList<>(); + locksByThread.put(tid, alreadyHeldLocks); + } + + if (!alreadyHeldLocks.contains(this)) { + for (LoggingLock alreadyHeldLock : alreadyHeldLocks) { + if (alreadyHeldLock != this) + locksLockedAfterLock.get(alreadyHeldLock).add(this); + + if (locksLockedAfterLock.get(this).contains(alreadyHeldLock)) { + try { + throw new LockOrderException("Inconsistent Lock Order between " + lockname + " and " + alreadyHeldLock.lockname); + } catch (Exception e) { + Ln.w(e, "Lock ordering of " + this.lockname + " and " + alreadyHeldLock.lockname + " is not consistent"); + if (exceptions.size() < 100) + exceptions.add(e); + } + } + } + } + + alreadyHeldLocks.add(this); + } + + long waitTime = lockAcquired - lockRequested; + + try { + if (tid == mainThreadId && waitTime > MAINTHREAD_LOCKWAIT_WARN_MS) { + throw new BlockingMainThreadException("$PERF Waited " + waitTime + " ms for lock " + lockname + " on main thread"); + } else if (waitTime > warnWaitTime) { + throw new LongWaitException("$PERF Long Wait for lock " + lockname); + } + } catch (Throwable e) { + if (exceptions.size() < 100) + exceptions.add(e); + Ln.d(e, "$PERF Warning: Waited " + waitTime + " for lock " + lockname); + Ln.d(lastLongHoldException, "$PERF Warning: Long Hold for lock " + lockname); + } + } + + public void unlock() { + + if (!isDebug || lockAcquired == 0) { + super.unlock(); + return; + } + + try { + long holdTime = System.currentTimeMillis() - lockAcquired; + + long maxWaitTime = isMainThreadWaiting ? MAINTHREAD_LOCKWAIT_WARN_MS : warnWaitTime; + + if (holdTime > maxWaitTime) { + try { + throw new LongHoldException("$PERF Long Hold: " + holdTime + "ms for lock " + lockname); + } catch (LongHoldException e) { + if (exceptions.size() < 100) + exceptions.add(e); + lastLongHoldException = e; + } + } + + if (AUDIT_LOCK_ORDER) { + long tid = Thread.currentThread().getId(); + LinkedList alreadyHeldLocks = locksByThread.get(tid); + + if (alreadyHeldLocks.getLast() != this) { + try { + throw new LockOrderException("Releasing lock " + lockname + " from the middle of the list " + TextUtils.join(" => ", alreadyHeldLocks)); + } catch (Exception e) { + if (exceptions.size() < 100) + exceptions.add(e); + Ln.w(e, "Releasing lock " + lockname + " from the middle of the list"); + } + } + alreadyHeldLocks.removeLastOccurrence(this); + } + } catch (Throwable e) { + Ln.e(e); + } finally { + super.unlock(); + } + } + + public String toString() { + return lockname; + } + + public class LongHoldException extends RuntimeException { + public LongHoldException(String s) { + super(s); + } + } + + public class LongWaitException extends RuntimeException { + public LongWaitException(String s) { + super(s); + } + } + + public class LockOrderException extends RuntimeException { + public LockOrderException(String s) { + super(s); + } + } + + public class BlockingMainThreadException extends RuntimeException { + public BlockingMainThreadException(String s) { + super(s); + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Metadata.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Metadata.java new file mode 100644 index 00000000..1237ed9c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Metadata.java @@ -0,0 +1,138 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.utils; + +import android.media.ExifInterface; + +import com.github.benoitdion.ln.Ln; + +import java.io.File; +import java.io.IOException; + + +public class Metadata { + + private static class ExifTag { + private String id; + private boolean isInteresting; + + public ExifTag(String id, boolean isInteresting) { + this.id = id; + this.isInteresting = isInteresting; + } + + public String getId() { + return id; + } + + public boolean isInteresting() { + return isInteresting; + } + } + + static ExifTag[] tags = { + // Metadata that we're interested in changing (removing) + new ExifTag(ExifInterface.TAG_DATETIME, true), + new ExifTag(ExifInterface.TAG_GPS_ALTITUDE, true), + new ExifTag(ExifInterface.TAG_GPS_ALTITUDE_REF, true), + new ExifTag(ExifInterface.TAG_GPS_DATESTAMP, true), + new ExifTag(ExifInterface.TAG_GPS_LATITUDE, true), + new ExifTag(ExifInterface.TAG_GPS_LATITUDE_REF, true), + new ExifTag(ExifInterface.TAG_GPS_LONGITUDE, true), + new ExifTag(ExifInterface.TAG_GPS_LONGITUDE_REF, true), + new ExifTag(ExifInterface.TAG_GPS_PROCESSING_METHOD, true), + new ExifTag(ExifInterface.TAG_GPS_TIMESTAMP, true), + // All the other metadata + new ExifTag(ExifInterface.TAG_APERTURE, false), + new ExifTag(ExifInterface.TAG_EXPOSURE_TIME, false), + new ExifTag(ExifInterface.TAG_FLASH, false), + new ExifTag(ExifInterface.TAG_FOCAL_LENGTH, false), + new ExifTag(ExifInterface.TAG_IMAGE_LENGTH, false), + new ExifTag(ExifInterface.TAG_IMAGE_WIDTH, false), + new ExifTag(ExifInterface.TAG_ISO, false), + new ExifTag(ExifInterface.TAG_MAKE, false), + new ExifTag(ExifInterface.TAG_MODEL, false), + new ExifTag(ExifInterface.TAG_ORIENTATION, false), + new ExifTag(ExifInterface.TAG_WHITE_BALANCE, false) + }; + + + private ExifInterface exif; + + public Metadata(File file) { + if (file != null) { + try { + exif = new ExifInterface(file.getAbsolutePath()); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + + // Dump only tags we're interested in + public void dump() { + dumpTags(true); + } + + public void dumpAll() { + dumpTags(false); + } + + private void dumpTags(boolean onlyInteresting) { + if (exif == null) { + Ln.w(false, "dumpTags: ExifInterface is null"); + return; + } + + for (ExifTag tag : tags) { + if (onlyInteresting && !tag.isInteresting()) + continue; + Ln.d("tag: '%s', value: '%s'", tag.getId(), exif.getAttribute(tag.getId())); + } + } + + + // Sanitize only tags we're interested in + public void sanitize() { + sanitizeTags(true); + } + + public void sanitizeAll() { + sanitizeTags(false); + } + + private void sanitizeTags(boolean onlyInteresting) { + if (exif == null) { + Ln.w(false, "sanitizeTags: ExifInterface is null"); + return; + } + + for (ExifTag tag : tags) { + if (onlyInteresting && !tag.isInteresting()) { + continue; + } + exif.setAttribute(tag.getId(), null); + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/MimeUtils.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/MimeUtils.java new file mode 100644 index 00000000..34c7362e --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/MimeUtils.java @@ -0,0 +1,186 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.utils; + +import android.graphics.BitmapFactory; +import android.graphics.BitmapFactory.Options; +import android.text.TextUtils; +import android.webkit.MimeTypeMap; +import com.github.benoitdion.ln.Ln; +import java.io.File; +import java.io.FileInputStream; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Locale; +import okhttp3.MediaType; + +public class MimeUtils { + private static final HashMap CONTENT_TYPE_BY_EXTENSION = new HashMap<>(); + + public MimeUtils() { + } + + public static boolean isImageExt(String extension) { + return CONTENT_TYPE_BY_EXTENSION.get(extension) == MimeUtils.ContentType.IMAGE; + } + + private static void populateDrawablesByExtMap(MimeUtils.ContentType type, String[] extensions) { + for (String ext : extensions) { + CONTENT_TYPE_BY_EXTENSION.put(ext, type); + } + } + + public static String getMimeType(String path) { + if (TextUtils.isEmpty(path)) { + return ""; + } else { + String ext = getExtension(path); + return !TextUtils.isEmpty(ext) ? MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.toLowerCase(Locale.US)) : "*/*"; + } + } + + public static MediaType getMediaType(String path) { + return MediaType.parse(getMimeType(path)); + } + + public static MimeUtils.ContentType getContentTypeByFilename(String filename) { + if (TextUtils.isEmpty(filename)) { + return MimeUtils.ContentType.UNKNOWN; + } else { + MimeUtils.ContentType ret = CONTENT_TYPE_BY_EXTENSION.get(getExtension(filename.toLowerCase(Locale.US))); + return ret == null ? MimeUtils.ContentType.UNKNOWN : ret; + } + } + + public static String getExtensionByMimeType(String mimeType) { + return !mimeType.isEmpty() && !"*/*".equals(mimeType) ? MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType) : ""; + } + + public static String getExtension(String str) { + if (str == null) { + return null; + } else { + int i = str.lastIndexOf(46); + return i >= 0 ? str.substring(i + 1) : ""; + } + } + + public static boolean isEmptyOrGeneric(String mimeType) { + return TextUtils.isEmpty(mimeType) || "*/*".equals(mimeType); + } + + public static String removeFileExtension(String filename) { + if (filename == null) { + return null; + } else { + int i = filename.lastIndexOf(46); + return i >= 0 ? filename.substring(0, i) : filename; + } + } + + public static String guessExtensionForUnknownFile(File file) { + if (file.exists()) { + try { + Options op = new Options(); + op.inJustDecodeBounds = true; + BitmapFactory.decodeFile(file.getAbsolutePath(), op); + if (op.outMimeType != null) { + return getExtensionByMimeType(op.outMimeType); + } + + byte[] bytes = new byte[12]; + Arrays.fill(bytes, (byte) 0); + FileInputStream fin = new FileInputStream(file); + fin.read(bytes, 0, 12); + fin.close(); + String ftypHeader = new String(Arrays.copyOfRange(bytes, 4, 12)); + if (TextUtils.isEmpty(ftypHeader)) { + return ""; + } + + if ("ftypisom".equals(ftypHeader)) { + return "mp4"; + } + + if ("ftypMSNV".equals(ftypHeader)) { + return "mp4"; + } + + if ("ftypmp42".equals(ftypHeader)) { + return "m4v"; + } + + if (ftypHeader.startsWith("ftyp3gp")) { + return "mp4"; + } + + if (ftypHeader.startsWith("ftypqt")) { + return "mov"; + } + } catch (Throwable var5) { + Ln.i(var5, "Unknown file type"); + } + } + return ""; + } + + static { + populateDrawablesByExtMap(MimeUtils.ContentType.EXCEL, new String[]{"xls", "xlsx", "xlsm", "xltx", "xltm"}); + populateDrawablesByExtMap(MimeUtils.ContentType.POWERPOINT, new String[]{"ppt", "pptx", "pptm", "potx", "potm", "ppsx", "ppsm", "sldx", "sldm"}); + populateDrawablesByExtMap(MimeUtils.ContentType.WORD, new String[]{"doc", "docx", "docm", "dotx", "dotm"}); + populateDrawablesByExtMap(MimeUtils.ContentType.PDF, new String[]{"pdf"}); + populateDrawablesByExtMap(MimeUtils.ContentType.VIDEO, new String[]{"mp4", "m4p", "mpg", "mpeg", "3gp", "3g2", "mov", "avi", "wmv", "qt", "m4v", "flv", "m4v"}); + populateDrawablesByExtMap(MimeUtils.ContentType.AUDIO, new String[]{"mp3", "wav", "wma"}); + populateDrawablesByExtMap(MimeUtils.ContentType.IMAGE, new String[]{"jpg", "jpeg", "png", "gif"}); + populateDrawablesByExtMap(MimeUtils.ContentType.ZIP, new String[]{"zip"}); + populateDrawablesByExtMap(MimeUtils.ContentType.SKETCH, new String[]{"sketch"}); + } + + public enum ContentType { + IMAGE, + EXCEL, + POWERPOINT, + WORD, + PDF, + VIDEO, + AUDIO, + ZIP, + UNKNOWN, + SKETCH; + + ContentType() { + } + + public boolean shouldTranscode() { + switch(this) { + case POWERPOINT: + case WORD: + case PDF: + case EXCEL: + return true; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/NetworkUtils.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/NetworkUtils.java new file mode 100644 index 00000000..27fb303c --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/NetworkUtils.java @@ -0,0 +1,92 @@ +package com.ciscowebex.androidsdk.utils; + +import android.support.annotation.Nullable; +import com.github.benoitdion.ln.Ln; +import okhttp3.Headers; +import okhttp3.Response; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; + +public class NetworkUtils { + + public static String getLocalIpAddress() { + try { + for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { + NetworkInterface intf = en.nextElement(); + for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { + InetAddress inetAddress = enumIpAddr.nextElement(); + if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address + && !intf.getDisplayName().startsWith("usbnet")) { + return inetAddress.getHostAddress(); + } + } + } + } catch (Exception ex) { + Ln.e("getLocalIpAddress()", ex.toString()); + } + return null; + } + + public static String resolveHostName(String hostName) { + InetAddress serverAddr; + try { + serverAddr = InetAddress.getByName(hostName); + } catch (java.net.UnknownHostException exception) { + Ln.e("resolveHostName()", exception.toString()); + return ""; + } + return serverAddr.getHostAddress(); + } + + @Nullable + public static String getTrackingId(@Nullable Response response) { + if (response == null) { + return null; + } + Headers headers = response.headers(); + if (headers == null) { + return null; + } + return response.headers().get("trackingid"); + } + + /** + * Extract the 429 'Retry-After' header value if it exists, and make sure it's in the allowed + * range. If the response doesn't include the Retry-After header, the value can't be parsed, or + * the value is negative, 0 is returned. + * + * @param response + * @return The value or 0 if the value is invalid + */ + public static int get429RetryAfterSeconds(final Response response, final int minimum, final int maximum) { + if (minimum > maximum) { + throw new IllegalArgumentException("Minimum (" + minimum + ") should be smaller than maximum (" + maximum + ")"); + } + + if (response == null || response.code() != 429) { + return 0; + } + + final String retryAfterHeader = response.headers().get("Retry-After"); + if (retryAfterHeader == null) { + return 0; + } + + final int retrySeconds; + try { + retrySeconds = Integer.parseInt(retryAfterHeader); + } catch (final NumberFormatException e) { + Ln.w("Failed parsing Retry-After header"); + return 0; + } + + if (retrySeconds < 0) { + return 0; + } + + return Math.min(Math.max(retrySeconds, minimum), maximum); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/PSUtils.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/PSUtils.java new file mode 100644 index 00000000..ea6a5220 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/PSUtils.java @@ -0,0 +1,112 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.utils; + +import com.github.benoitdion.ln.Ln; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class PSUtils { + public static void iteratePSresults(String psName, String matchName, PSResultHandler handler) { + BufferedReader reader = null; + try { + // Query process list, which returns: + // USER PID PPID VSIZE RSS WCHAN PC NAME + // u0_a141 7716 1 884 180 ffffffff 00000000 S logcat + // u0_a141 8028 1 884 180 ffffffff 00000000 S logcat + // u0_a141 8211 8189 884 180 ffffffff 00000000 S logcat + // Orphaned processes have a parent (PPID) of 1 + java.lang.Process ps = new ProcessBuilder("ps", psName).start(); + int exitCode = ps.waitFor(); + if (exitCode != 0) { + Ln.w("ps command failed to list duplicate instances (exit code=%d)", exitCode); + } + reader = new BufferedReader(new InputStreamReader(ps.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + if (line.endsWith((matchName != null) ? matchName : psName)) { + String[] element = line.split("\\s+"); + if (element.length == 9) { + PSResult result = new PSResult(element[0], Integer.parseInt(element[1]), Integer.parseInt(element[2]), element[8]); + handler.onResult(result); + } + + } + } + } catch (IOException ex) { + Ln.w("Encountered an IOException while cleaning up duplicate apps: %s", ex.getMessage()); + handler.onException(ex); + } catch (InterruptedException ex) { + Ln.w("The process searching for duplicate apps was interrupted: %s", ex.getMessage()); + handler.onException(ex); + } catch (NumberFormatException ex) { + Ln.w("The failed to convert pid/ppid's to int's", ex.getMessage()); + handler.onException(ex); + } finally { + try { + if (reader != null) + reader.close(); + } catch (IOException ex) { + handler.onException(ex); + } + } + } + + public static class PSResult { + private String user; + private int pid; + private int ppid; + private String name; + + public PSResult(String user, int pid, int ppid, String name) { + this.user = user; + this.pid = pid; + this.ppid = ppid; + this.name = name; + } + + public String getUser() { + return user; + } + + public int getPid() { + return pid; + } + + public int getPpid() { + return ppid; + } + + public String getName() { + return name; + } + } + + public interface PSResultHandler { + void onResult(PSResult result); + + void onException(Exception ex); + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/TrackingIdGenerator.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/TrackingIdGenerator.java new file mode 100644 index 00000000..064db0cd --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/TrackingIdGenerator.java @@ -0,0 +1,61 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.utils; + +import com.ciscowebex.androidsdk.BuildConfig; +import com.github.benoitdion.ln.Ln; + +import java.util.Locale; +import java.util.UUID; + +public class TrackingIdGenerator { + + private final String base; + private int counter; + private String currentTrackingId; + + public TrackingIdGenerator() { + base = UUID.randomUUID().toString(); + currentTrackingId = ""; + } + + public synchronized String nextTrackingId() { + String trackingId; + if (BuildConfig.INTEGRATION_TEST) { + trackingId = String.format(Locale.US, "ITCLIENT_%s_%d", base, counter); + } else { + trackingId = String.format(Locale.US, "CLIENT_%s_%d", base, counter); + } + counter++; + if (counter > 65536) { + counter = 0; + } + currentTrackingId = trackingId; + Ln.report(null, "Tracking-Id: " + currentTrackingId); + return trackingId; + } + + public String currentTrackingId() { + return currentTrackingId; + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/UriUtils.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/UriUtils.java new file mode 100644 index 00000000..7bb7714b --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/UriUtils.java @@ -0,0 +1,305 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.ciscowebex.androidsdk.utils; + +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.github.benoitdion.ln.Ln; +import me.helloworld.utils.Checker; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class UriUtils { + + public static final String DEEP_LINKING_ACTIVATE_PATH = "activate"; + public static final String DEEP_LINKING_ACTIVATE_PARAM_EMAIL = "email"; + public static final String DEEP_LINKING_ACTIVATE_PARAM_TOKEN = "t"; + public static final String DEEP_LINKING_ACTIVATE_PARAM_VERIFICATION_TYPE = "vt"; + + private static final String DEEP_LINKING_BASE_URL_REGEX = "(web\\.ciscospark\\.com|teams\\.webex\\.com)\\/"; + private static final String DEEP_LINKING_ID_REGEX = "\\/[A-Za-z0-9._%+-]+"; + + public static final String DEEP_LINKING_MEET_PATH = "meet"; + public static final String DEEP_LINKING_MEET_URL_REGEX = "https:\\/\\/" + DEEP_LINKING_BASE_URL_REGEX + DEEP_LINKING_MEET_PATH + DEEP_LINKING_ID_REGEX; + + public static final String DEEP_LINKING_ROOMS_PATH = "rooms"; + public static final String DEEP_LINKING_SPACES_PATH = "spaces"; + public static final String DEEP_LINKING_SPACES_URL_REGEX = "(https?:\\/\\/)?" + DEEP_LINKING_BASE_URL_REGEX + "(#\\/)?(" + DEEP_LINKING_ROOMS_PATH + "|" + DEEP_LINKING_SPACES_PATH + ")" + DEEP_LINKING_ID_REGEX + "(\\/chat|\\/)?"; + + public static final String DEEP_LINKING_TEAMS_PATH = "teams"; + public static final String DEEP_LINKING_TEAMS_URL_REGEX = "(https?:\\/\\/)?" + DEEP_LINKING_BASE_URL_REGEX + "(#\\/)?" + DEEP_LINKING_TEAMS_PATH + DEEP_LINKING_ID_REGEX + "(\\/chat|\\/)?"; + + public static final String PMR_URL_REGEX_HTTP = "https?:\\/\\/([\\w\\-._~:/?#\\[\\]@!$&'()*+,;=%]+)\\.webex\\.com\\/meet" + DEEP_LINKING_ID_REGEX; + public static final String PMR_URL_REGEX_SIP = "(sips?:)?(([A-Za-z0-9._%+-]+)@([\\w\\-._~:/?#\\[\\]@!$&'()*+,;=%]+)\\.webex\\.com)"; + + // TODO: The differences between this regex and the PMR_URL_REGEX_HTTP above needs to be resolved into a single regex used throughout the app. The regex above + // is used for matching on clickable links within a conversation. The regex below is the same as that found in meeting_rules.json and is used by MeetingHub/JoinHub. + private static final String PMR_URL_REGEX_HTTP_FOR_MEETING_HUB = "(?:https?://)?(?:[\\w\\-._~:/?#\\[\\]@!$&'()*+,;=%]+)\\.webex\\.com/(?:meet|join)" + DEEP_LINKING_ID_REGEX; + + public static final String WEBEX_SPACE_MEETING_REGEX = "https?:\\/\\/([\\w\\-._~:/?#\\[\\]@!$&'()*+,;=%]+)\\.webex\\.com\\/m\\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"; + + // https://avatar-intb.ciscospark.com/avatar/api/v1/profile/f0b30c25-038c-45b6-840a-09dcd8d29bef?s=96 + public static final String AVATAR_REMOTE_URI_REGEX = "(.)*(ciscospark|wbx2)\\.com\\/avatar\\/api\\/v[1-9]\\/profile" + DEEP_LINKING_ID_REGEX + "(\\?s=[0-9]+)?"; + + public static String removeUrlBase(URI base, URI url) { + String baseString = base.toString().replace("http://", "").replace("https://", ""); + String urlString = url.toString().replace("http://", "").replace("https://", ""); + if (urlString.startsWith(baseString)) { + return urlString.substring(baseString.length() + 1); + } else { + return url.toString(); + } + } + + public static Uri parseFromURI(URI javaUri) { + if (javaUri != null) + return Uri.parse(javaUri.toString()); + else + return null; + } + + public static String toString(URI javaUri) { + Uri androidUri = parseFromURI(javaUri); + return UriUtils.toString(androidUri); + } + + public static Uri parseIfNotNull(String uriString) { + try { + if (!TextUtils.isEmpty(uriString)) + return Uri.parse(uriString); + } catch (Exception e) { + Ln.w("Failed parsing uri"); + } + + return null; + } + + public static ArrayList parseIfNotNull(ArrayList uriStrings) { + if (uriStrings == null) { + return null; + } + + ArrayList parsedUris = new ArrayList<>(); + + for (String uriString : uriStrings) { + Uri parsedUri = parseIfNotNull(uriString); + + parsedUris.add(parsedUri); + } + + return parsedUris; + } + + public static String toString(Uri uri) { + if (uri == null) { + return null; + } + return uri.toString(); + } + + public static String toNonNullString(Uri uri) { + + if (uri == null) { + return ""; + } + + return uri.toString(); + } + + public static String stripHttps(Uri uri) { + if (uri == null) { + return null; + } + if (uri.toString().startsWith("https://")) + return uri.toString().replaceFirst("https://", ""); + + return uri.toString(); + } + + public static boolean equals(Uri lhs, Uri rhs) { + if (lhs == rhs) + return true; + if (lhs == null || rhs == null) + return false; + + return lhs.equals(rhs); + } + + public static boolean equals(String lhs, Uri rhs) { + return equals(rhs, lhs); + } + + public static boolean equals(Uri lhs, String rhs) { + if (lhs == null || rhs == null) + return false; + + return lhs.toString().equals(rhs); + } + + public static UUID extractUUID(Uri uri) { + if (uri == null) + return null; + String getUUIDFromUri = uri.getLastPathSegment(); + if (getUUIDFromUri == null) + return null; + + try { + return UUID.fromString(getUUIDFromUri); + } catch (Exception e) { + return null; + } + } + + public static URI toURI(String uri) { + try { + return new URI(uri); + } catch (URISyntaxException e) { + return null; + } + } + + public static URI toURI(Uri uri) { + try { + return new URI(uri.toString()); + } catch (URISyntaxException e) { + return null; + } + } + + public static boolean isSupportedDeepLinkingUri(@NonNull Uri uri) { + return isMeetDeepLinkingUri(uri) || isSpacesDeepLinkingUri(uri) || isTeamsDeepLinkingUri(uri) || isActivateDeepLinkingUri(uri); + } + + public static boolean isMeetDeepLinkingUri(@NonNull Uri uri) { + return compileRegex(DEEP_LINKING_MEET_URL_REGEX, uri) || compileRegex(WEBEX_SPACE_MEETING_REGEX, uri); + } + + public static boolean isSpacesDeepLinkingUri(@NonNull Uri uri) { + return compileRegex(DEEP_LINKING_SPACES_URL_REGEX, uri); + } + + public static boolean isTeamsDeepLinkingUri(@NonNull Uri uri) { + return compileRegex(DEEP_LINKING_TEAMS_URL_REGEX, uri); + } + + public static boolean isActivateDeepLinkingUri(@NonNull Uri uri) { + if (!uri.isHierarchical()) { + return false; + } + List pathSegments = uri.getPathSegments(); + Set queryParameters = uri.getQueryParameterNames(); + return pathSegments != null && queryParameters != null + && pathSegments.contains(DEEP_LINKING_ACTIVATE_PATH) + && queryParameters.contains(DEEP_LINKING_ACTIVATE_PARAM_EMAIL) + && queryParameters.contains(DEEP_LINKING_ACTIVATE_PARAM_TOKEN); + } + + private static boolean compileRegex(String regexString, @NonNull Uri uri) { + return Pattern.compile(regexString, Pattern.CASE_INSENSITIVE).matcher(uri.toString()).matches(); + } + + public static String extractDeepLinkId(@NonNull Uri uri, String deepLinkTag) { + uri = Uri.parse(uri.toString().replaceAll("/#/", "/")); + + List pathSegments = uri.getPathSegments(); + if (pathSegments == null || Checker.isEmpty(deepLinkTag)) { + return null; + } + + int tagIndex = pathSegments.indexOf(deepLinkTag); + if (tagIndex < 0 || tagIndex == pathSegments.size() - 1) { + return null; + } + + return pathSegments.get(tagIndex + 1); + } + + public static String extractUUIDFromRemoteUri(@NonNull Uri uri) { + if (!Pattern.compile(AVATAR_REMOTE_URI_REGEX, Pattern.CASE_INSENSITIVE).matcher(uri.toString()).matches()) { + return null; + } + + return uri.getLastPathSegment(); + } + + + public static String convertWebExPmrHttpUrlToSipAddress(@Nullable String pmrUrl) { + if (TextUtils.isEmpty(pmrUrl)) { + return null; + } + + String sipAddress = null; + String url = pmrUrl.trim(); + Matcher matcher = Pattern.compile(PMR_URL_REGEX_HTTP_FOR_MEETING_HUB, Pattern.CASE_INSENSITIVE).matcher(url); + if (matcher.find()) { + Uri uri = Uri.parse(url.toLowerCase()); + if (uri.getScheme() == null) { + // the URL does not have a scheme supplied. Parameter came into method as + // "go.webex.com/meet/user_name". Need to add a scheme to use the Uri class. + url = "http://" + url; + uri = Uri.parse(url.toLowerCase()); + } + + sipAddress = uri.getLastPathSegment() + "@" + uri.getHost(); + } + + return sipAddress; + } + + /** + * When pulling the meta data from a site, before we go out to the site there needs to be a scheme + * on the URL. So if the user did not enter a site (or it did not parse for whatever reason), we + * will use this method to prepend it with http:// + * + * @param urlString The URL that may or may not need an prepended scheme + * @return The URL that was passed in, now with a scheme if it didn't have one before + */ + public static String prependSchemeIfNecessary(final String urlString) { + String returnUrl = urlString; + + Uri uri = Uri.parse(urlString); + if (uri.getScheme() == null) { + returnUrl = "http://" + urlString; + } + + return returnUrl; + } + + /** + * Take a url and ensure it as appended with a slash, as retrofit expects a baseUrl in that format + */ + public static Uri properFormatBaseUrl(String url) { + Uri potentialImproperFormattedUri = Uri.parse(url); + return Uri.withAppendedPath(potentialImproperFormattedUri, ""); + } +} + diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Utils.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Utils.java index c2513cf3..5f322aa5 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Utils.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/Utils.java @@ -22,26 +22,34 @@ package com.ciscowebex.androidsdk.utils; +import android.content.Context; import android.os.Build; import android.support.annotation.Nullable; -import android.util.Base64; -import com.cisco.spark.android.util.Strings; +import android.view.WindowManager; import com.ciscowebex.androidsdk.Webex; +import com.ciscowebex.androidsdk.utils.log.DebugLn; +import com.ciscowebex.androidsdk.utils.log.NoLn; +import com.ciscowebex.androidsdk.utils.log.WarningLn; +import com.github.benoitdion.ln.InfoLn; +import com.github.benoitdion.ln.NaturalLog; +import com.github.benoitdion.ln.ReleaseLn; +import com.webex.wme.MediaSessionAPI; +import com.github.benoitdion.ln.Ln; +import me.helloworld.utils.Checker; +import me.helloworld.utils.Strings; +import okhttp3.logging.HttpLoggingInterceptor; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; - +import java.io.*; import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.regex.Pattern; /** * An utility class. * * @since 0.1 */ - public class Utils { private Utils(){} @@ -53,10 +61,6 @@ public static T checkNotNull(@Nullable T object, String message) { return object; } - public static String timestampUTC() { - return DateTime.now(DateTimeZone.UTC).toString(); - } - public static String versionInfo() { String tempUserAgent = String.format("%s/%s (Android %s; %s %s / %s %s;)", Webex.APP_NAME, Webex.APP_VERSION, @@ -66,16 +70,7 @@ public static String versionInfo() { Strings.capitalize(Build.BRAND), Strings.capitalize(Build.MODEL) ); - return Strings.stripInvalidHeaderChars(tempUserAgent); - } - - public static String encode(String id) { - if (id == null || id.isEmpty()) - return id; - - String encodeString = "ciscospark://us/PEOPLE/" + id; - return new String(Base64.encode(encodeString.getBytes(), - Base64.NO_PADDING | Base64.URL_SAFE | Base64.NO_WRAP)); + return stripInvalidHeaderChars(tempUserAgent); } public static Map toMap(Object o) { @@ -106,4 +101,191 @@ public static Map toMap(Object o) { } return result; } + + private static final Pattern pattern = Pattern.compile("[^\\x20-\\x7E]"); + + public static String stripInvalidHeaderChars(String str) { + return pattern.matcher(str).replaceAll(""); + } + + public static String join(final String delimiter, final Collection objs) { + if (objs == null || objs.isEmpty()) { + return ""; + } + final Iterator iter = objs.iterator(); + final StringBuilder buffer = new StringBuilder(toString(iter.next())); + + while (iter.hasNext()) { + final T obj = iter.next(); + if (!Checker.isEmpty(toString(obj))) buffer.append(delimiter).append(toString(obj)); + } + return buffer.toString(); + } + + public static String join(final String delimiter, final T... objects) { + return join(delimiter, Arrays.asList(objects)); + } + + public static String toString(InputStream input) { + StringWriter sw = new StringWriter(); + copy(new InputStreamReader(input), sw); + return sw.toString(); + } + + public static String toString(Reader input) { + StringWriter sw = new StringWriter(); + copy(input, sw); + return sw.toString(); + } + + public static String toString(final Object o) { + return toString(o, ""); + } + + public static String toString(final Object o, final String def) { + return o == null ? def : + o instanceof InputStream ? toString((InputStream) o) : + o instanceof Reader ? toString((Reader) o) : + o instanceof Object[] ? join(", ", (Object[]) o) : + o instanceof Collection ? join(", ", (Collection) o) : o.toString(); + } + + public static int copy(Reader input, Writer output) { + long count = copyLarge(input, output); + return count > Integer.MAX_VALUE ? -1 : (int) count; + } + + public static long copyLarge(Reader input, Writer output) throws RuntimeException { + try { + char[] buffer = new char[1024 * 4]; + long count = 0; + int n; + while (-1 != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + return count; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static String[] chunk(String str, int chunkSize) { + if (Checker.isEmpty(str) || chunkSize == 0) { + return new String[0]; + } + // return str.split("(?<=\\G.{" + chunkSize + "})"); + final int len = str.length(); + final int arrayLen = ((len - 1) / chunkSize) + 1; + final String[] array = new String[arrayLen]; + for (int i = 0; i < arrayLen; ++i) { + array[i] = str.substring(i * chunkSize, Math.min((i * chunkSize) + chunkSize, len)); + } + return array; + } + + public static int getScreenRotation(Context context) { + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + return windowManager != null ? windowManager.getDefaultDisplay().getRotation() : 0; + } + + public static T getFirst(T[] array) { + if (array.length == 0) { + return null; + } + return array[0]; + } + + public static HttpLoggingInterceptor.Level toHttpLogLevel(Webex.LogLevel logLevel) { + if (logLevel == Webex.LogLevel.NO) { + return HttpLoggingInterceptor.Level.NONE; + } + else if (logLevel == Webex.LogLevel.ERROR || logLevel == Webex.LogLevel.WARNING || logLevel == Webex.LogLevel.INFO) { + return HttpLoggingInterceptor.Level.BASIC; + } + else if (logLevel == Webex.LogLevel.DEBUG_NO_HTTP_DETAILS) { + return HttpLoggingInterceptor.Level.HEADERS; + } + else { + return HttpLoggingInterceptor.Level.BODY; + } + } + + public static NaturalLog toLnLog(Webex.LogLevel logLevel) { + NaturalLog logger = new DebugLn(); + if (logLevel != null) { + switch (logLevel) { + case NO: + logger = new NoLn(); + break; + case ERROR: + logger = new ReleaseLn(); + break; + case WARNING: + logger = new WarningLn(); + break; + case INFO: + logger = new InfoLn(); + break; + case DEBUG_NO_HTTP_DETAILS: + case DEBUG: + case VERBOSE: + case ALL: + logger = new DebugLn(); + break; + } + } + return logger; + } + + public static MediaSessionAPI.TraceLevelMask toTraceLevelMask(Webex.LogLevel level) { + MediaSessionAPI.TraceLevelMask mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_WARNING; + if (level != null) { + switch (level) { + case NO: + case ERROR: + case WARNING: + case INFO: + case DEBUG_NO_HTTP_DETAILS: + case DEBUG: + mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_NOTRACE; + break; + case VERBOSE: + mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_INFO; + break; + case ALL: + mask = MediaSessionAPI.TraceLevelMask.TRACE_LEVEL_MASK_DETAIL; + } + } + return mask; + } + + public static String readFile(File file) { + try { + BufferedReader br = new BufferedReader(new FileReader(file)); + StringBuilder sb = new StringBuilder(); + String line = br.readLine(); + + while (line != null) { + sb.append(line); + sb.append("\n"); + line = br.readLine(); + } + br.close(); + return sb.toString(); + } catch (IOException e) { + Ln.e(e, "Error reading file: " + file.getAbsolutePath()); + return null; + } + } + + public static File mkdir(String dirName) { + File logDir = new File(dirName); + if (!logDir.exists()) { + if (!logDir.mkdirs()) + Ln.e("Failed to make directory"); + } + return logDir; + } + } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/WebexId.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/WebexId.java index e69a2d6e..94519985 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/WebexId.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/WebexId.java @@ -1,8 +1,32 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.utils; -import android.text.TextUtils; import android.util.Base64; +import me.helloworld.utils.Checker; +import me.helloworld.utils.annotation.StringPart; +import java.nio.charset.StandardCharsets; import java.util.Objects; public class WebexId { @@ -56,11 +80,15 @@ public static String translate(String hydraId) { public static WebexId from(String hydraId) { try { - String decodeStr = new String(Base64.decode(hydraId, Base64.URL_SAFE), "UTF-8"); - if (TextUtils.isEmpty(decodeStr)) { + byte[] bytes = Base64.decode(hydraId, Base64.URL_SAFE); + if (Checker.isEmpty(bytes)) { + return null; + } + String strings = new String(bytes, StandardCharsets.UTF_8); + if (Checker.isEmpty(strings)) { return null; } - String[] subs = decodeStr.split("/"); + String[] subs = strings.split("/"); return new WebexId(Type.getEnum(subs[subs.length - 2]), subs[subs.length - 1]); } catch (Exception ignored) { } @@ -80,6 +108,14 @@ public boolean is(Type type) { return this.type == type; } + @Override + public String toString() { + return "WebexId{" + + "id='" + id + '\'' + + ", type=" + type + + '}'; + } + @Override public int hashCode() { return Objects.hash(getId()); diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ContentDownloadMonitor.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ContentDownloadMonitor.java new file mode 100644 index 00000000..4ac099a6 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ContentDownloadMonitor.java @@ -0,0 +1,111 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.utils.http; + +import com.ciscowebex.androidsdk.internal.Closure; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigDecimal; + +public class ContentDownloadMonitor { + + public enum DownloadState { + START, COMPLETE, CANCEL, FAIL + } + + private final static long NO_LENGTH = -1; + private final static int KB = 1024; + private long contentLength = NO_LENGTH; + private long downloadedLength = NO_LENGTH; + + private volatile DownloadState state; + + public ContentDownloadMonitor() { + setDownloadState(DownloadState.START); + } + + public DownloadState getState() { + return state; + } + + public float getProgress() { + if (contentLength == NO_LENGTH) { + return -1; + } + if (downloadedLength == NO_LENGTH) { + return 0; + } + BigDecimal downloadedDecimal = new BigDecimal(downloadedLength); + BigDecimal contentDecimal = new BigDecimal(contentLength); + return downloadedDecimal.divide(contentDecimal, 2, BigDecimal.ROUND_HALF_UP).floatValue(); + } + + public void cancelDownload() { + setDownloadState(DownloadState.CANCEL); + } + + public long getContentLength() { + return contentLength; + } + + public long getDownloadedLength() { + return downloadedLength; + } + + public boolean isCanceled() { + return state.equals(DownloadState.CANCEL); + } + + private void setDownloadState(DownloadState state) { + this.state = state; + } + + public void download(InputStream is, OutputStream os, long contentLength, Closure callback) throws IOException { + this.contentLength = contentLength; + byte [] data = new byte[KB]; + InputStream bis = new BufferedInputStream(is, KB * 2); + int count; + try { + while ((count = bis.read(data)) != -1 && !isCanceled()) { + downloadedLength += count; + os.write(data, 0, count); + if (callback != null) { + callback.invoke(downloadedLength); + } + } + os.flush(); + os.close(); + bis.close(); + if (!isCanceled()) { + setDownloadState(DownloadState.COMPLETE); + } + + } catch (Throwable e) { + setDownloadState(DownloadState.FAIL); + throw e; + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/CountedTypedOutput.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/CountedTypedOutput.java new file mode 100644 index 00000000..f73e1957 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/CountedTypedOutput.java @@ -0,0 +1,90 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.utils.http; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.OutputStream; + +import com.ciscowebex.androidsdk.internal.Closure; +import okhttp3.MediaType; +import okhttp3.RequestBody; +import okio.BufferedSink; + +public class CountedTypedOutput extends RequestBody { + private static final int BUFFER_SIZE = 4096; + private final String mimeType; + protected final File file; + + private int percentage; + private boolean complete; + private Closure callback; + + public CountedTypedOutput(String mimeType, File file, Closure callback) { + this.mimeType = mimeType; + this.file = file; + this.callback = callback; + } + + @Override + public long contentLength() { + return file.length(); + } + + public int getProgress() { + return percentage; + } + + public boolean isCompleted() { + return complete; + } + + @Override + public MediaType contentType() { + return MediaType.parse(mimeType); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + writeTo(sink.outputStream()); + } + + protected void writeTo(OutputStream out) throws IOException { + byte[] buffer = new byte[BUFFER_SIZE]; + try (FileInputStream fileInputStream = new FileInputStream(file)) { + long bytesRead = 0; + long size = file.length(); + int read; + while ((read = fileInputStream.read(buffer)) != -1) { + bytesRead += read; + percentage = (int) ((bytesRead / (double) size) * 100); + if (callback != null) { + callback.invoke(bytesRead); + } + out.write(buffer, 0, read); + } + complete = true; + } + } +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/DefaultHeadersInterceptor.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/DefaultHeadersInterceptor.java index 85c55ccf..707b5931 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/DefaultHeadersInterceptor.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/DefaultHeadersInterceptor.java @@ -24,30 +24,25 @@ import java.io.IOException; +import com.ciscowebex.androidsdk.utils.TrackingIdGenerator; import com.ciscowebex.androidsdk.utils.Utils; import okhttp3.Interceptor; -import okhttp3.Request; import okhttp3.Response; public class DefaultHeadersInterceptor implements Interceptor { - protected String _userAgent; - - public DefaultHeadersInterceptor() { - _userAgent = Utils.versionInfo(); - } + protected String userAgent = Utils.versionInfo(); + protected TrackingIdGenerator trackingIdGenerator = new TrackingIdGenerator(); @Override public Response intercept(Chain chain) throws IOException { - Request original = chain.request(); - Request request = original.newBuilder() - .header("User-Agent", _userAgent) - .header("Spark-User-Agent", _userAgent) + okhttp3.Request.Builder requestBuilder = chain.request().newBuilder() + .addHeader("Accept", "application/json") + .header("User-Agent", userAgent) + .header("Spark-User-Agent", userAgent) .header("Content-Type", "application/json; charset=utf-8") - .method(original.method(), original.body()) - .build(); - - return chain.proceed(request); + .header("TrackingID", trackingIdGenerator.nextTrackingId()); + return chain.proceed(requestBuilder.build()); } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/HttpClient.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/HttpClient.java new file mode 100644 index 00000000..fe74fe63 --- /dev/null +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/HttpClient.java @@ -0,0 +1,109 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.ciscowebex.androidsdk.utils.http; + +import android.support.annotation.NonNull; +import com.ciscowebex.androidsdk.utils.NetworkUtils; +import com.github.benoitdion.ln.Ln; +import okhttp3.*; +import okhttp3.logging.HttpLoggingInterceptor; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.*; +import java.util.concurrent.TimeUnit; + +public class HttpClient { + + private static final int MAX_LENGTH = 2048; + + private static HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(message -> { + if (message.length() > MAX_LENGTH) { + int chunkCount = message.length() / MAX_LENGTH; + for (int i = 0; i <= chunkCount; i++) { + int max = MAX_LENGTH * (i + 1); + if (max >= message.length()) { + Ln.d("[HTTP] " + message.substring(MAX_LENGTH * i)); + } else { + Ln.d("[HTTP] " + message.substring(MAX_LENGTH * i, max)); + } + } + } + else { + Ln.d("[HTTP] " + message); + } + }); + + public static void setLogLevel(HttpLoggingInterceptor.Level level) { + loggingInterceptor.setLevel(level); + } + + public static @NonNull OkHttpClient client = makeClient(loggingInterceptor); + + public static OkHttpClient makeClient() { + return makeClient(loggingInterceptor); + } + + public static OkHttpClient makeClient(HttpLoggingInterceptor loggingInterceptor) { + return new OkHttpClient.Builder() + .addInterceptor(new DefaultHeadersInterceptor()) + .followRedirects(false) + .followSslRedirects(false) + .addInterceptor(chain -> { + Request request = chain.request(); + Response response = chain.proceed(request); + if (response.code() >= 300 && response.code() <= 399) { + request = request.newBuilder().url(Objects.requireNonNull(response.header("Location"))).build(); + Ln.i("Handling redirect, url = " + request.url()); + response = chain.proceed(request); + } + return response; + }) + .addInterceptor(new Interceptor() { + + private final Object lock = new Object(); + + @Override + public Response intercept(@NotNull Chain chain) throws IOException { + Request request = chain.request(); + Response response = chain.proceed(request); + if (response.code() == 429) { + int retrySeconds = NetworkUtils.get429RetryAfterSeconds(response, 5, 3600); + if (retrySeconds > 0) { + synchronized (lock) { + try { lock.wait(retrySeconds * 1000); } catch (Throwable ignored) {} + } + response = chain.proceed(request); + } + } + return response; + } + }) + .addInterceptor(loggingInterceptor) + .readTimeout(3, TimeUnit.MINUTES) + .writeTimeout(60, TimeUnit.SECONDS) + .connectTimeout(3, TimeUnit.MINUTES) + .build(); + } + +} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ListenerCallback.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ListenerCallback.java deleted file mode 100644 index c27306db..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ListenerCallback.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.ciscowebex.androidsdk.utils.http; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -/** - * Created by qimdeng on 4/4/18. - */ - -public class ListenerCallback implements Callback { - - private boolean hasHandleUnauthError = false; // only handle unauth error once - - private ServiceBuilder.UnauthErrorListener _listener; - public void setUnauthErrorListener(ServiceBuilder.UnauthErrorListener listener){ - _listener = listener; - } - - @Override - public void onResponse(Call call, Response response) { - // -- Implementation Class should override this method - } - - @Override - public void onFailure(Call call, Throwable t) { - // -- Implementation Class should override this method - } - - protected boolean checkUnauthError(Response response){ - if (response.code() == 401 && !hasHandleUnauthError && _listener != null) { - hasHandleUnauthError = true; - _listener.onUnauthError(response); - return true; - } - return false; - } -} \ No newline at end of file diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/RetryCallAdapterFactory.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/RetryCallAdapterFactory.java deleted file mode 100644 index 03856d41..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/RetryCallAdapterFactory.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.ciscowebex.androidsdk.utils.http; - -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import com.github.benoitdion.ln.Ln; -import okhttp3.Request; -import retrofit2.Call; -import retrofit2.CallAdapter; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; - -/** - * Retries calls for 429 request error. - */ -public class RetryCallAdapterFactory extends CallAdapter.Factory { - private final ScheduledExecutorService mExecutor; - - private RetryCallAdapterFactory() { - mExecutor = Executors.newScheduledThreadPool(1); - } - - public static RetryCallAdapterFactory create() { - return new RetryCallAdapterFactory(); - } - - @Override - public CallAdapter get(final Type returnType, Annotation[] annotations, Retrofit retrofit) { - final CallAdapter delegate = retrofit.nextCallAdapter(this, returnType, annotations); - return new CallAdapter() { - @Override - public Type responseType() { - return delegate.responseType(); - } - - @Override - public Object adapt(Call call) { - return delegate.adapt(new RetryingCall<>(call, mExecutor, Integer.MAX_VALUE)); - } - }; - } - - static final class RetryingCall implements Call { - private final Call mDelegate; - private final ScheduledExecutorService mExecutor; - private final int mMaxRetries; - - public RetryingCall(Call delegate, ScheduledExecutorService executor, int maxRetries) { - mDelegate = delegate; - mExecutor = executor; - mMaxRetries = maxRetries; - } - - @Override - public Response execute() throws IOException { - return mDelegate.execute(); - } - - @Override - public void enqueue(Callback callback) { - mDelegate.enqueue(new RetryingCallback<>(mDelegate, callback, mExecutor, mMaxRetries)); - } - - @Override - public boolean isExecuted() { - return false; - } - - @Override - public void cancel() { - mDelegate.cancel(); - } - - @Override - public boolean isCanceled() { - return false; - } - - @SuppressWarnings("CloneDoesntCallSuperClone" /* Performing deep clone */) - @Override - public Call clone() { - return new RetryingCall<>(mDelegate.clone(), mExecutor, mMaxRetries); - } - - @Override - public Request request() { - return null; - } - } - - // Exponential backoff approach from https://developers.google.com/drive/web/handle-errors - static final class RetryingCallback implements Callback { - private static final int DEFAULT_RETRY_AFTER = 60; - private static final int MAX_RETRY_AFTER = 3600; - private final int mMaxRetries; - private final Call mCall; - private final Callback mDelegate; - private final ScheduledExecutorService mExecutor; - private final int mRetries; - - RetryingCallback(Call call, Callback delegate, ScheduledExecutorService executor, int maxRetries) { - this(call, delegate, executor, maxRetries, 0); - } - - RetryingCallback(Call call, Callback delegate, ScheduledExecutorService executor, int maxRetries, int retries) { - mCall = call; - mDelegate = delegate; - mExecutor = executor; - mMaxRetries = maxRetries; - mRetries = retries; - } - - private void retryCall(int interval) { - mExecutor.schedule(() -> { - Ln.d("retryCall: " + (mRetries + 1)); - final Call call = mCall.clone(); - call.enqueue(new RetryingCallback<>(call, mDelegate, mExecutor, mMaxRetries, mRetries + 1)); - }, interval, TimeUnit.SECONDS); - } - - private int get429RetryAfterSeconds(final Response response) { - if (response == null || response.code() != 429) { - return 0; - } - - final String retryAfterHeader = response.headers().get("Retry-After"); - if (retryAfterHeader == null) { - return DEFAULT_RETRY_AFTER; - } - - final int retrySeconds; - try { - retrySeconds = Integer.parseInt(retryAfterHeader); - } catch (final NumberFormatException e) { - Ln.w("Failed parsing Retry-After header"); - return DEFAULT_RETRY_AFTER; - } - - if (retrySeconds <= 0) { - return DEFAULT_RETRY_AFTER; - } - - return Math.min(retrySeconds, MAX_RETRY_AFTER); - } - - @Override - public void onResponse(Call call, Response response) { - // Retry 429 request - int interval = get429RetryAfterSeconds(response); - Ln.d("onResponse: " + response.code() + " retry interval: " + interval + " retries: " + mRetries); - if (interval > 0 && mRetries < mMaxRetries) { - retryCall(interval); - } else { - mDelegate.onResponse(call, response); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - mDelegate.onFailure(call, t); - } - } -} \ No newline at end of file diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ServiceBuilder.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ServiceBuilder.java deleted file mode 100644 index 0f4c368b..00000000 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/ServiceBuilder.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.ciscowebex.androidsdk.utils.http; - -/* - * Copyright 2016-2020 Cisco Systems Inc - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -import com.cisco.spark.android.core.LoggingInterceptor; -import com.ciscowebex.androidsdk.CompletionHandler; -import com.ciscowebex.androidsdk.auth.Authenticator; -import com.ciscowebex.androidsdk.internal.ResultImpl; -import com.github.benoitdion.ln.Ln; -import com.google.gson.Gson; - -import java.util.ArrayList; -import java.util.List; - -import okhttp3.Interceptor; -import okhttp3.OkHttpClient; -import okhttp3.logging.HttpLoggingInterceptor; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; - -/** - * Created by zhiyuliu on 31/08/2017. - */ - -public class ServiceBuilder { - - public static final String HYDRA_URL = "https://api.ciscospark.com/v1/"; -// public static final String HYDRA_URL = "https://apialpha.ciscospark.com/v1/"; - - private String _baseURL = HYDRA_URL; - - private Gson _gson; - - private List _interceptors = new ArrayList<>(1); - - private boolean _interceptorChanged = false; - - public ServiceBuilder() { - _interceptors.add(new DefaultHeadersInterceptor()); - HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(message -> Ln.i("RetrofitLog", "retrofitBack = " + message)); - if (LoggingInterceptor.LogHTTPBody) { - loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); - } - else { - loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); - } - _interceptors.add(loggingInterceptor); - } - - public ServiceBuilder baseURL(String url) { - _baseURL = url; - return this; - } - - public ServiceBuilder gson(Gson gson) { - _gson = gson; - return this; - } - - public ServiceBuilder interceptor(Interceptor interceptor) { - if (!_interceptorChanged) { - _interceptors.clear(); - _interceptorChanged = true; - } - if (interceptor != null) { - _interceptors.add(interceptor); - } - return this; - } - - public T build(Class service) { - OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); - for (Interceptor interceptor : _interceptors) { - httpClient.addInterceptor(interceptor); - } - OkHttpClient client = httpClient.build(); - Retrofit retrofit = new Retrofit.Builder() - .baseUrl(_baseURL) - .addCallAdapterFactory(RetryCallAdapterFactory.create()) - .addConverterFactory(_gson == null ? GsonConverterFactory.create() : GsonConverterFactory.create(_gson)) - .client(client) - .build(); - return retrofit.create(service); - } - - public static void async(Authenticator authenticator, CompletionHandler doAuthFailed, Closure doPrepareReqeust, ListenerCallback doHandleResponse) { - async(authenticator, doAuthFailed, false, doPrepareReqeust, doHandleResponse); - } - - public static void async(Authenticator authenticator, CompletionHandler doAuthFailed, boolean notifyFailed, Closure doPrepareReqeust, ListenerCallback doHandleResponse) { - authenticator.getToken(result -> { - String token = result.getData(); - if (token == null) { - if (doPrepareReqeust != null && notifyFailed) { - doPrepareReqeust.invoke(null); - } - if (doAuthFailed != null) { - doAuthFailed.onComplete(ResultImpl.error(result.getError())); - } - } - else { - if (doHandleResponse != null) { - doHandleResponse.setUnauthErrorListener(response -> { - if (!handleUnauthError(authenticator, doAuthFailed, doPrepareReqeust, doHandleResponse)){ - if (doPrepareReqeust != null && notifyFailed) { - doPrepareReqeust.invoke(null); - } - if (doAuthFailed != null) { - doAuthFailed.onComplete(ResultImpl.error(response)); - } - } - }); - } - Call call = doPrepareReqeust.invoke("Bearer " + token); - if (call != null) { - call.enqueue(doHandleResponse); - } - } - }); - } - - private static boolean handleUnauthError(Authenticator authenticator, CompletionHandler doAuthFailed, Closure doPrepareReqeust, Callback doHandleResponse) { - Ln.d("handleUnauthError"); - if (authenticator != null) { - Ln.d("refreshToken"); - authenticator.refreshToken(result -> { - String token = result.getData(); - if (token == null) { - if (doPrepareReqeust != null) { - doPrepareReqeust.invoke(null); - } - if (doAuthFailed != null) { - doAuthFailed.onComplete(ResultImpl.error(result.getError())); - } - } - else { - Call call = doPrepareReqeust.invoke("Bearer " + token); - if (call != null) { - call.enqueue(doHandleResponse); - } - } - }); - return true; - } - return false; - } - - public interface Closure

{ - Call invoke(P p); - } - - public interface UnauthErrorListener { - void onUnauthError(Response response); - } -} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/DebugLn.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/DebugLn.java index ee40f59d..82493e70 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/DebugLn.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/DebugLn.java @@ -26,10 +26,6 @@ import com.github.benoitdion.ln.BaseLn; -/** - * Created by zhiyuliu on 03/09/2017. - */ - public class DebugLn extends BaseLn { @Override public void v(Throwable throwable) { diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/LogCaptureUtil.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/LogCaptureUtil.java index 8a024589..3d36f854 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/LogCaptureUtil.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/LogCaptureUtil.java @@ -1,12 +1,34 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.utils.log; import android.content.Context; import android.util.Log; -import com.cisco.spark.android.BuildConfig; -import com.cisco.spark.android.core.PSUtils; -import com.cisco.spark.android.util.FileUtils; +import com.ciscowebex.androidsdk.BuildConfig; import com.ciscowebex.androidsdk.Webex; +import com.ciscowebex.androidsdk.utils.PSUtils; +import com.ciscowebex.androidsdk.utils.Utils; import com.github.benoitdion.ln.Ln; import java.io.BufferedReader; @@ -16,7 +38,6 @@ import java.io.InputStreamReader; import java.util.concurrent.atomic.AtomicBoolean; - /** * LogFilePrint reads from logcat and writes the output to files. *

@@ -114,11 +135,11 @@ public File getCurrentLogFile() { } public synchronized String getLogString() { - StringBuilder result = new StringBuilder(""); + StringBuilder result = new StringBuilder(); for (int i = maxLogFiles - 1; i >= 0; i--) { File aLogFile = buildLogFile(i); if (aLogFile.exists()) { - result.append(FileUtils.readFile(aLogFile)); + result.append(Utils.readFile(aLogFile)); } } return result.toString(); @@ -129,7 +150,7 @@ public File[] getAllLogFiles() { } public File getLogDirectory() { - return FileUtils.mkdir(getLogDirectoryName()); + return Utils.mkdir(getLogDirectoryName()); } public void run() { @@ -200,7 +221,7 @@ private void rotateLogFiles() { } private File buildLogFile(int i) { - return new File(getLogDirectoryName() + LOG_FILE_NAME + Integer.toString(i) + LOG_FILE_EXT); + return new File(getLogDirectoryName() + LOG_FILE_NAME + i + LOG_FILE_EXT); } protected String getLogDirectoryName() { diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/MediaLog.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/MediaLog.java index 48465eda..f867ef04 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/MediaLog.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/MediaLog.java @@ -1,16 +1,31 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.utils.log; import android.util.Log; import com.github.benoitdion.ln.Ln; -/** - * Created with IntelliJ IDEA. - * User: kt - * Date: 29/11/2017 - * Time: 00:47 - */ - public class MediaLog { private MediaLog(){} diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/NoLn.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/NoLn.java index 4c473d07..cd040593 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/NoLn.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/NoLn.java @@ -24,10 +24,6 @@ import com.github.benoitdion.ln.BaseLn; -/** - * Created by zhiyuliu on 03/09/2017. - */ - public class NoLn extends BaseLn { @Override diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/WarningLn.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/WarningLn.java index de2e64b8..4f6cd5a4 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/WarningLn.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/log/WarningLn.java @@ -26,10 +26,6 @@ import com.github.benoitdion.ln.BaseLn; -/** - * Created by zhiyuliu on 03/09/2017. - */ - public class WarningLn extends BaseLn { @Override diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/webhook/Webhook.java b/sdk/src/main/java/com/ciscowebex/androidsdk/webhook/Webhook.java index ba2424a0..06b4016f 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/webhook/Webhook.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/webhook/Webhook.java @@ -25,7 +25,6 @@ import java.util.Date; import com.google.gson.Gson; -import com.google.gson.annotations.SerializedName; /** * A data type presents a Webhook at Cisco Webex for Developer. @@ -35,32 +34,15 @@ */ public class Webhook { - @SerializedName("id") - private String _id; - - @SerializedName("name") - private String _name; - - @SerializedName("targetUrl") - private String _targetUrl; - - @SerializedName("resource") - private String _resource; - - @SerializedName("event") - private String _event; - - @SerializedName("filter") - private String _filter; - - @SerializedName("secret") - private String _secret; - - @SerializedName("created") - private Date _created; - - @SerializedName("status") - private String _status; + private String id; + private String name; + private String targetUrl; + private String resource; + private String event; + private String filter; + private String secret; + private Date created; + private String status; @Override public String toString() { @@ -73,7 +55,7 @@ public String toString() { * @since 0.1 */ public String getId() { - return _id; + return id; } /** @@ -81,7 +63,7 @@ public String getId() { * @since 0.1 */ public String getName() { - return _name; + return name; } /** @@ -89,7 +71,7 @@ public String getName() { * @since 0.1 */ public String getTargetUrl() { - return _targetUrl; + return targetUrl; } /** @@ -97,7 +79,7 @@ public String getTargetUrl() { * @since 0.1 */ public String getResource() { - return _resource; + return resource; } /** @@ -105,7 +87,7 @@ public String getResource() { * @since 0.1 */ public String getEvent() { - return _event; + return event; } /** @@ -113,7 +95,7 @@ public String getEvent() { * @since 0.1 */ public String getFilter() { - return _filter; + return filter; } /** @@ -121,7 +103,7 @@ public String getFilter() { * @since 0.1 */ public String getSecret() { - return _secret; + return secret; } /** @@ -129,6 +111,6 @@ public String getSecret() { * @since 0.1 */ public Date getCreated() { - return _created; + return created; } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/webhook/internal/WebhookClientImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/webhook/internal/WebhookClientImpl.java index 3bf1f2a0..b06bddde 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/webhook/internal/WebhookClientImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/webhook/internal/WebhookClientImpl.java @@ -23,89 +23,88 @@ package com.ciscowebex.androidsdk.webhook.internal; import java.util.List; -import java.util.Map; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.ciscowebex.androidsdk.CompletionHandler; import com.ciscowebex.androidsdk.auth.Authenticator; -import com.ciscowebex.androidsdk.utils.http.ListBody; -import com.ciscowebex.androidsdk.utils.http.ListCallback; -import com.ciscowebex.androidsdk.utils.http.ObjectCallback; -import com.ciscowebex.androidsdk.utils.http.ServiceBuilder; +import com.ciscowebex.androidsdk.internal.Closure; +import com.ciscowebex.androidsdk.internal.Service; +import com.ciscowebex.androidsdk.internal.model.ItemsModel; +import com.ciscowebex.androidsdk.internal.ResultImpl; +import com.ciscowebex.androidsdk.internal.queue.Queue; import com.ciscowebex.androidsdk.webhook.Webhook; import com.ciscowebex.androidsdk.webhook.WebhookClient; - +import com.google.gson.reflect.TypeToken; import me.helloworld.utils.collection.Maps; -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.DELETE; -import retrofit2.http.GET; -import retrofit2.http.Header; -import retrofit2.http.POST; -import retrofit2.http.PUT; -import retrofit2.http.Path; -import retrofit2.http.Query; public class WebhookClientImpl implements WebhookClient { - private Authenticator _authenticator; - - private WebhookService _service; + private Authenticator authenticator; private static final String KEY_TARGET_URL = "targetUrl"; public WebhookClientImpl(Authenticator authenticator) { - _authenticator = authenticator; - _service = new ServiceBuilder().build(WebhookService.class); + this.authenticator = authenticator; } public void list(int max, @NonNull CompletionHandler> handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.list(s, max <= 0 ? null : max), new ListCallback<>(handler)); + Service.Hydra.get("webhooks") + .with("max", max <= 0 ? null : String.valueOf(max)) + .auth(authenticator) + .queue(Queue.main) + .model(new TypeToken>(){}.getType()) + .error(handler) + .async((Closure>) result -> handler.onComplete(ResultImpl.success(result.getItems()))); } - public void create(@NonNull String name, @NonNull String targetUrl, @NonNull String resource, @NonNull String event, @Nullable String filter, @Nullable String secret, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.create(s, Maps.makeMap("name", name, KEY_TARGET_URL, targetUrl, "filter", filter, "secret", secret, "resource", resource, "event", event)), new ObjectCallback<>(handler)); + public void get(@NonNull String webhookId, @NonNull CompletionHandler handler) { + Service.Hydra.get("webhooks", webhookId) + .auth(authenticator) + .queue(Queue.main) + .model(Webhook.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } - public void get(@NonNull String webhookId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.get(s, webhookId), new ObjectCallback<>(handler)); + public void create(@NonNull String name, @NonNull String targetUrl, @NonNull String resource, @NonNull String event, @Nullable String filter, @Nullable String secret, @NonNull CompletionHandler handler) { + Service.Hydra.post(Maps.makeMap("name", name, KEY_TARGET_URL, targetUrl, "filter", filter, "secret", secret, "resource", resource, "event", event)) + .to("webhooks") + .auth(authenticator) + .queue(Queue.main) + .model(Webhook.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } public void update(@NonNull String webhookId, @NonNull String name, @NonNull String targetUrl, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.update(s, webhookId, Maps.makeMap("name", name, KEY_TARGET_URL, targetUrl)), new ObjectCallback<>(handler)); + Service.Hydra.put(Maps.makeMap("name", name, KEY_TARGET_URL, targetUrl)) + .to("webhooks", webhookId) + .auth(authenticator) + .queue(Queue.main) + .model(Webhook.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } @Override public void update(@NonNull String webhookId, @NonNull String name, @NonNull String targetUrl, @Nullable String secret, @Nullable String status, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.update(s, webhookId, Maps.makeMap("name", name, KEY_TARGET_URL, targetUrl, "secret", secret, "status", status)), new ObjectCallback<>(handler)); + Service.Hydra.put(Maps.makeMap("name", name, KEY_TARGET_URL, targetUrl, "secret", secret, "status", status)) + .to("webhooks", webhookId) + .auth(authenticator) + .queue(Queue.main) + .model(Webhook.class) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } public void delete(@NonNull String webhookId, @NonNull CompletionHandler handler) { - ServiceBuilder.async(_authenticator, handler, s -> - _service.delete(s, webhookId), new ObjectCallback<>(handler)); + Service.Hydra.delete("webhooks", webhookId) + .auth(authenticator) + .queue(Queue.main) + .error(handler) + .async((Closure) result -> handler.onComplete(ResultImpl.success(result))); } - private interface WebhookService { - @GET("webhooks") - Call> list(@Header("Authorization") String authorization, @Query("max") Integer max); - - @POST("webhooks") - Call create(@Header("Authorization") String authorization, @Body Map parameters); - - @GET("webhooks/{webhookId}") - Call get(@Header("Authorization") String authorization, @Path("webhookId") String webhookId); - - @PUT("webhooks/{webhookId}") - Call update(@Header("Authorization") String authorization, @Path("webhookId") String webhookId, @Body Map parameters); - - @DELETE("webhooks/{webhookId}") - Call delete(@Header("Authorization") String authorization, @Path("webhookId") String webhookId); - } } diff --git a/sdk/src/main/jniLibs/arm64-v8a/libaudiopairing.so b/sdk/src/main/jniLibs/arm64-v8a/libaudiopairing.so new file mode 100755 index 0000000000000000000000000000000000000000..3720178b103fd03b4423045a9464ccbe535830d9 GIT binary patch literal 96640 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 literal 0 HcmV?d00001 diff --git a/sdk/src/main/jniLibs/arm64-v8a/libc++_shared.so b/sdk/src/main/jniLibs/arm64-v8a/libc++_shared.so new file mode 100755 index 0000000000000000000000000000000000000000..d8637792ef0244f9936fb1042a68742208e52db7 GIT binary patch literal 919888 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%0DR*a$JNS{)%9crM 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%0Dy#=PEFxW+hxAvDnw_j9e@=bymy-Wu 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ɽ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:vw&YEcA<=)=u*K?bP-LYgA4doqElu3N*QA; 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ith*bD^^^K9%_#K>(lEZg^!d6 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%0DwdnI8pr+BF^6ulNU+TUi5)eg4{AiT;6B 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 Z}|($ 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 LwMTM(d({5}I|C`G literal 0 HcmV?d00001 diff --git a/sdk/src/main/jniLibs/armeabi-v7a/libaudiopairing.so b/sdk/src/main/jniLibs/armeabi-v7a/libaudiopairing.so new file mode 100755 index 0000000000000000000000000000000000000000..b993424260492273f133d528fd8c78d775999fec GIT binary patch literal 75668 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

SJ(IWq;A04%U*`wP5cY$k2u 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 V$*c*JZt|~dFN}lbi^!Cd{{`03bK(F1 literal 0 HcmV?d00001 diff --git a/sdk/src/main/jniLibs/armeabi-v7a/libc++_shared.so b/sdk/src/main/jniLibs/armeabi-v7a/libc++_shared.so new file mode 100755 index 0000000000000000000000000000000000000000..c13b0451e1dcb382b2ea238e11614b0d695fbf77 GIT binary patch literal 558904 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 z z1rcYU1xcUb^DKz!ac5TR+N41na!E%SdlljVoJ_PKt@83*|xjfpjV%3s@Oc_JVGc+eB+vpkV@cp`n4C(@2*qVPnTBc49X z6WMjBC-OW!5gZYoNT212w8InWvpkVq(i3^|Fi&IxJQ3!_@iD7SKiLgo8L*7V)P2@=>5Ztwk-d>ig*URgPX%gFZuj@8 za#)o1XM>~K>646yPcpupJ_%C2NcBGu%xkA#l4bcN*iXT(w0{xLjAMI{BmZ5&qIUWz!{-}&$oWPdaz1zam-kra z#M2(jgecC#l7k;UvVG8N$%?M&gO5ymv+Hob<2U?Z5nS$bT6yqTL7kF9XJV z-AD3YN)E9zhx;#|XJ@`_e`mmWy!-#V{ha}$q+42;0mI)tY+;Vn-x)BbS$iDZ-x)9p zy8j;io!P1DUplgd`L4Bn*uo4LU0p}EF#rAiodKh^>+jv)88GhX`tR=V3>b5|{^$BT z1IE72VXN`C_IC!1w>l5C7aw#U$zFWX{!ZZI-~TK7J1(og;~47ilv(|qm(kz(8u~je zR)6Qxd6QF`)#Ev|uM_dOlL5p}0_cCM)K^7cXTVt7xe->f(X!b;+{NC`l<3Sp2YWm1 z^;U1E$i%Nm_BhbnIi{80U5~!}tUd?(JMbtRIrz5iQH*FC7eRj~lJ4)scfW|I(5m1m z@OB*PYgUgZJNgo~;V71Ov7VlDMD}?Gj0!|997BDc0i(P#W%YSj5>(J+Mq0e(o)Zgb|pJ$f?eIBprC_E+75L^<)HTscq!UOPrRvvRIa*bZkF7|pZ ze(t!)tVkDnJ*%u^*Jmr1?Aj^co z*W);>*R!~heH#aQJua))GhlS=N%wjjR$&WpUe7P!sWjl4Hb_q;a#Y0j zR3hUdNcAE$?Wsg^BJflqxe@G__EhlQ&+h>Z7$mHZo(f6;HTuQ+LIcJPh^FA!9^@$PsYFIchR+92<)HJyQ#t5-^i$U zxgA>>FsAN#dJ=m@6QVc|OK#XxiJUSiE4s1I;dj`cN@lue6j_A`ivvBQK~H5c*0iEw zuwOJ6{i1_C6_k=HvG0nah!6L~*|BMp9ww<0YL^o#zu`!U2-9OxGfAZ9_!^H||z^pqUv`wSSbC24saRahA`wJO5$Zoo!#r?)VO}JGUmMR5#*oSsVOUJH|58w5(3+ zp;iYmmTJr9n3l~!L=`s2v}_I{s)(@&o0Hf*vpOAPaSX*+USeMzThDAdlD#<-@e*lo zPEAUCv+{`crr6r&#$kJ7TJ~o9A@&9_7QboPn^xExLs1r34?D^N zOXH}{t+t{puri3Uz{+^4ttiVEurXB~GpmbHKZvrRy%$x_f<}~uZQZUpMp?d`Wx0w` zmg=LbttbnuO8N|lvJ9O8Q5JCqMp?eBEh+3s+Y-cSt8=P{;tw=yvk#`cqRs^04YG)`?3k!lsZ8hx&BekDpKi(JiV`Jh_`>`!? zB>OS%ke<$w?Z-bNPCH;!C5Ga(mgh1Qr)_Wf{5UQAmZ3N;A|XeN)52>xJWjjy2yxm0 z<8;I~hU2sY#;n9&i_@aVV(oKSoOah|#A(}y;a-=vdeA)Pyi_>oYoH*?%spB^v zDNcJzYRcw=2coMFU4XP`HdKEvmEBL~N62aNpqVR71Y+~nXm zE#fABpE&L2ro-d3{l<>&BgSdlj}WKb^~K_}{l@z4L*umlMq~GXJx=?Nd;imKT-`ln zSN;dz|MVL(5Y-sAEB(gQ?!RVN`i*>RpTq3R_Rp{@U*P>uKcX66&aQmk`=3)%xi1~r zu4KJ*uwCglwsw6NT*QdVfAjmFej}&r zFuU>(fB(~Oyw-U{yYe@@|LHf@bslb4)_4BDVOJJ+4%wCeL4T#+I0i8mX;;Q~{&l;O zW9@U8UHKdQm3||(=gZlZ&+}JirMjDrWLIXTl1+!&l?FS)@`c|k|6To+exqW~-`ij5 zH*}6nN!ykGHh-nx*q1!auKW-9D~-t`+Lgb_U%5AVxLsL?@dy9a_saiBf93rD72{R< z4bMU2Rr(G0UmdT4JF0`W=rFtTH~A~A9be9_e4f8DE46*gk?qRww;XC$9=9VYU)Zkv zo&A-CfA{e!{YJ?@V7v-E%*0`K<$u6mS)VwfUHO~*mB?Y^Rr-y4|Az4@`$yfcS7Ric zV|9IxN4aY1G0y9aL`LLsy*`@CJmvJ2Cg!D+bYg3t;))7!S7!8-3RL*j|BYG6E+RU}(`lb3gdcQFzu`8kGwI|e` ztr%^0YcfM?{`lpH>(O7#%Z|R4P*a}jal6M){9ZC6Q`h&lm&Gz`qX{*3D}SpOzc=D) z&p{sFHOEHA#`r%6`Hop)SdMxH_m( zZ$~m8-mc@!9XR4_^qw7ClTLLDj_T3>(*AglJ8zNc9&uiHYf@$2g7X`@?w*&~`rCxc z@aQ~_S+-`B6({W@}~`O8dqcZ=z2e#6YGL!NS8oj0`=SN6O0IPQg}`t*V;^1==o$`_D#u=T5o%Bp1bYUggW(sc`XTbk-O=a7<>8d?srXh z&1#+3);=#UirkLDQD=Xn;D)3l0}&(W-(Z{OuioUWU8FBWiLQ;~{CLYX7oWWNygHtK z!~LVZ6Q6UgLrr2tuL~o3bK1Qa)yF;Vu=dEsx$+~AVib*Aao>L9mUvX}`^dSD;{u}? z(YyEOXIdkAzxFj}!L*ski&l|vOc`77y`<*a%)Cq~OE|O{v2yF&SwrLUW~Huu8AsL1 z^~|;B=yLmaUVg(=HB8I=3F^*KjuDZKKM>OqW2lC z-MDwhpoHw2^0vPQjS?F3HvW)iZy(+MYiOj6X-lWs+p`!`LJCsH48HNg80oC^m7kbs z&Ke#)yc%QO`;3O}KbY?3o%sGc33c{Ws1rx#N$tOa#vRL?j6vG$D|p{zPHN|UgET8Q z!?`@l$_;aQaBi|0f3kBUBT!r7d3KICCRp`&FisHdNK20t>@&{q&gjV>$+uCjVVoUH_eiOfY~dOTWAG@5WM za-W_~`*>GfzUs-x&#e^cBYU)wxI<3e+T$Ko9L+|a&$sftT;H*qXM-)pyR<%ITi4Ne zm&Pr~2SypX@jearOIIGeL0Vho985#LtZ{~!h>D}6b5mP5hrw;XQ~S&AbQ%2PZFZj# z={n42r#{nWw;pD*TWMkbs?Fa1rEPZW5p4GMzmv_zo53U4?A9-DvoRVQE$LvJ-DkXq z9`LZu?!#D*&$roq#_QG|huZ8uV{7LZx7l+(*JeN2NE>{(&3>%$P@COn)F4XoH`(mg zLHk_LdIX!@ik5XGo6YZjp3UZdU)W}k?>xk2w|<7rZv70K&GFi{mHc8hd+(kj*zDHN zu-UDjVY98=9KmLDZ1;b`X0P7!IX1iXb8PnZzqiev^O-g~u;;JX?AFh*+1tOo&35lO zlFc5!=f7&RW20*HRrZXN^*yfa^{|JInrZs_WTuv$ZSrn}b4@yj=9+BGPtP5uiB3}CJXhm@jUrma!scyc&Jn5Z0vd^r>D!)uX^et zj{x|4SSzs4a^&fw z-Q)G@-FM)V=3m~a<+x^kWzs#tV_S=lWv*9q%dElN7(2#I8a&o3#XP#Pb5+pY#$&As z@@VN1VX@ug^e2NOq7PyVk208-VAJjRv=Uo2f6XSpK3xx@d`gouCfx?_HwX{8&zO^J zv*x^|=f0fr-1=mOdV1pWpu2tW`?K)C~Z=teqIIjx^ThpoJaw!PE27hW%pBs_QdC z9h<_uCr~Cs$CFNFURItue`a-t70muC#;a!M)REKk9#o7=FbyLejEiFr4!nfdx3hGyOL zVWh>O(NWwlpBcr-Ib@8;@T{A(KRj$(UAeHUu&tgU+nSDG#H|R1Y1`Hnj*a>0*u|(J z+sdc~TNNW0gZ6dRLH2b{Vn?T%_*SRN-P`r2+_ZhIx9n?9w6#;608dmy$_Z%;`^nBT zVsGR7gWq-Rq;;i@^;kCcy-0bdToY4!95`QW zV%o;m!741me(uw-r?o9@WnaZ!uOMe1!ph#Z`!#&h{I7I6a@{j=){J|CMXgU_Pv*as zTW1aC%Gd!PH)HUKe>!2<*7AsJf;?v0*1l)k+MU?K;|%60*z_xW+J>#1V?1a(pT#%? z`nH4C_6a*4f#?xt8qONBw%J40w$|EXD(vl(yRolITiko&w6kM{#dTq(;E3mjViFUN zpT!!v3?(<1qtYf^|HOs3&J&JcaW8rqC88Z}bIYyms2yQ-FN^2!nW%AVCVFOv+TAG5 z{3gl?wa>F#rI)>Pux2LhY{qt!WA60W;I_2gMX7T83HJU&IUi^3!7@iY0_jxtv8}q! z*lF*X``LEaG~(SX5!BPraVPI&iJ+cXbGf{$2Fq&9PSo5)q~^AzQ-@M$cUzFgn*CyS z*EC-3-W2Bjfif97&di;>KX@gF=IYqb%+=V>%oXkKV6Hyj?s{N%hvO2av6yiQ%wT*h zI3>ywKpuzMaoX~tub=tL&diB9(e1dK+@}w=k)9pJrTLcSWnF4$M9;j`?pX_%ed z<6t{%8eN@#Z#!Jqcw{@g&e|^RuxY%6RUZzw!zLmS=~W;8ciQ2y&O8-$oVsUljSH0y5dcz8q^m;bFClKcq_Rj9trqUYqq98|IYq=_twF_r%NASHbP$+%xd)^ zCc-`(#e{b|Gh@j7J8g0o;-KWn)Ncj%9X`V5 zM)jw^WTg8Vkx?V{GZtj%WA#A6O+89wwR#a>*b;YJYuTt&W#d;C-ld= z3#~IwF^xJL-)o)y3LJmp#jc^V`*8MEL#em(?2Cqv_=CpPx_9BR=iF)K-861ZM)bOY z9EY0X9>|{jLQ-XG135+G7nbQ)B{j`7u1WH$GI{h{Oyi1V2F^Mc*LaYre*n4T_JT!|hpxyopV$8J9aEH2uUz{K{tuQnOK((Vp1wSo z)pl@+2O7OY*M@s)s9a|sQm&rH?CH)n|4gk?E6RvD7v54j%N*^|B90aKtw$?Tx9XfgY#&=jpXg2aIUb>+V~N zYnxQc*?7QsyJ;xz2OaNs9jeE#@mSLrzVjrtC(ab=}D7A_xfj6w8! zOyzujzv+cctmnnmwgz*fAvf1|R5CYO?m4d?-8|qNgItVB=fd68g!6wF=f8gF{5RnI zAAG8s)az@{*!O*xnrxq+--&EFV7&Edy0xW0{oeYNbMxd4*V?A{;N>Zc@1seLC_Q#k=3PO{JVQ?whNgAEBS$J9qS?vO5b3 zu_99K+)=wGE@VVgp}oxLC|H=kVD-eu=DK#}FVJe#fEIGbu1%?cRx_^5Q8PWPtq?^8eAhSfP3x#AZCBHl_$XK+_%ewRcJ5S1o|U_Oi37$p$lcYv=99yh^12T!ePhyr zuY7BpI`v!I4*YuU8RaO4^~n2n{0-jgBk+dTG*m|>+EI~Nw#kK(Rvj*Eb96Aj@T^d- zsf0?6F;&s@>x#qELvx30kUuqdGh3l)+>-F=C#Bq`3j0%MZRY>d&FS^kOvHw`n%V)Q z@YA9D^qy6?-%fy4v&t>P6>+j_ygEz2Be5(T#u4`;SU#;II~=u*aS zo$8OcSG8v~s|=n>JYu?(b8T~$yXnfp%(Bb{Ri(&%xZZCXkD?4rjAx+=V&7Y_uLCug z9d?HpXPky@T;prRd02nXUSm#+`X)7O$+1=eH1Muf`Ff+u+uU8Qwk0x@cT%A5z8tU4 zl#boO2V9uGnqEH+_jrQO8J9n@rGNF{I(LDvcLQu_BE&n~s*!a4aE&?@cKf}d7*eiG z)P;Q;v~YH~dVU=~UuJz%H9c{IOYMJ;=N>!RsjH&1`&Q&=OD2RW=QGzCVVC}c4WaPu zh{*ef_V;1`(-W?*e7xHWH9PTP_{I(1Ww!_2_zv?jEx~X2@QqJ)^W0N$F0NO|Bj#a+ zFO|wSnLE=cL=B+rq-L0ru=0&@rkQv}AnKFs7pX z%qaItKX3QF)PKKAb>Qzk{0+8;6%84%gL&e<)M|DnoLY5oOf+oe;i6CRdC8p<@AMeP z$K9F9bZ@15S3Qje7 zw@$}hwmSZ7D9<|19dX(Y&9)tU>uwnB-7cLaVj5L(FYfD;_U9vCr=tu$u5qay_)FV0 zbJTME)UxcJJO^`0OYEx2dfi>HsBlBFZq%u7YeiZzq_hW3BNTTPW#YV7#+9!;`nH+Z z;Cwbie;ZG)+c1B4m#OMr!kC-UQLf?T#nrsAZzk^Ai@MuQm-k}$WUr&u%rlGXR_h(R zb9-F5f7*>>DAam9BYB7Vb;4P$J>sb6lfGf!+e2kPyZaLCljqIDnTzAPIaSqcfY+5! ztCok}HphCjnZL&W>0y^u6N9T@8OCMZCT0^|fBoQfs;mr*IZ?}&EvpVrd2^?k7r`hQ zbwNkSk9qsvKpL|*2|AlJzzYs|18vqVbpi8jc2LB zGA^;p*f4(H?JCOPyOBGnm9K(j8F4?ll07@A%_S}Ekjbq^I!pQmU3h!J)@8bB5`UNQGeFGRrvuJ^JzeT!G zN9Fk_XT!LuyJf=ythm-ZpLIDGW!{dXYW~;p-(y|D`Q5l8%gzp$_~TuM5$ZOKE4meI zYWnUouyzUWzV3ahsqi|N3f_n7xYwmF!C$(ZI3DJ>gPssj5Z;Pd^DC9^fQ%V}Mgnnj_HHYo3`@cLjz^!hN~Di)8|jW@@{9FvsK-ISeN?x+lV zLJi?1%O1n3NK2M@Hn61~ZTfMY?{#stPQ&=9i_eXN+t2A;z1O-_KJxjCdt7Ss3$EwX z{VqMP>}tD}Xf@24O5HF}w9Iu{(URrCW14abv`L21(d7&CSnj6HXousw&c$)0-8uFU zyK}&({dA(0k9A$N2g`$#Y#TIV0H19e)X>S=jck|;3#3IOum{nE^C&g>;b3O8@L1Q9 zf8x4!p(%RrZrVk|xOM27hV7GKAkxs}Mt+KMP48hnS(&eb!}4|Rr{k?-mD~9mZRac2 zKb)_nR=&JezT8&64jBGV(|I_(>qu78Fz)WG{H{x_#`!NhBoCtx$wL@*^|UzKNu997 znmf$MXfXVEu1V_Nqhp@~*T84N$*KKKzr#AR!}neBVfWqkebcNf zZtL7()x;_GefRBtd>*>*I`;6sJL!4lz23U-elc|4O^hLDj=?*x0e7A%dMn{{)S#A* zI`)($SQl}|{hO$!fd%W}TJF$0af(|6;VJMp&4-P)2kc_T?IoEK%lb!$t7`=i_+A_$xfgGww3VYBd-z7^fbr*n0CMfe^FMdlbga2sYv(&{KVHKT)BU5tyl=J6 zaYKJCj(t7;LPt2qBlbBSx6iR*=p5%9;T&rYJICGDIfDJOaqN-!+gCk&9plj7FF!FWkAgs+w=rHEP7hEht+ZEYYFWMO;j_u+GswWi-Bx!Abn-3 zDT?DiWuN23L@IZ=eqz~JePr6Vv3z?cEcdJdpLNDl_c-clX|!=4QRbuJ^j5#e#f?RbCQR)@I?64a7XBs(DY@FWyMRhCCiotmtDPN?h^QCW3c95 z)cxy6LjAOc_NQ8WN?%KVlC6n7*ug%PVVs|wb2Zk|#&xv+Sl*{^_2*dmZcnD~)5-zf zlUw2qxZB?!x+hzcymzYmp2EHl;jh|02E14=#z3h&y*}hdd+AC#&<5FZx^TRPEomRz zt&hf*Tat|T^1amZ@M9sB+R_)b(sMDo#siX_EC@OE>HU9BONVQRTcH+lGeNO@DE zGHLBz>$t8ENGb{@{05ks|mYDDe|hFPd+C8-6bS*jIo*n6&$0Gqq4;%g?cW zu+3+p)YS#QP31M6@4hO0zpl@lx81!d zr^p#A3Kt>fsGYWI;(Dysp}eQikBd}J2o`vu9GAjdNfyV>dtUkSnp{}pdxz<6crodA zc%r#UcTNsQ?<_(N3X-|WOtnBSn^)a5z4Uebho2T(pyNBL80k65qN>UXzs|~RnyZQ` zLwLI6THf}c7shhfk5$!q&FS)6YIbZHjA2AZamC=#Do{`pT(sR=^{|eye03xA=B&J? zP+=Wbc0R7`cC7wTKA|BwZ&XQBSmpYrHF^A~z1#~@xw#sm7oOY-oa6mOrcQ6)6;%)W z^$W4(?v6hsoVT5_;pSzT7_HBHcxA^K%P{&kds8yU;l}s4J->8O>0H>On~;`sqBE*$ z4Wm49#sV%&ot2$KEM~KNE?K-3M?3Ep3mzJJ=W#E(D+6mcF#|f^e^Mvd- z@2XnS;S8R`|C6(;76r5c_3?_13ul&{jkvf!y5+&do0q4{YhME8<7;Wsirji+%gL#m ztnmgcR7aCjZjGI0k&xgg3-(ytednRat(YS9dhSl2~U`_9fZ3*9@+Bp%TD#`3F&9ZC`NB?PXA_rBTCPtVasuoe0s0(4t_15 zH_HC-ad@H>=~?#gJM}Nh=pOzyJ>3DGd zXPjfCb&mV`>#TEVI7hEh+r8g-=~F&sd*eLXYX_a_GV4qa*=K6B&h!l8rhAqQmoMYt z1y(PBeRM>`#dY;!9S~mE#r-XtFuy^uv|Hl5Lils`6>hZ7yQ&}iTD{@HIC(GD+T?Y9 z-9G!x*4eN5wCW3=`yuPxNB1`moqJWh*YM(s=UP{Mt99n{j&SDpx_IUS`^ z-WM7yW8R;K*JCfnm>hg{rPetn9#pD7@2bXe2Jg>1P=4&Y@@N@W>0u5Y?h0p3uW@R( z^J%uS*>UA{)Hv!dGTql2#;o{No1CbtR3G-R$}Dr}?u>NNAH49Y<^toBNJG8949h@Z-$jaD34;R)Ob!FINT)Zha>WuBi759c; zfxkenmQQ&1{PcZCfB#5j(%PlrD%f&(hdqc~v!?kjqSx?srSIZZR?dEa7{?9YOxq(T zYT(kowB^#^5vtT0d}q*J!tQP8MJy?8^WK5I8o5ACzPU6HHdDJ_3#mEAr;*$8XjN1H)O4I`1h$R9+6TCke(>w8 z>^JcYzkem(we%V{bg3Ea)v1^^H65dJ;OXFKXh4a)x@Z03^s_8O_uxKiKz;RM)>Q67 zUK?va(#05n7G~dy9(S+tL?@r4y~b0We2#wFkC^@~E_FAKvkHIqb=~aQz`J5LdhH9$h?VI&_Nmm%w*P+5oyq4#4 zQfge2=0#lfK>E9k1gSnN5&V?Y<)+ofto{RfSKbjgN@*wS>eMdxg6xGimAsS_b$J~d-tT&L)N?hUSqQT`Cj|8w@cRJ$RJj?g+DSn zqyjPQaBge#EA)Wl(Qy7KfY}HiRm7p z3qC#Ccbn>I)|~5AYHxo=`0e*spq*%IRO(OtKE1W5b!xA%J{i%~z}RxfdPhwG-cDuU z`#zN5JNcI;->T=x!uGGcm37(9pBl1t4F(rDLIW@$w0jRfRL$EpZvlW$RYqM_; zrrylOYW@v9{@nbg+jPJ0f>f(=H(|wSw|hXP)Fbb}-+AIPmwJDPQ&sMC;`b1?XEQ$4 zYlM?!^O{q4u22KnsoR6QFe5Q1Gku1|)){Wa8Ey~$9^3O=>|OU7JomLLLP&WP zDIPl|m~>ewS6V4AAZ3i5a;m-0#a2o^QpVdUK6{@sE9EChDYR1xlbP1h&ahJMManUD z%1HZYCs`?H?Opy{cF$BhP1$>S?X>S9&1a{5+>y@T7(4A-NGrC}KIlkamCH{1I?_(E z)84Z8>s`((K5Op+q|LU|S~}9XjN55vAnkNJ?Ik;{-A+3ZX>;tfXYKR-)=oPXX+b;f zQG36wcG_s9>2_L;otFkX&55)!J8gx1%*XAtzx+JA=X^Wu2K$(6?6loTyU z?P@#CYws7Z(;h(DHFnwnm-9y{$Uq^+{kwkFc|(tCE=Or+gwr#0Be zjM`~akhaE7d)z+et9IHrq&;M(t+9`}(N4=k+B!S!4tu|+?6kh0W%oR8r&ZZ$wRTz( zX;0Z{SKE16Wv9K1w0b*jv30&%x2LZ>ij-&VlyYmYYweU@BIOr$O3*sjm3GRDNZDwo zoN68IVmsw&q`YLO_^f@(?38s#*=na0TIV^#PPq>$&34L2>u4w0DJzh&%}#Mx`xMzJ zHzMUVJ7sU2bu!jY2_q$Hr^Mr#Jvn$IoQX88$B}(|@JD;E``INQYU`X2daXBZT9Z%D zuvRIc9}|x&<>_%DR#Q2j&zf}1=OlCS&zy>WW!5?WT3Q&M64oC04y>gQ(LKJgcHxb6 z6nnSCAH8VE7u=FvaF=Iv`0@>l-Pd;flS3s}W(3~27pv;7%lGM1^p9;%S`EeGdNIb~ z$Z;6-%&Z=Eudx=RO{{kPyeRrpIk4?7Nu!(52%>F4Wk9~S+tB6vRdy_`ZkTi@&O zUhTHLn)>;ntLx``zf(UyhCfCVJ~cjo9~HnceE1vm3p4b{)p@#pOl4tCbZ5e?Ei$Kh zr|aeBG`|zk-tY2a6 z^%_#0NS*wDnR^%TsH$^seD9e(lSv3<0s$ign1m1}A*2HZ4pr17Btt-yfYy&%wF9Jf zCs3Q>JrgcAg0-V<&CFzy?A+LskYv8! zyY}9bnPhTlPygTZe|Uz>tiAWz>$l!_z3aWLwfgn!>XS~(_R{Uz)x)^T;ZuTiHnR41%b`ep2v>+qq8S54izjk;G)rM!pEj4AHEu5ux z%Zp`|IPoa8EURooz+%qFXLDIu=zDD$Z}T@REi|3BZo4RN^q^&_`X{Yh9ouTRTDEbi zrCYabdotg6df~R>K&oXGKK$bDW~JSx(;hst!h`mv@=toUTDFTN@adMMZm&c(0nGxq>x?>I^C^=jn; zE6rjvLd%E)$Y4e~HTI;<9J@O;%l;4(sdx(ce^8@wB zO@74>WR%YJh5LbeTZ6Rzh-?;N3fF3Jw(*U6D?JfiVD5A9}(eL6D3NRwK@{7Dz(9IwsJW9-fG zDjs=Q*tj|eR~Jh01LWbNtP)<_fYT52Q}R6AJZ@p2k;?`&%u!3DphjeYvsZF^%Vw;8D(9W7)Re_b3nB)mvR}*~+y%s@uE` zk;#@_dc+z|TYi73`D9>471vV9)#tBhSZv?CHO7tHuvDXTWuH()W0rR)*}KTyojV7y zWknaJHso&SJNQ`ad0&WD6yg7-nr+wHkFa*wIch}$KaE;pcWM*IBo-adauW5Pd=ic`?xn_%LcmxKJGCq?V5!R=x=@BuAU#p9{2J~k9+m=k9!TNDK^F4 zsXDCk)vX9Ttx6qN_rO4cTsSx1aQy zZg=3f0l%sIq<0F+;%~QXx0Ym-I3QPUFHz!=G}%&?aOW6t?sSX?Wx-{ODrYg_RZT% zOB^M2$8_*QBvzQqDIzunKE52u%=)|sd)yEW7D?4C-%YSr<|nx(!)oSId*toRPtk+D zfor$xQfo>)+ubD=$O1=uX{p6-l#1cwsXMkv@--0sdgRB{x^_gV%dXb7XINcVsC8wr zy2y?k?o02HbMUO|m}i|LPkN9mq_p{Jmdk`S%EzXlr}wq1->WVQtC@ zhpB>|d9+NcC8a?rS%VV2IIAofwdqnQXblz2r4H--_nU2x0$KlZK#*Ek^Cd%9e|f+c8`1% z*)K{Krx89;6XR#<=c;QpKTA9`4q>tKjMZVqGxxxoV8X~Sg+@kAY3*irsRzExI?OY- zsLvAT3pVQOo5p-X8zpove8PdTM~P!|ZRv}puWYW_>?!@S)VtZe8Sm6|Dx9BcuqPCG z5E-i|$h4Ekkj|d$kyGILATF2+-&G#|PHCf3A<_#5A7GDM)v|W2z?~2i3*JLUsmV6w zc=_txrHKW*HkYr4EJ-|pzx0p#9G;CtXcM?E@)xc9r;jG#DZ>t)o(y~8ob$-YGVjVy zI9-eV(+X!E%s<>P-9Ep*2$^g>@=E`gV$tPp$14RUw?*7lX0cbU&Px$oIMa6$KR>77 zi)I@*i&lUTUnw3Jige|%J9%3I<2SdMm-3|}xq+*2srQX+hXw60LWeiAc1#YngEH!R z<_do{+b(@Y~LeB^Fw4IjBrv7Q?m zxpA{Gaz%P3V&t-tks}uwRO-kjSsOWW|~{esN)mUTqm+G@aW4B_=C&I^WP+mFskB{9Gq7K<|;bV<{|7%7YaXF2)#M8Mm zG2RSsB3rn&;bF5f+P3@MVr(rl})v>giauZ7-s2PneYvILBX8np2>)u4ePs7=_569ySVv*z?0ip(5ic z*1bk74#dZ&7IT(FJ0jQYm!*JmRY<-o_w~q93*q2WPkN`C;iF|^*t8Zh#X=Do9ri&% zwgc=@%aYuH=^Mx~3)0hE!;V6M)8voIMpBc?p>YS|Q%nUW+al>JH4aZ#ow%yZh(CB+ zyJwN)eLG*gR$S#+>xdIK2I8|5;jyQ`X0(z!tZ^1JkCxi)FK&OOgmjNDw|h(6&}9^f zCP8n#Ld%b=p&Vj;6}zW(dn&h0Z0spyd_TQ0tBW!J3*dG~&3 z{I_!)^e$a(5As%!yBpBG=0tu?4^}`~#mU%1hY>A228F4>;>-Z=mM` zxraDw+}Wmp$$b1!B3AAlkI}ny)jhJM#oMf_rmd~$mUpyw%W235M}70TOjCnlKAuQPEr=`4S{1ih zd768`EEy7XjhGv~XPaSF!$SpXvp)RoK)?J6VpO*wzCxowog<&17^tnNl40f2lt?IN z5vuf{&(**g&vCD7w9)waC9gsH)umKX$42EjaclCkrNTjE{8+iP+SSBadyw@aJgZ@9 zMx1_lOtc$&B^VeN-T^NeIG|0a&ISF1s#K~qJFQ?^Y4R%bW_(A#kjH{>eeF37Tq48e zMovVQlm}c}fNMwI5UxeuAZ*{OLa4M=YcZgpvC4qk0Bl|qm6FF^E2ah_&>WM9$M)bs27|A{IEvzTr>F<~S+I<>-F5)qNV;{)pSByM&w4ewof|>7Zk)LjPPbW6>9!K6bhX_$RhYQZJQ;68!kt?WjC@PhQ`^d zsJKd0Tpz&_?Uv0G!j;c(okRvtH%{CoT+jDilHUz-4OuHEN-s#NQE=@AuBQVUAAUOu zAKn#)OOXB)j7F~jGMb4GZ)3QA*)kD6{Ir$mwTak)?QW8XyRHRvaLIT@}1R&-<`Z|stMA8@_& zt%>9EwMM7c^}w|ugzH=sT($^YPesM`2C}M&4`(u5jtSw~%Wx$zT(nXpOKJ^VlBWRI zM=K_d>nEe&`pPdze;?H7HGSJixpC4TPOk+~aTTe!UPA-;U9#|@aLr@H(1NbqpqRBZV1S+i%U&nwucS2@lON8 zSAb+o*S@3JMT@-d1i`)%YkFxv1L}kQc1^D)3)bP_(dX&t2Z5`4oz~FJ{WDodwOH-p z5H}UhIIr1B-SWwnyp*Z1lQtAia?v`ONGqvZey!#2&0Lz!Eu_IxN>i<*C5Wk(Tf{`w zQWB(h`VV*T3BSZ%sMd1Qt92}TO8$T;SUb@zH+h2Sn@VV^qxGU5z4)$=Piw?_c56B4 z&-#&87G+A)(T~f~k44Lryux_==11eicu;`sBx^xX{zGtR#YMLC3|nzQ>*xh!v`vSnSLyfR_Gq_U z2AiDYa$gU(MxhCym#3kZU&){1D#H73Y2j_L!z|Kn>`jZlPUYOXR8T?3VKs=bSh3p# zX;Qzo9+NU9l^yN7GQHzgH{VU?Ou5S*Fk>OkwlpVp5TxCKwS7@6;i-n} z>{?%wA8=Ax9z#>8puq}j0e&vs{2~9AAbr{E5ErX?Sc*jHLbR+)egm2qs1|j!=o`Ca zUpqhlJg86xG+kI9L0q#6XiDH4xa%8{bjX2UfD6shTD`Fdb`xKuN;-oDF+4~Wj|jgP zpVp0Bu;KGJ*7V~JzX!3K#zL$) z-R++Ni@>n#WLW-u>5@DMyYi)+5SC-aQ;Uiwf@E(9NeM&Z2%}kYeYgCxF>oXg#{mtb zOTGd)e9*SW#xVyty5t(z$6YvUmS}P>aO?+;rbWuUN#11YV`Y5_Uqv(FRMy7Iur`WV zZKZgTu~srnJNhWVrLhsbM4MI3(30xVKA*o!-jDWaeLP&k63@8W_|zt}ub8#(6ztqg zDHH8mi}od4*9whE))_P$pKXOPvQuLYMfi`Nxu`L0rv zXe>2ZxHNbpoU}fKo0n_HK25#<9mk~>;(u*?2vSLav=lAJOY!}6$&UcX@^Nr%2afZ= z;fGz@C6_Q9@Avh|U&F4wBRhm6hW49UTvTm;5;$lUr5Or4PN~w6FD1^;L=8LJ_3-8M zXMRsvNiBG^bdq>mDezcK^MqR6Q*=H--ReIhs%y&SZKj6EaiEt1 zLG~WiV;!eP8Nd%fcB*AO4jODF3jKs33&66?lr{m`y}_3kM&hzf0GBz0%groZH*g(h zK59Z0C(bA}rLCfs$vUBS?U1Pa6TW_D75d0)dTNg6X zI2tI_Mm+eB$I+JHT|;p+@DAD$9!Fa!UHz^a)3ZUF!&Qo-EtGyAinT42zW?q-;%Hs6 zv2Cn4+PB7yqv@qj2d`D*XkBta+t(3sv}I}>txLYWm6Ki!Ovd?gM&#vnAp;;FUu|C5F}|PxWady-U6k z(!1DCF*I-x?DS0Ow}C$S6WFt9*6dg*rqnl>7#B{g}wmv#BAwl=(DBhvn=$_#A0S$asU?aNZ)*yZ1U@+Wg*|j$e0;sG{_ar z*Q=MVi{jhp!k%{I+vt+dVwVSKfD`a-fd24pKr4rB3u*(GRr+BIhLF*EcQV#qWj7qgz&=NUitf|2BF zL{Aj4o;U$(+$yD^Csy@~^N0Fj?3fwRF*<#d(F=v4UU+(h&%2B4|1kRA+CS2Fg?SLD zh`xWr4h~(|@ojvcT$g-{kLddaeEY~^+!^7c+9K|`(F%?ndv3}rI9hSF2u?dy4?kYorp(Ggl>K>A>7UoehtgmD%pYX z2bUh17m085m|2&c4SdnY*QCm_S#e>rX9xQ<7S(L=6!_0qtINcK?73^Fb(Mz5EqN5!>V#dQEN`c9lL zFcDly4A(QTmO*WX>qo#<1zew`P8`>bqu?q5t|y0ZjqvG1#zo+IB}(o=r~DC%O?SyQ zh6{P8^*C@H3B}yM9fe+Z zMBr+S5|i$fJ6TM+OWwqAy)c1Xf==vNK=j%OT%b2>Q>(NPxYhxeeeT5RWgZ2W1-PyY z;Tjn;>ymX5xV|41*CPy9r|d^ex>H^y)uKN7y{p8zm;)iC7uQ!%o@BaD6a=m~^KcKuo%mc2oea zPT06s=?37s3%H({J#kzsM!{7CTz7|Xjf|Of%2^S(o`{O;H5O~{M2-W|>*fjJdYs{! z!f-vpa5cli#r{SO@1{%?SEu}O)L45b_D9f5u_0U|V`iQ5yYLeZ>6NKbapkMHY7uMi z#I9}Q%fn9D!f?F=D;M-;xbE-kl@Gut@%5}BTS)PXDjuM4?_#IC1&AVJW}Wg0$glBY zW;&?>arNObvra_8Iw@OpRF9C**eQR|O8(qN@R^;p`(0RXR%tHUor`u)MY}0GlwxL` zSl_{7X4o}kteDxOBVuM*QscYfF|#YjjG1*}A68}!vY6TIh?rSY$SdE8ER8%^NyUY6 zF8=+hrLaDHpto0k0kN&5nWM$aI^{=NgYtV6FDujHWu0<4YhZ zDN8lCa4L(I%|^70e_!z&*fw>_x>hY#_V*~UGDv3sXtA206@hetbSl^@ zd;6gS`#0-%1rg0-7602W9|X!o-I!K8408ZA}^sl{UO;juEUr~lblnNGU4e|W46904?Q z#zAwVk78v&4oTW6uVZL_JBTxe;S(rQ@sOW`_-10UGDzbVB~}J0&X9)Zx=^ePvjOr8 zqQ}Z~($}yqhsVkw0X!WnBXz786Le$mXTWj?!$Q{o0%}w&rhL!Z@|9wBx++|;;}N!l+1$v zXJTbK=@XVI9~mp_kfpW`xn|6$cPH&Vfmm55&OIRT*TV2%p=b2rg~Vv9vJ>+{J2w>=(E7gy$S1&gh+pXZ z48CEL-9YhTcE-^=dn2`Qz&(OJ61h6TI`n80XeDPU2^;otxZ(&00t9wBfpWd z8)+|bW0g?5f!+%%)y$oGooTT9s8@E zQ}m1tyUw3L{@WyJE%(YH6IOdow&$|{$x;wXDOS0}PCEnW4y-t$JzdOtYh6GkY_X!2aGH zH$KiQM#cFCEOdv8^QBg;XT$0FU50aPdbSS|J>y5g86U#ABLZhP^6NX~I-mAdqNfBo z=l3i0^dOGCKw1NwWx%;Vc6^*4z`l!4&s^a24=D7^iHfs%V0?Ps&u~_^M(5jVpT@U? z{&0Fa8P1gvIClbPg^KeohVxtiXC=a(J!Bdm=f+WSe(Vp*6)Mi7Aqg5z&pR2;vFRDZ zaHfxfGd+a!u?U>;4Cg6tI6Y0kDX2I(hI2D;?gq|}VlUKZWvxA8!w!X?+ZgaoR7P4{$|Z3r4?U=Bt$rEpSwhS zT;#VsCzPqY%&?OFFhmpLnKoyz@eM3&z3w#wDWGY51>)4ezV4g)^kdz?%cSR=tLIbbaYDSc=i-9RYaj`jmO6GbAs<+{fixFLS9%pbraka7q-O_kE+}l} zD|8yp{urnIYVBk)c8a3`y94B5Ow3>wanUTVf?by(We!NlHXW)P zdKCKLsOP`gJ#Tq*Zk*?d(*x*juX@ilZ{#)Gfy237xYG+S7gmN~mn&FeitV87n=y}B z4;1CnW93RJdT0-9YpjO~JP|&>dod98j`P%auPGt^$FSvBCVB6 zyuYm<-cDrmZ&TJL)aDyq;qByDJLj;|X6ZBl^0sQ{v`F$CwWU)+E&V{r>}M@Cp{0W7 zOV(13(PJ}Ox*IW`$AZe9t(tWmw{t4?vM{<3uM6#l_4%-&)Ag^2cz@g==xrUNrs$wd2s0b zVam(4M6@dw7I%ky&#-n~hISnlsa0mQie)NW1hk6Uq-0-5w&}`Vss%X_B6-S)4%*(K zl6*636J0N2ZTc+0QN6ecYYIWlKc*Q zH{m{&OleBUry|L(;wt%6tkP2rnhzvXx^;w4Wk5cAWGtUb2lhjqm`|kxp7M$KRCuYH z?OTK~=9lER+5*iO|Nk2a9Wimbr3sQxJxv-xX2sLrvly_)2BkxPV=cqvV&QXB+vinJ{3-S zDJY<~EKz(a67)hvN01O74%dk!>{LU&wT0=8iU$Z|zD=Usa^_Q! z3txjIw}mt@;)@(0&0@X=^bEuKAHZ1)8+=CJ_&7^O#rYH9RD3EDvcolfGh7!M->1S! zM_`*WzK!BLlH^ZS+fwWgE#y;?u-i&BdXDc?;iOv`&hyMqJ5p}n7sBZd*`m}h zCt!U;$BMvt8*tvN;=Bns=S#l}%5oEI(R(gxIHUViBzfPceg+Av@HL-`gzWGzoFPBM zM0_fowC4S=|z{KqUEV)eePhgdI9x$^+Id!1{R4 zcv$C*fpta5rve!l73)NNDx9=~VU?oT+^|ekn_I#Tcaif;6SKLOL}0xOSj$6L%NW)_ z49c<}dR$F+IM!%B6$xI8=sp$j5NuGzrvm98k__Q;cj7)3PU?l#Ey?#p^{Ghm4ArM1 z$vctl1HT4~Qb<@sXSKKEgfES&XuS6M&@;>ymDp*D^Q9Yr_b%Xlt1A-ka36yt+rrRB z`cyF2g?uWKydoTLh>s`gQ{klD3@sOhzU^2AtLYEMVf6LD@@|*&Bhc;vTBqt`kPwX} zUcN9Ov;6;)o#Wv>49i>dm<`8!+N=3gpwomTMYs=XqCOQ)ieq>yqxe+XWoroU&%BZR zT+Z-*6w+yly79nk3gOi;yjy{H4}1-0J2bqb>r1(#_*5YKfLHOUNODm)-jI)Qe4h%= zw(BGLIyI_KrCmPMrp-IaVLlb`EY=USV;AahK7PgvJ<6lZJ3oW%HD7A)mt`|>el2M@ zNAsyj^2aP1KfX_;U(V>K6^_u)ypcW?=(kaPDx8!)%%{Rhv*1&aa9T+;pGv#DLiMS% z%U`o|*%hA($1HWGPyDb36G|z=^Q4G5=q}{Et}pawhr}ube{@r(_!uU$9yWB^dz&Vv7_S%p9=VawMkdoj;s~x zXFb|<)UWU|?PV{?cF&ih&YmAI&7D_DtLbkj#+gHot?c`%;ulL3=}cdiV;*NWuMzCZ zX?6vH__=g$VXR1XqeoeQLA8|XL3 zZ2n$3JK~(hm*3QLy3)i|3#4Zn=zIe@FR@)tMkaW>e7>E|Fye6%Dpys8wq~O2({?(Y zofm0`ah*u*H-VdJzEHjsmhS;eHR8Fi;vDRQ_|T5n${B#B`VC^`YC5T=JQ%I?`%z18 zj#|1tNS-A+88Ilg2dRgKet$mf_lLuNzr}u23)uQow^$~Cl=SY%SFg1#|aLil6eb0fDf6s5I-bx3tYCZ{}YD3Y6brl60uG>lbL{vRcfE~}+s`;kCb?{SCE|tCtT9s$T z(yZBQ7^cMDBK3+6SF9dGN3syxaU;$&F(KP(F;Lrkb6FM^Uv&+zGzPf3RD08E1J1-V zATMh%tL3iVZ?Rg)1HA%w(=HXccGv3V>u}y#tf9lK+gYHzZ*K1rb|<{)sKv&lovmP3 z=_2+Hlq@xLBsB7UF8=Tm&%!RIhOdvI+({<3@V_jY^~59egox_0}wbEGO#CEKGpmRp) z8?8{G)5@d)oPG=2^;HkX2tL~1@b&kzhxzyUDjH*(+Br+=>^*^{9PK1w+4`$3KeT6T znTGo5tPZA!!#3NEv6+c;7(_hrvY+Om;rY7lvJHC<(Di5FHNcDy3vIr%3-ipuW<59a z^�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

%yyB4E=8|n8Q^kL&&=)>^8p%1Hq=vTlc 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 gVr}`^6n9F=rQ1&s}wbph|6vm(rF^$ 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�M_&>;J6cTSd#)Utvevs|k6i zh&QG)h92Vleg~tKD((f2Ow-?=&Xv3PRm>C8xpGFqVnb?Ri|CX*Yc{gFPDM8y8A}bU z({W(0EV#?g)s(K`ORVJ0IYYNP#hLm>St9Z%#0aXNh!6^$T5m>GPKkvx6!IZ-%D8&- z4xLqGd509^B?b39PN{D&Ln`9vNSimZ%NxEK^2fuA^Abx2Uxu=;x)5i_hN#YAd?qd=n4+Pe%zIL^ODa!RD>&Ftvw0tB@i|&u9RqqF9Xw zQ+?F|-xi}!cNRJe8uOna)e_m8cx^HEy`zeRt}6fOD5393#WFbdoOvP&WxXzBa{ebJj!xHW0SJIni~xjE z$E;-I(>s-d<-lXxzB*%mOT`}*9?zc)-48k#U3AniqVc$%pj-**5(^8zQ&~QKEz3*n zB)QMflZa_V_NNXYLwT#4x?@U!%vMIWbvL5_p>9c$z(gZYH-LCo)>C_hghvDNv2FF{ zP?(SWTFVBT69ABT+mA8teM*~INLK+6$4^;363zoh^=7~4R459@3a2%DgcX+2f|}Yk6=yip3p*boqbiw(j2#D7$@Dlg1op>rH$qEw{e}W>{-tvBaO{Cp3E0AzMgvr%V@CkhQ?8Jlz zcj7p{;07bI7o>uE_h(={ww6&a)mF$4PSh<5se==Zzqvn~`s-=0 zJ0V|eFJ55%1=`Dq{t{x5)j-LggBJTV^47M5`v5ghfJBsE|{_ z$|+&Jm4xl1B~0XN(Y2fu=l}`prN3wq+aERMODtNzn5n|Fd=d{9E#OSChJ-V}Qb_1B z9_TqGr?@F*6(nf=CL0niR@OmB4FC6&yKA#a8sW1s{EsS?-Da0VFHw--B_w>YW*f?8 z>#mxu*Y4WO|2GFDd_C=T8`_zWz`KufLc(s^t0Nw$21?$r8%XFPal4@|^DD%`&IDo9;ctAtybc&c$QvkwJ%Ey+cG^^=fog8X!=_niv;;vrRAJ z7br{Ja&ZtOx~LIjCCKU1{ObxEt@4nUSV)sAbxeFAjV!IRsW@#CghtE@`L(v& z{-~H@MvF9GY_p25N-v9PgP{b5Sb@dFEX_on#RToBtqb{AnBW7Lpb5m}x<1oT@N{V^>3TsJEOPV#E=!SubCQF&Aw^KE#Q9L}rh(3TXuWs^^%-bP;G}S)FH!C zDM$ZnXkGSA` zCT3zVTO@wv1u)zbHSU<&Yc3*#6YhsT3 ztc?B%YCKW`o_OpIpaeqXN4DliU_Txy$I?YQpa?4;#yoM^_b|?bXd@J17CnJX0MC#$ z@aUK&ID0uFv@yy}jEcQqcU-4jTNyi7u~&7W*q|=A>m2`dC8a?(d z)T%3dkfSa67-{_|bdVJq`XC-X_Flwe+UFmKM7Mqvesk+WNoq76Acb)D5he1n`K=2% z!HJin`BF0nPbbOK3_OjKr)hYaB2Sa?#O*a(YwGYcOP(t6#QPMt)(po}lRV+%hQ=G@ zsTfap%99UI_sNr+2L;v0_P(KDFy5W4e)5<&f(!Kr_+$=-f{qOAiD*_0MptreOVFD^ z@1wn~`i$~sZ#B9w=tT)qwHv)#f;eO{=rIYBx;7dYBPe-`gj*GNi-fCcivC@KZr62s zwFIe3i}Jq2_`=0H=v)S|3Zs7(I`NF9oho!xX!HTnYi5&pj1W<`(R+k=5s3#25!D zohWYwjn@Q7{68V0p`r~!lns~H3ek<$s|7JR7JnGGW|6&5&z_HS92oJytqM=<4%a#5U*mSksv|hcxAANU z%LkYN(yYya8qc;Ca8KlD?ui`jLig>kVfBtj)rM6g`dhSLCy@6F*vkcZcdf|J&d$HS; z?fV4!0rHXt{==i#s{9Z;hQQ`oEDqIuUi0o@bM(?Zv!1V6pDu7HszrErusHy%*sys7 z!9rP#3Cf9=M=>Y|ULGj)EW9ibVisP0@Cb9r!pql$n1z>ZLd?R;hlQAhmv;y;3oo05 zn1z>@3NZ^W&k|w>yzINsMy*_UHTR|t`d4A5{;MK&Kb#E) z{Tw<}=Xmflr29_e!3Pgnc<|_hf(LT0-GQjN3_N%m(QG_;LVE5t)D#>20SVH0@Q4Ii zcyOZxX*~Fi1X*}+g#>9lxDi3gJ0#q~gEJ&NCmx(2K{@f@5C-MIgI+?$yLwQ+WCU4m0(mzd=8se)NZH?3_E-j|}FYsUK;)*`t1R6*++82sF>m z^`m8AFBc>&h9=(;lHP?jl@mAK_yfwqHw^-)0;W2`(Tw}0oJ`$^AZRY2?IXI+v)IWc z7z1pB?z0qNql zF$>?G5Mma-{XvLX_;#}pv+yk<#4LRKi4Z&B+hJGRC}in7>Imku=ePZA5x{2*97As5 z=pK7zgPFLV3;sjZouJ&W&>HH&iTep@q-mTDombI&V5r;3)C<`G#>!A{ zSETi~kzIac;Srdh@3!Jm-))%tdk2>QDm?t$`DZY*&WOGQ26C6XYnl<|B?pmR7aNTa zAQ}tpSe_C26C!12!EZ96w;^O?>KU8c#W~XNp+2(tJv0Zu^XBw+O*0y?!CH89s6#o* zGa@rO<#*Co&+lcq3Io5W(;pznQ8mJLuKL}Kp(%I$zJ!oH*6;XSX+srC-XMnXU7RPP zxz>oTRYfW4VhX2RfjVzaPgd~n5Srvf0&>hs$Zgm*RVCznDidBD4yVF)m@X=G4!L?+ z<+4l)LScw+xULA7rABp#KeR)9)SikT>Z@W;^u&KA{RxGh5yBzTfI_^Kno3ls9L)W^ke)}deM8CZ;v)@`QF=cD0 zEBUKf=&{!$!<+@O!(K_5Vu$@PVnMhZ`5Td&5SX2k-vB=tgp5o*pDm46fBjtieUPh^ zIoG-&KrfLy3%VTgF8Ldg@wrk8f8}2xe=-rA)nF0uhe|tU_x$nJJFM zhK?SYqWnMx@^N=}bcre>y9Y+*G_wMEjdJp5I*Lv)zheq^J*K!ge17VDJM+-@$v}rb z7nyUN`-6I^k#`Pq#eGP~k$|F651dY;4I z{-j^+(ceDr*HEpT{`M!505$sa`P-jy4>Vw|5<}14v%mdqhz*Tg``iCnZM5Q!O3qJW zHA$^9?FB=s>;CpH4}#L4?Qj3Y-O!Y11%!L0I{Mq+gHY=Jul=8VvIRHJ_V8Qn@mwTF zdvxw^fAX)?UW45J_P@s_IMi_>!cWH{n)bI}Lp4|Y?R#1uDCBANq4RlCeP}wqt(M?M~v9N%paq*nFfoqJz)pNJ~SUgDjduk*fpyU22Pw1KR0y&G+-Qv4a#OXNA~Jvh69Rr?Y1N>iPgTq{My)kgwjfSy zWW~HIkIV}d#jE_07B&IT?U&5nqlg`l7%6Xwcpn}s2FIEh+U^Bfli*<9>>+uf1LKus zEYecuO#L8J7o+APtIL>OW(Ge)C}uSRGP6MuK&Ds!4w+u%Nz_y#pVBz|_>Glg4>wj$ z8f>f_eI#gJo(4e{&|N55*wkE$9Ym#OHH0ijEeZ5D1uk z5gE``>k3im>RIwfcgW|6SS~}ogN|;3`P#|hSyorh6s}>nNqdz-xXP4p$@~eM2;!C& z*Pe(+acwsmD>1M4pdb9O2b3Lu7d`-9ksyk!8Bsqc|MtTl^FO!B=pviw+w=+M_^m{W zJQQaB`cCOdehx4Dq64wBNQ=FO0Kgv#^s8$P{Q6Lra>NRv=n|aTeN<`;>(;*3KvHf& z4KN(6mEgBBvd)F3VQ(VG75dk@+JF@$$p)i9hM^ToczU-qbmZ;yxI@;!x*B&9_aSyI zTd>|f=cTr-QUcYk864BZkHmKJTFL(hhscDJU$qxIAlplVDsPt&s2p4GlLw=NfK5g# z$Gnt2yra^Jx*wt@KV#(~PVyr>r0P>+`GT4%MJsFo33-=V2`1d)&P%RfydUXU0mS;f zip2$9;owNd;&$!SiK#pgfhIrwi8a~fhYVbW#*&zB#7te1Vs9kjsPl4fgYs0E|TnC6hwv!ttP;pS7jS_a+5Jvj^n)o!P^zyRL;;8F@Y2{i&i zNiDF4W_fUoA7$)3GKQQrzjg2&INYCE*gVEN?6$0v?1`r$+g--WPt{o!jZYbk%hAZ_E8GJU0CR=hJ+~Mg5!@iRZi!Rfu_rdX z8^6>O|Eb&c$-S<`=x#=JOX5_QF=`z+DN5Asi^u2i=%=1KQ6()xgkXyi4WRvTPbC2k zt`A~{#99aaYtR$HmyE{SDI6_>{vO%xHzE(wz-o#8Be{hZO1s-w=qG0_@#xB;+u`QA zxqTz*$-b}?g z-3=g0>b3HKW&c0nA&Sa)6u+?#lSiOrRam~Wuq(i?6c)h)3%eT8t-`wHC9lx0t$9q= z&EoNARzYt==1(9x&3M3(9SDL# z)Ku6jnL=(>;rZk~+6R>6N2orF?8@gyu?>>{1i9HW=#|hRxH481!4mxAakhfr+?xg9 z!OFf@GJ!-837-~2a5BtP}*we<+9!*B<^+7MkJ{Yv!)e_v5s2FC{JvRa+#9j`+4sQB4 z^$a4*@RDSnDn%MKuUqt~(Ba9w9iQ3F6@4l^GP%PU%grz6UQ9UB#XiK533QZw={KTI zCf7S+x{=t3t|SFosj;*GUjF-Fwyw54@2RHVt?q)nz*!@?A{lNa< zC*i*ZQ8l512dz&hM*SH}i-$E=3~j0y)>J%nG+fBvL+zEIFQbA3IAOzBm`|pnky7>z zoZ7-BhmgDT@}WIY$Ty)wh>*V}4=zN2%gD2MK@V?Shu`FAW+8pbt>m>u67Ys|hqIA$|TpgaqIP8Xb`KceO`0TpmPl~x- z#SdMKxE#(TE)evXbl!Gc?y&?*p)rU{-9Sr1iZ_1Xv-7*4 z|G!C!bL#&{MTM#h`akoBw&l?OX_oRh7N`Et{JvuSKkGvay6~ab+?f5L>lfSl|2*`d zF6#gILTQRhZ*N5(Vd}A?`u`Zybgup% zeqAp0|KDJM?G)4Me>G|Zf|9NNr|0M9Z{h|aYYM4!M&=MwfhnYDfNBr0wZkmZZ&8@c zBKeIdUGgATWhmHekE74DnYH);kZ2=&l^x_a|BWE$OaCl># zf=PTjPtp^f*I33+_9L4@{8QKszF0a+246+Y8oxgNg1_fr9Wb<+*Q)trpMnkg*zJ|5 z^{2YUYdNt}0--6)bkMpK9Hh>`znT1ES3<5u|{4QoE%gvO$Bw7W)?<}0VLp;?{%=|-d`J94x^wOcjm z>=K7xU2RFaIWrD4C`U7Lr6zo^YDRxzbV(w94-ZAwbARvL0yyQjO9S(Ku8anbRdi@v z;d3*R$$1CB44fn8VZ)ZPVas&Gj?ZjZae&NfP$P0L3^L9g+=XB9ymPe9Zv7vJ)Blc& zdKXSZyh2rJTn!qQ7>wM`gg#9`XezEbMBV+@mlqqfPRV+HRA-(5^%` zn?2mwCc}5rCS0)&m#8*53`rxahm)zyrm4FbO+({Lnudo+cd2P6B3X9Rl(T6nbkj6+ zrDX}>GLK~FP*jzjW#v~FW#+Ps3Dk z1Ez{=b~9C6Vm=1DCem7qXiS2s;)a}4#UG&C2Fyi>oTV#1wNOw>2BO3Q8MZJS!cC9E zq0u-Wm2cUI9RX)|cw0CDme>x^q@UwXL>FKkRj8cQVCn}>x9hf1)$}$Xo>-moU zX-;brb+42f^EnjS{aVU<|;zHnt!gvYbjpq^shDl%-WYO`FqtGr4XPpJ^u{G9rMqW z7<@S(5bDg{@O@Vb=u~_Dd2%Q7&pe98Z@!9wTGl=%yFv$niK$k>Pc(}9S&LbmB)z;O zQY~f(xrmR5^;X1N5K+xfw}M^n{043 zuLM5r2z-cvk1h&e&diTw!eFW`b(DBd4uNDzq5G45aOweFCn3lDwBL+DG;w&GQqSym zJShTbmE}ag`CHT&WH4)LLwbN?exoe5&QebkKf>(v#n$XJEkA39x)*1tJwsPFy_@Q} z!EAb0%~Chx;1@kZy+fb30=G!cQu{dRf$2&tff90X6si&JO{m74UA!PZ)}6Q-^VIX- z+=VK{9Ch_1cYKm3;cYfX?J%m>Cg6#OscOzo{~axzIL!wTDdL3mFuY;*T4j3Z0*D zUx!vJWUXs`4Fh0&BGMvOF=k6Aq#H_R zN@Y1f&39rk;UPps4I!=%9-VmMOeuXLlfS`7tLns*q*{64{3{|GQ7;}aEjg1lkM4Cz zYk^y}661wtNSsfR3F3@NdL$!8urtcDGU}-^Dv>7amO3;uqr)798PV0qu&uy3@5xlI z{8SBpW$x3L7kW#yL1E05IzsZrx{&;Ki*3iGIhF!=oG|CcpN1*L$;}5C+|9+{(Ep*q z)RGdGMo^+PE#9-ueGOjoQr9rDi*u!1444VqDK(iSHz!6xYCMaiAInSFP!d1R>`xlX)<3Y%*)q>eSi_xD&uh->7Sqh zYjAjLVn%yxmYavGlJ(>o1f&Jd#;;8K`q`_VtT%QAU=1?MJFFXkY(ruCw@;e<~lao8l+tDE?PS#o|AwecdyW zZC`s)d6lRvj!m#iPfl}FjgZ~g*AL7SzDtlc!@lm093bJ}x_y1gqW|C8*BP_gVqOnN zcm5SRAauW6=Jlmlpsl)OUjH4v4eg#`${mf=wkbF2D>kp2nxQbR1?!*ByuKdEvTe8w z^E%i0LLJQO`!L2+>G>6YbJ%cS#D3HE_0edMJ=oX(y1c86Qhim&M!5^A?MC^U?CVW1 zkG_C?{V|edx6OCkzJ385cd)Oq7Sn*Wn3~}#yWoQAcShMa3L%Dyf| zBHpivP(VMg zeZ3E=6);vN16$Ya>r+*0bkV;4L*(;yz;@aCw9ie zMe(Z&a->><^@=xa!mA^j6sHzF>3MYrI4nA$%v^uqy z%s1Q3beZsoxP|wb$Xgo|g$E_PMH#1^VgHiPeFBzmPT+2*a_n|0$6057oOSk25XX~|=`#yM z`#Wk3`xcvARU?BhggCmNAgC^hY_%X`Px;$o6BJx$#b zC%IE6pyAy(q$9F%=kbV8X+&1y2P2p#;cmoJ9>L~#d^l3XPU2FIC-Rgl)+_c?&dj*c z8G^e)`$SrHVp<2s3VXCnjfG52X4c$Jw=Ge)GT~h|^i{h_Ay0Qgp6;YP-3)oU*%x`z z6MP-=gmrF|glt0x*s-zRlpk}k%39pPm&04yFtY;2UP()pMw(IJlY$lbfLrLn_(!<% z4FvXIhkQZ0hGcBdTio)tyW6l1!i5rp8)B`vPfxrIm5|x^quV3B|EnJDVV&IM#>zd9 zSszujwbJcMOe{={@rBRB{C+uB1VD6A4>ZeuUUZ<*BQ>fdeS zy$i$Zaop>$E19Ja`zNt^5;KPJ%e{lvwd~5r2H*woMu8eRpVNRiBFl*WM3~{FCIRyl zj4Y8gIC+!To(Ag8o=(=LkRh`61(~{o+FmD2y~mH6Gk+&fMtl>`a6S@-9;2)vP4{?Z z5o;_IsBM_Ud$~CCP={&blhwT-yyVZD04TFTeF(#iB^3R_=`J=A?rg1}G!E_6U=o=k zYy82@Xba=UJmd`cD1h2sXJ0uw)!cHC6bovlO`TxArl{;usR7cIu9TsEUdcw05|!->bQf5&76>jHgDwC(x+;CYX&LG* z8n_veAnAeF+Cke|w&h>AnYUm<^ki#7WY>>o?MHmw|0mQ~P|by5!#n^lsBPLng}C4V zbw2{2Fy2ZO+r~Dq4)Skx<&SMgc9GTIk-<@gp~1#d-_|Ew;l3N*#qQ>!)awo`;bXks z-S~XysaBT@`}=VdEOPaO#k|zMDkAdoqd22+JBR?6IHr47F+ylmyw*FS))(44)|Lv| zxyG>rgKI$$7WAU-Oi_+2H?aYRiSn{W)5VJuqrCAlZ0$TOKH58Cv@d)x7Co>IJ{)Qe zG6?U3aFtS*Fmx-#_r{jSt;UT{a8_LLWJKw9UWRoK_B72H?nmf>2AFr1AM>@mtvz)h zzSrgtL9rGU$XQqbRO|`4nhq;9g4c!MA=Z-Ifi8(!DIxoSB`$B5&O5<{yFoeS-&&B@ zj?<%YZOZ5%TID>3Y~f`F1yn}di@C%C2x_kOw6m=6{_!zI`bsX`5{AZf$574?Or z2|r{k?T&5Q?hPi^!fV_QxlmXMB-|gq6Kfe^SYb@&%d~%n!e(1!n&Z?~cIk z&CtKBn;29BKwgC025koX6s1-UrGw#MU9=m*&_7+r4jG`|y=qBtf}5V<@5c&Nt-fzY zt207qawDb#ibLJz_0Erv@{IuO;6h#;Hh5eanLIJdM_2%0jkTdg9x7v_c`r%15}c4P_DSkUXABV}0yGCOTs+tw`y{+K za?|j$b!fYcU=Z0+D3A5;#ch<3IPZv&KE8zyP#5pvYFn?mED)J6Ak+iv8~u_4P|L`| z0;Qp=Ih^hVBC|7=q8ef?8IRqQ64L9< z3Yx}ie9KtPQa9Kdg*elTxdiKFUT zu2M$(dD(ufh;lJoF`1Uihnjs=G3xwae49Vk!jcAUn7{p(h&h+L*oqVNyl~qe^PoUq z1OAlapWht&uuINtALEa?NTr-iV9iz6n*)R?AW7&L{q?#i0NN0bKqKazriWKEtOf%5d zPa>Oae0r|>%iz;;+N_=6)16bhh);E7;cLaG7evjbm9b}hdQ{^651(@2)9uPQ*b_d5 zRkUvjpSnxw-vU0J@IV@$V&mM|5H(ks8{aL6y7KHaeq=(_R29-ihF`TB$ERIC=psJdf8y7TPe;M3Lk)BZpZZGN z|KU>(eA=nZ@;%|x-)!@~1e@rb+UGZ+Kb-QEuo!3!;dgI3e1m7)mdhPqd zR1O8|2^G>sbSj+ODLP%@C?btc=PIh8(=PxM=$oDCPuGq3GWc{WY{|~_r?VQmh)-U! z@U`ksH_+7WB0gO%asP);Iq+%91tQOT!l$EEv~Nj&YCE4yehc`t?p_O@I>J+xF!dd? z?~b1&&6xw94pAXpgs1T7ox;;UCZ>x>!_yi?6?obvMRji9y?@M?!Ka?*vHaZgPb_;k9maJz(0$4cD)=}$TIr(!i}uqS-__$*8AzYTm^ zD5ZZ3_%s&hm0S3fWB#fAOsSRc7DVl+vzjVI`h}y2G(^o;RDq~J zjUf}A%s)MF#FxRRcQG&489rTo@^0|S?^wSpB@5}ryCMXEZ!F9F5NjvrCZYkHe3*v~ zG84v)$EsmbgBew&0&Xg>n!)9`a{XJ$U$q=pp_b#;ig|0nO*tn-g0dV}$u%te8x9K3 zxhS*HtF<~X*o8lbkK)2yITk65)F{0kSHr7>%i%dUqQ-~yxLsN6aoAPDrL+cnJ#LqC zJ+6J|R%<=(XtjhK-dC27k))m*PPl}JmA9>-gOa@d&|W98*8I4TOh+?WaMCMpp+H4! zi&}Z}V&!ePT6y~*;XcM*Qp5U@o=>olrQ9VeZ{-;)Z-{oAW40i(qOb`sgmVSdhvNu} zyp#|73o^c!>un9j$_ar z-drh#6IlAIa&Rjv7v4|^7v5B*Cg*^}@2|yz+b}F-)xm9Sa9#+>LUe^FlLfcQ_JUgx z7TikJf?HY4lj^a-l=$KGP#A^>u_zrn)BFnr6&|2m)GSn6FRlHzIAKMEkw-iSc+y^x zS)!`wpKxD>_as*M9vgt~JkK~XQv37I+AsUwhlVdwiKk^Gr$)rb6t}^V4sF)3IyDX{ z;`Inb^tG26j9P6+^=&b}zdDX{m&5R=1=oc!!)SO4EMf({IP8gR8(@^I4foKwm9&U( z#&%)5(1%8!Jk};9d8*ntW`2MvAqW(t^-#U-z~5nsuoKyw)46O;hHP33g4pF-9&5{C z92V4Cm{)7>b(&&st`Vx>9ea3ZOM+X&zs4qos!@my46x33F0MDvCJA4J9cDj<46u_& zPQUE4cC0R6u&O_H16(^AE^2FhYHKqRqehC&ph}hGWv$lMsABUdSfq$5%;TQFgY-@a zu0En`=+(zMvqJF2t5>UGxz-;~EBP|``ZVUqI>Xn4s&|90&ixV3 z9+rWxT##km)&;lgS&l{+Yl(wGD#5 zl|&4j?h-hG_#Y!dCny}q-U{LVTw5XB@R!qDA+lxUi)@A1 z=cF{CU}W*8F=Shngmh8QJEgKyJ?{aPQ5HnqqNoB!e-$RYiOX{AAGg;VR~_t^t z*}e{SNKnrV;@xRl(a(XZ2%Qml&~>FKk=oCpx_(@Pc?wJcD2CXMOh1RQp7>>HKZjr7 z_!9a#Py>zgndk56oucs@%CW6FF{@w0B-p58%83Fx+^iibIf4<{>xthY{Y8HMk^=-O zTeVm|hH7aM?bHLnqE~EHKc1*dRq78YK{ka{A|d;?R_og-ZMM z18_yXpvbmQi!J+>^YoF?^ zpo?THD3zY!{4<$e;|zTYxFPZh&-y06~6LrNn6*#_yYRERPSQn69F)fvq*Xf4`P zZFdE?V;tOyz0GFyrfthl*npA2uwmN6{`z+D^n_AYWPYR)!rO;8MQKM6HZ_!G?9-NQ zGQbq(e;l_a?e@y)(?F`vH>{)Y5bX)qg<#V6kpF2w;_{bg5anJavBs>(6} zhno)`4`e$)Ho(*DgT!gGuhbkB%=OJf6jhMzT={<6A7&?r)VA|*W#rlY0A}G*`g7)u z80BlmDV=8)h1iunu~*_}`kOB6( z1@WU2SGZ%x#fIv1bk7?4e0gspdL*8f<6mC+Se$so8Mx&*hXQZ<3Wnt@sC;ZUBgzRk zUMYb$w-M#m>E(OL+g?VLAG#dJm?Esei2j3b-Q}&j5q*|#9(nWNIDWqMkhdO2^g+IH z=Xd$op16CGZ@uKLml3^@Z`?~=KGthQ7w~OwdD}ZQXL)aV>K&T3+>j?Dbis0;Jo!Rr zE$<^weL@qK?;}t9gicw$uRQG=s$5QxEFW7KI%fHP^0Z&5bou`Bw0~&8^1kxaH&nEo zm|Q-#DAarT0rGT!(MUH)*OozB#GNy;qwm~uTx$kDf>6)Mb{`#Sdxm=jpPth_<&W&x z|Efdc3poNbyL}jnJc+R`-FWTY(l-@iQpYoRj4$+lWPASHclkE&iuSVbM%7TAWRO~w znA9&BM&7yi55C{mR;GDxQV}{DehT4p7=tgzyGOzImPfLa2q$BnZtI3~3d8QiJO*Al zN92jY-(w}>LM=cZVY&+VEN>F?Pe&ml5`5+nx5^yjd1TX6k$>L*Mt;6q{*X5bB4~fe zwO@%px(OS9SYee*XF-K;J!r4U^}{Il(jppNvu7m=Xf;?&MTo6+;i=@Yp+ z!zXgvk3cWR`H0?G-(#2Cfr4Uf;vMNTqU!+ABf^E4u{;NgU^P4M&~^|U{*jwec|OZ4 z2L6$j8=d7Mi6d^sMY2#_B=<|bX00vo*Wn-eTw=5v`45Mp=?B+xxlrn0XJp2&4v62d zA3PY1ytoDwDmekVLc)3SVOMChc9z>W?t%&)?w@ja_*=enIOxx-d?@!u!bo`@{2h4| zgY8B4u*-6t9HzA&cv`3SZ-Tdx=sqzy+tS;ahF30HLquXRJ`mkz$%F%GBj6C^K=tAXBS+mm>+ZLirB-%0%cQ=VIWq$}o zrR`5yi~{IPsW`*m${OJx}l-5&`;Z+RawJV|_CykPsd^fyM|G zL|+ZG!#9zo#MaSn^SwBCHMLaM~Fxc$oF_Geh! zh!#`P02tXdCl+@xszO)8KB$IbM`dw*$fyra+ANY)37Xjf{;5~SH-_g4mib*F<~JxP zyi}Tv2KWHG9Ha3v!WDAnqOhvzq8e&tKu?kVB7KMw% z3)4M`8Up?mnrmmLcbSk%>8Rz>Lq)xLJ7&WmMwS2^tiPONQSZ!em9`HZfX1!Ya}tND z#x0LN9~zme>L3&kyMPQYrUnqxGgj5(g#@ecTD#Gaf$|flue~?sk*2YX*WqT<;g+a7 z4fa`zimFitJ3Aw;RKOAW>60YZ9hNcI2Z_)Y@o@8~oSA-4QN++&p2fFvj1oC$)^mHJ>gSQ zDfQnDJ}nX+zgc`*7Ea?6cEM#s)b?Y(`w;b?fw>^+IYr$qL=8TqQ;1reGt(;-RUqn* zhboAIqj<;jwe0oLUlx2Be7aStKQ})8WIz}3shBK$?fTQIqoq2!gijH%cWJKw51*(D zKsTA8rUdqcPbb?`3)waI4d_psr0{PRpJvap@Cja++356xVc&gpsyR3pIt^9S-J(o*F}7qLl(YveCiLY7!}eb ze0qxpu}mjs_p<+I^{4emN|o#hpYBu9av=LRfKPSOY~L(C)m~!ZQ%87OafH;_ciO(Y zx7ZSOr+xP`Mcpkty>~#T@N|04OpjMofv1@Ohc4N7XMa}kCFY;5lorU1Pe+3PF4=dl z?F0*7J3h_D^j%l+=_Ij^|EE7$ntJ>gRid*&e<*}nmNx?c+aX7R~$QRnzn zJm|ZRPoAP&__U?3PYTK8=r*}*E9l7!8 z+QKg4Qw3T0+VSaiOow$9pZ-rwnwkvk1#Cm-@Hn>|l!8KkOzv@&nRB=b9YTMh0m>f} zCxCiVy=0+@>v1($kHa#{33{2ui?ta0N`lOl6ty0=pL6MjtBg3NSuMq3ze4DEz4W}F zT6!LcrMO|qLs0=z9@gV{qB2@j?eSIXaX4gGpODJcI367>OHuY}+;D3(&W-)Ar8!pP zu(C8jO)pqzgHewANy{=;;}Gpr$23A_#fdglYVChTC2-v`^ZT**whhd2$*qKcWVh=y zwG4-au4(vp5y-V%fD7PZG=olsW6(fpGQy0#5B3_a!Da4)4eK?yO02=rF|!(;K!>Cq zGjUQZq$krcGoaSsN^Hl>L-NEivlL#BZa8L^qPuCwOi#9B=Di}7bj&QKW2Vo%PSp+k zhl<31sOWPzW={M(j+q|IF%uVpbnci5DRsDJQmDl>v##Ep)L$?`#CBiZV%RK-%?Mtc zvYI-`dKi+~e44DJc;60EoR;CBmf^jX3?GaI!^2ZYa(haq^kUPBn@fwYJLK2)?&Q*V z_bh}wqPH*(s&ms;Uquy%0zw5&aduq%Vb1P_M46tPH<6?~Igf+TblmZ~#+$k07wubY zUZPSZyCaFUsjJw$5JsVz`N0O?OixaysyJ(JE1Hw_DT*rSyjVVC&+~6{-}^H7{4S;l zJJTP>_Us})@BDA3{#b}xB^Cv;VS0sv=}-VL-B3TtJWUndC6K=0w_8*RaMP|>bqAjLDSvz$yh7%L3`bljYf57`$E3pl@JPv(jVI~Q~`D(Y_W=nYq= zcr-d^re%sMcr*>j082KFNAouU=WY9O%6~HPph)zS$%uiWypt1qcz0Df{5g|iMth;` zmc<_zUyV6|dfT6K0y3CPognScSr1ji4@}^;^IB0QwLfPa{W-6M&5L%->CgEDcGFw_ zoJ;u(+pa9JBCwhHcjC`kVb1O@If9WrZ|kbF=L9f0G$(K{OxHr#y4c){r&=&g=6UXr zeGQ1(b_xY5)dPBfLx1u?f2!7s0`(`canZuCcRTJm&CsFLo>OGWdP`dgCuu9;KxHKi zh7MJpJUml}%5Crd%`sXUjdWtnwfoey1G-af_;lU_;=n3g6w+W0SF<9P?$mMbX@l8E zMFCE!s#DeG+J$+8TIdKqT@`z0=u92!L+v@W%-#xGv{U(~PC0za|tv_XefGNg!E}sA#D+U4_eNl zsl#J0XWE0Y9n^*1alpOqwFSCDfm1eQLSAQMAtNsi>&1B2k6d>B9{f`%GyJ zYS+(2pMA>SN!QP}QJ>O#Gh9C(-_h!2j^D}S5(2i3*-wk&wI@9|J(@h8)N%_!ub=I z9ff$`59b5oXTtlF4mhFn;cOH9SNJ@*a{jQRD<_f}*R4b4WqWhde=|OAYH&+vui(sS z;d_HycH=S{N8}Cf;@Zz!hdv)1>Tm!J&U8B*K!Y>ktho>3iUVkHCR{LW2hiY5IEdH| zpuw4i4hPWS%p!*aXmDn+!vQon)9-Kq4bBWW96*CJOB@cM!I`BF2hiZmGKT|baOQCB z02-WGt{p&wGb^+MXmDnwb^r~|tkw>o!I`z%0W>(XPCI}GXVz;6(BRAo+5t2;bFy{- z4bGgR9YBLKr)mdKRISl?J&-L?c>SQKwFl^wxs~xVy|E1~+w&uz(hc-ex`BR5H_*Ss z4fK%6j>%UYYI$*bFoHSUK%pMD=Q%tTjaFKdx3B+`gRj>hkN?6VF` zPz>oiA&UsPUxbyI8lH2oa@kCEA7to4f~OaqS)C{cPrW7=Nxn1*cP@@8Qq)4!oW3Cv z;W85yR&W3ofyeN!D$lyOtZ^G)sS;;NnIrHg?Sfcrj*yh@N#=l^#2IgA_YF&9o;AO9 zpV!csSCz%jq_=nTD9>@Da2T97Ja}F(&xpq0yp4IgR@k?SnAo@ z;tCDG4QQ$U$Kh7W#`&oD*xzHH#;-zPU&7B(@dkIQYy<8pZhXp!PDWPoUa^;APY>EM ze~0oVuO_W;Vx~KGRIE?(7`)MCF!p-v8L$uov@cPp_;Z$enQx~ zYB>DR;U#_zp$7l*%4^_<9^xC4;0=E0=kX277~bHA&f!D(q1OPgPT|{L5(Yo?3ciUS zdJX*0#kXDj&}&eFpJALdDzCAiP5jVn;D;{ICVuEO@Ix196F>AC_@T4jl^=QyKu~Hiw26Ou&3=G3@lUVWAJ8WL={0=;ZAFrI5ui={(`ya@wDl8OKS0}o@^m1ejf!M> zO);PiXDi_8dw{lsp%DVyu5R%c(51mpP2P-WLN&I zqY|^s$S&9Aqj~#vZ+gKQ&EwkVy?J)?vGd-ZTfQYcFfq~#>)p@*#llS2%>zYc=_*q(VcRDl(B$KW8vkCe0JhxzporG&*+qu%g)kx zIVlG?YRJq1j+1wY2GuDzUhpBn@enMjnFryI6C4kclmN%QJ`r%tIPbu2ulASr&|be) z#;F=kw73749N&h+ScV#!v%PYSZ)Kg2Z`#NI3y*L2X$8BZkN{pZ@>NkO*l1xCj0^ZIGgYXk`hf=^>LTRw_$%%CRUFcSRV8XjTg4$QSOv|RL)t3N0R*d{S#wBR#UU+NHCzp8t2m?utIE}o zwu(bqu&P20X{$J-1*ok1*>L+2CU+c7OV<|idJz*3s%hz_2$8^c$#B0zKn-N#qvQft1+#8&fE*) zXZm70T6W~?fvs@=#O3$4v>wE-)rqA*sHTf{sv`?73my9)*f48x83r0AUYOL%QYz?o&2-l4g`4>uZhY{`p z8R72hFv9)99^uX`h3e%=Er`7wd4FDV0M8`Ap$Lxu?DHogn{0f1eZwB`aiKC`ze;>8 z6m2#)K5j(2WRGVyK6V_>zAQe*K2_M210Q!go^=X_O&G6s2ZlFq0vMj&A7D5Zf1F@A zR#E~CkKQa`m@%H!vtQ=nyqqEH(O$}5zdH<`TAUlSwaN|Oa9?;durOYR885%FG+Zo4 zRKRSZ+i!`na#RtV;K$(-<#re=Sd?wAFR~VvYXPQ4^f7=!@)i8STq8^y?v(J4uQ!`^ z2{SNHi{g)qwZ&r~BBhv5LGh(9{mRH$dV;kCWS%=$iC>tJY16NQ6RZd5;Xc=ad7KlD zhj3sXj)j|mXJtPH%%iucDlM3I6|OV~ccI?OJT03v4xf?YM`Dgn-il!*8B6iS0DgQX z?N2WzRE+4q$s`!&nL?+`g*!7VU-GS8f zt&|g5Yaxa|GGN7W^t{M3=5FKIcfoou7h2{oEKP&Pt6(*AOrK+PZ&3N81DcE<{#h8H z*LiOt{ZBSW-uY{AB*NF&Oj%cXWp`Z#jQ4eA6WQo9z56?JFcTrfN?kcFG0_2eF*;Fq zT3229B=sQd?aDbJ)RnVT-yVHyR`g&{^&_2WCFREF=H@SF|tDmF46Ybuk!@}oF)D^`q@nQ%~7a0RC z^(N|y6LU)wO&C~>&8g+S)S0Q}e&Y;91=)Rhkul@1(zmMP>JVhf8?P(SHq9x(;LT4h zFHS8lZ3gbAq1l)NMSx@YN=QAmgjx%VuMO`cfj4`69#P-k?428u=hva=YkBv2CsI8;{+YAD`Mz z?k;j7GohhDPi4H^2_KqXEO_xIZ46@wQN1u2rX8$*dl(|RcqtfjpaJ7Lz+s(DI2Ksm zClujl-}!hC12NoQmQ>~%p)UmkEPm}j4qg2BFlyrqAe(nFkfUR&~mUH4W+Oh-R4Qm^B}#x7a=oya`hc6FKs!uEOMbe{u(jK`3X*87E8)h zn2*d1v`sTS?t;+RKC7f?cW&mlD5+|H_yjOreO1r$@hDpay|%G2)n3+iU8)VwI}HQqF>aW*d>_mw?mF8odvRfW zxYe$8Gpayn>vfnekYQjF0&%U%*Ef55&?51nRa?Ug6W67xx|TO2W}l^6Azh-jaVo;7 zjBRU7wdKvN`WqYMJy0C?naA7xQG@`us$KNIO`7BL9AJ%n5R{#aIJkMzLZ9a)guTSs zYh1fkN{fU?qcPDvw4Rn4@BC3@2#BMMqxIAdLb3(TX4L-yliHxM(5F5e1AWSC+Q-5p zLT5%kcd2}=tecD-e-dG2ZJ>RMJ(Nv9ehNXi;t0xV&u$$15kFOwLJ(B_Ti?izWNAp&A&DEI%>_Y||YQ*EFi8my7088JVSTO$Vgu zTX|L93wC*Tf>n^(+}!s|^Cw1X4`wokc14{S&r(QSf+Vc=y&x5nn~ z)S-`}5M9}wv-HSSqFhTQ+S6AhN`Vt>m1vykC{T&uRmsqbzJ|FV`t&ER746K_icS@+ zzJIM~f}#TBm6}AkjMl&aw4x~=z%zUVTG5m@z!h$-=(YZ}qKo!q(~1To2S+RV9<`!J zUeC~q{sDE`r4?O~mPD6$n~l1+lptE3A%D{RboS=n{PbVYuOmmMU+3;QGZ+2W*kFr?921K^}TA2>2j`txhOIO!1j^~l$=ancjW!Qmv) zudl`vmwx>q#IK8!#;dw;P9rCMAdKkGre8Ot`RUIv8B!}#L3go8$U3Axl zWX(3uwPu^@Ub9W>s+*dzX3G#!hg`Bn^eYS7>T~03y!xJK#~!_|Kz};DWP@=tA2XIE zoOX=G0uZY$im16EC88SD!mS~`8b`YQP5QhqX9e{pKbCG&xO6+!wRH1w=~m}AkK@{H zEZ1%$ZQT*Ca`|eIzS^(9gQZlWHfKb1&)$-5OJJ47F9~27w^}WPWf@nQm|K%*DpSk2 zAQo|{LW|~S;qxH zXoC@Zm5deur*I{(P2?5q^1TnZ`tk299!mpaxZG?)Y9x)X&QIP-VU>q_i^T$bUx!7W z!((N}FEB6SbK$W-v+>Q}^EMODvNtoH?Ydtnfn~4aV!;h$Eu6h3EC!QBrd?nJ^o^Nd zGHA(>(dHQ3&BFGrnPf9OQlO>i|qu z^|<#VJ0EllP~)Y2+BlB<)pP9XSt?_d%lR?%@Ht#?N!E6rC`)C=jI0brxkTgDQn&IT zGxJ>JUBotrVpnTUWmeOitb}06Bx?p8n6sD+`YVovQZ9emN#^9Y&$R6%P!*x8!63%b zHs3Ycf><$uvO+AP&hvDTp3hK@bxC02V5HjkECn4#;;|fw1?}@ZE!&D(4y=HQXkM;L z80j{BC>dEqeuYy28&Q>@R7K*IbAwy=O9!3hze5S=4J_>B{!_fq1NfgqBXW^@xI2f~6*1vA zU;I~!qx`!Fk*f}{V|~yXKDGv8gUVTUn_n7~qYO1Hgz1(cUGnotWSodAC(lB@tF`jn zaL7Er=+0Bp6*A8oBoWVI03q`DpTAWk-hasKCiKbf*GQMVmLy)FL=YG)C$iAI6jpJ@ zpf5D@-P+Pw?3aw*k2UOre8PXn+WbDSHu z;#*m_^p2O``Wt)*a)12*tWocI5x?6?v6#7o*q|cTe6|1e$7MFX8tHY}t184^wa8_! zs&uUP92zxXr4Z{X7JMDMA;YH$X9I1F-v)eAuh3hpA)eIZ*9)q!Krb+6L3iavR+H5! zgOMwsTu4w%7Cw&m878Yr_A*{)5^*F1Y{M+uF9AQs^bwy8qZJ@a_wYKB&rwRz#1*O+ zg0oWhW0A?plZJ^hy{mml&E)XV8XTzsyJ(~sasbC>z%&KBlvG?|Xcwe*#YfP9G8UjO z1VvqezX3pddvdjPd6;=%o6=hUjYhR}46Su9TNrK$u~DH+w7Qq8deWZS>11XZsZ^2K z%Y(5>OiMqZ0T8L3pjCtha+qzS5$1Ak#yT z=@^vy&^tETy)&8`dgEnjIwP-|bKL~4Kv66O1n$m8;D+7V2%Jv>@8$er4o5Q=#^EnR zyV15*X&EqUXu!mT#mBK?bSi{7C$wV|btxDH$6|`hZVxOIdm#EaMJvszRr|H*y=VaR zcoBX$7Y8jfAdC&_fMHfZ41gh2v`85MSDyz1;JM^V8y!Uh;Hk<0NFqm~8EP^lg0lY= z+4jF8+y0lqPGH?k^B)?)vHu18*#AfxoZR6HXI6DCUx;IB65(9i4ybLcgZ*!0TT`md zGqdXX#B$jG%yL9ew+2lSnijizQR6~1qv$7kelWF5@0nB^40`gcyit$Bs-7Df^bbqA zGCXSR8Es=IRdWhrUiTe{s7Z#2nE8a}GSkR2>{@gxc1L5ZvqSvSA?#;o;Id}DXyq+F|{&JG=Wwxzd!ihBFW zmO5V66&h4$o`n=y7570Iiu)i@+y{x`K1dYzLH~Kh{R*!1J}Je$9+`bC#eE28#7|Cf z-$0&9EA9{A_7hRu%U~k=2#R|ZR--P({TNP9A60Qb${2v+zG8wVhO@ zVHD6dMGBe#UxAOlkqe2>HOy}^zVo)SbYZ=O$x(Gnq{$6mVJBF-y}s8i)KFDr=m83g z%mdtiy;WfWY=As1wAgC+BxP2_t)qPlDvIDaL3l@rMt58=najlpk zXgu|tO7l@rSKPuz&8pP&63#?5kiY@KT*5L#U=s{6TJ2t1;VV(~e4J)cWM1y91k?p{ zNO;#*b%nnGSVtX{wRr{A^9sY`5{+KHxj^@D17dml6p^@Qfv=h!@Kr|O8v$RHr=nfn zKCr7hEZ9}4d29c$tHp}FEZEgCZoYLvt#+BO8xKDX-n(YM#d`v^y7pPHUtg$|PvwbL zZ!&7OO0OTrem{8wIIy?<9xkC;$hIRk-@71Jhcw<_F2;M0WxU_p*Lbgib(Ha5Ecb%9 zqUF9Y!)$*REg4x{i=T+u-uuiKD9rj=?w`iU$7rGismp4)AFaqD>n|@ep4ldxZ+VC; z%RL6M;ICYEdzu%b^fV6CZvWh7=njtE{`vmw_W#_H)o%Yiq~;)o-TrpUx4F1?+wE_~ zlmVs9u{Dc)R%$*;+?)qHSQ3_-^$`FywjI?Jz%`kLfDuB z5P-1$67Td?%Jz}%d9W%G?X*8K2~y2RlTs<>2N&8&txUZ@9@-|Q!XS`SKs?c|wDKb2 zotkW))f~>nT-GuZ2k+#{!ZIW|1);8Pv=i3Asw61`R*jRCRins;I*9OO}Vb+ExsQ()^j-LZ9e^?+iS0AqD3cd+sM7~U16KxRzv(#?AviZ$`5bp#Jmh6XTBjJ6V76k&$ z%qfC@!quczzJ&KN0HG#EJ3oL8NRb3D#mAe4C8FB2x&xe(+6YwzB-jJsj_Dd{Z%ySsZcP4bIM`X5zv)VLNmDdcvHZ*XF*j zzmH~9FsIeWccyYt#rzDUll~&GPVyCyPUi{IDWKiTpod@-aoORQTRR;4*xG}8Q>k;c z=oQpO4(8raV!@qw2z#N~)EB$ME=}%14vCw+Yu^F-W6fH^TtZs3oHckc;r$hEb6`#} zzJoSGm5LPJiQXWZ{Q{(qKt_c+s>K6uP=C=#bis6pyKe78%s{wTe;{ICGG~Vf09Ont&0dZitphOi8qfI^Vu?w=7|1(?3`8aSZ#Th;j0eBpr2G-q zdDjF*NtO$dB`RtpP#+}Vr=z|qpB_SgPU8=*xhsqQBI*m6;D{BNf#VO93Udhj0XIpx zR2acWWd$FEF?mG)b6U(3V74q;%!i_oA3}?nqsX$fn3R$Sht*=<`IlOg4OolG`z1Ka z(PEzMPm4MAiL6@8%a60|M2lHZEv60kZY^dj^kJ74Qdq{>%Fj27;G5h<>&4E$GH9c&YKSB<+i8`I!3=?#@Ks{ah_}MIFwzA7QYfLini2 z_ytBgIxG_}WoyH(-3WIbAzJFGUyzMlyAj?LPRhC);SY~lyp*vUA%Pq~nc9tTADO8d zPb_BQZiJQ4c^zIVGX5;gqcmcmrJe^Llb5o_S9am0e)aAD8+mnDycF=x4nG|ZFV!i1 z-j}mJp@kQ>k7f~B=c@&6{|m2gE3zz+H5;>0n$`MWcvT!JVCsUOyG7R4{zTSFg!Q6q zx+D`YH4&-#7z?iix$L)(I$S1zsWDqzY*uD`f(bt|#}?B901U=Q}`NSdg~#7x1?ieMgdn0ZK;-ZnGj?_#=9%RP{c}^ zfD{KMwFTxV4#NIXQZy#_K}q>hBbT$~$Kd4b&X)LLK~ifikd*9atkj2KMwYPqP3)dz}Co&Y_=dx@*5;+CS;9Ki$CI3Da?tS zZ!R>srKOvs{|Iw&Ul7z7&Vz!TvO!R8$H^}st?(9zL@My&4!WNL48D}-9uc<4W^Z)x zL{HsL;gq%qm5Dt_@I;n9=##_~9mEt(r*~FMbp!E3E<90)_ZcRkkB=w1=}-jhAcn}o z6K&x&_qHiKQE65@QKi^@h5${p$`_f8rCzZZe)?dEV03t%JKfyYAIJ2gts99EAdn&- zE*wbFzc|h zj5^2&exAxSzUTyU)kfGQDVw;+C&z`VVB|+Gk)6p`)FZAU`NVkQ$Ev$A?w^5t>w_*b z0dnGpndqXgA(illF%|c`!`tmJ2(G@mbk=M+6Tss7voF?cu*$BEYD?wfo zbU#~fzd4drnZx;)`yMgyEKrda8;ssVVKrQJ)+QX+LW~8vJ4=$gGz6?%vS~9sy{+5AN99!5D z3m&H7&iWU>{sVZQZvH?oi*|fawK*}L_B+*SRr_!FV#$Xy>@U@?ws8irNT=BZm!=1@ zjYS%1nH^^+9MZ29Q!tLYben}jlCdeDj^GEmRt<{dx$zK@iGnW%*#bh^NfWS*KW-AX7DPj>GOMSAdmWnzWU29GUr?VLm-8b>{dxn}EYuqrAH zt1}8}G0{tAheaICLjIVTNWZZfqku|Ami1JozPmK>U(t8}kMTzTImP#%Tqb=|ito$F z>|-jvUqcrEEyed}Fx(L+zT0VSI&#H#G-~8hd>`ekkQHTgc*VEP0vTmje2@8&j88}L z9j5LNulTP0!9Wz>AN|m+_+E@OO7R_ytF*>?hLzW$72iuU@*2s!G8Nyye19N{Z$U;j z+mS{oz6}&c=i^US#rI)os(lsTLNG)BitnZemv?61Qn+eGY25r^8I8ycWYeuHd>jZwT{7agpx&q@a*_BfAzFL z*sH%}PJ`b}mNBLJ4tU)fg8KXV0n{8$_LE?)R*{j>CWu8OrnHdtTgl(@-H5-GV#M>Z z)_rJay6|dno?D&2x-JkI1F}V}L7c20>0^Tq$6mO-;gTdbPB>A|-4Q+beiJj-Vomr4 zRi3SF^5{F_3xc(X5vZ13AjrpW*k-B5V9mtHRj~e4N6=oMLLzMwfm8i|K0WNMDT`b! zGj6Ij5-8m1MJNoMkLLwRS3#X+LwDx78HN>X{RhTHGC*V6414Q= zuu0W)G+F}0&CoUl05EI&3a<6e&_3_&p2%C~D(v*(?w%lNhgmMJ+4_17iuGf2Mh(g> z(>CSAHBiM(O?X_1$6D(`6iE)X0_o?4aB!gMhY}zgpTHHxBzCG|U?FlIiTnbmf;q(y z$p^?&$blOdY7lGk0#K}YmkA@Y(!7iJ7L)N)Fj{1Czua4%D&LI|WdU;m8=!nQ^TKYi zI*Veve$&%|w;WL5}*Q&qWnAf?5Zt2|@0XF_n>pw{Cu z?3H$VtFoRqyNs`X7s3)n8TC6jn;G0#PxF12?ry6a|ie+Rmx+D7T^mLL)0wn<0Xl!t(128$l=zdMc^_aT) zBk)8LDBECM^o8v9dSf-{17;^KlP{x44FwhM`1f4aiXxRQ{=H*v8EEYL0;M8k#btBu zu;y98y!{0C3GP{>w-_o_p>gs(Bqk6)Gd{x??PeP`rvi8Yk%_Jxya5R)O|h$Q2{llp z$!}dvxaedukg(6LcRias-^xvR=a+Qq z^RNUsH0wma0oFNZyPI`FLMd41Bn)4)U$6L+4!=zJ(xLdJQR?O}OuBl#8K!Zv%`j56 z;tYoAziK1;u*zd!{}&G1=pzpud2{W}hvAoTA|MF;4>)>$8giSKH=^S+1{gIe#u%je zls2&*Jf`Xd`Ax^_Nn=Z2Y*Px(fT#? zerT(^_ooR7==~B17508_`JL|no7kR#_^JZu2x@1#0|1k>LpxpKZEQvem+=3wWQA@j6@JS|)1v~J=e`Nu`}3WIa=fhL&8)%Pf`kHenFx&%;#1>fVhg@=9iC zt#PCf;UMMaC%=Sya5u-)1w|8=;gb9=imKw7i8Gk|{3svQ*sN%MbXiUXJ#RTYXmYOswz^mt?t}L>ObZc8iC$1jQKp zSV1y|FIk7DT~|`g%ax)u)5-Vm~7yKsPf#22z*W~$`02?`JFbu_EX%0EO5uSR zEAXfc?B*scN(v#(8?kiqLlD1)cjSBH6)_){LI6-UCvWSg`fzXFd2EIm|#JC_>LGBl#nz=}l7`=sf?n_qnLq_J1 z{qs;E1k*f{YppRP!i=fib~!F&x=-?`3Mo57qIQ>&yq}b3=`oM1 z;;U47WVyUGn)DXDCgk=4^P=cBuRg+D;93m^p(2%AhHN zHtJ;#WQWLPv?_pDO=uF-5J78kYShMge(dFooPky6*2tN%!smWget`Z&74qV_Smbjy z*IHSUdodiJ7w~KiZ+Fi%GbDm{wu$C-oX~)NhHrOaQGAv!dcYrhWu>&AjM@p#*cHFF6x;#_{W*V*MWLOSLw$ zCid6m0N&TUJr0YL? zfc0-bWc>$L{vc`pYP)<99Rq8DAuPVndL>=|YmTJ;P(-Bu;6v94_Sg5{`)zvG^^#Nm zxkpky6(Otq>VegMD2hLH|1ZtUv7>BTHo)TeLVr9L#?p@PWb0Ji!2n=>YQ1eE#Cw_v zz46mbe>Y|r+p9r&jRRW4Cn+N-tkSe6(@d)p;c?u8a0Tfd2udWY- z132>x7TE%`#xkqA%7ZEPMEa1@me_H2IxSWU5inJ+_b2OcVNpKJ%5*Yiho>k=|vZBu}kD@Y=pycBiOjT1s3Vo%@-ZAal6Cp##>bj zd~uKYT7T>JOTPgA>et@WD04}d%q0=;F2fuI!9h`gX4 zWtE>du<~DNJxuwxUCsU+;Ch@}3{n0*tjC98j!-jP-*xxpD6~KRnSk;*F*`%@M2oS# z7?Q`>{OTH!d8)IyL+D&^ewoGjqixP-PIL0f;E3`b9@jE7PmpE~cgvtm@*F68Tn@&# zG<{A{BWy2|#P*cA9DW1%`9{ltQLdWsh!A7W9xcPmYc3VX4ZTV-ruG42CXPr@5*~&D zREjZGZ=Pp;B~FMT@+pvp_BaFFZw}%pgnwhzXr$Cg-vRj|ZqcxY`V49r>I`P5O32(a z|CDjwkYm4p>how{GzsG74S~QLVap<{!~$kH9SM|F=1KMy&j8mQPYDvqhk42?%#D_T z_-UZy3{^jUZ-j0b?3#RuWFlxjILC*^hojXGZ%H60oR1zbXQ)oYDO&REJ!DF=l9G!< zm0TQQj<<`3G}IXEZ!Y{&JNJ3N8j6epPqz4QB7&o?ZGqU}iZ-6TzvAQKv;5Vw0^z)= z`YgX0fLAp?2$x|X)mYq)A8pg#6jQ@1VUD)sF=edv5Td=cLySaWThdNNV8`9zFDNHq zB!c7;T{KpR}9cgfOx1u>ET7_Bda-s2SyNYB`uz)XKNfz+g69#j_Nps(pROP#) zT{~M-I6H?a;cvTRGup2J`W*U2yLB}>u54HMW~&)Ts%AVU`3jtJlHM*0+aTJW#zW$r z=h;oF#eRlIiHePGw<^fC86Kk`QL#*lQUz$OjI3_uS)6Uo}atGQ4X$bVrr^^q`4>$ntBBRpoK77awhGOK5O%5ZO_8>uPv>t$g4Z|S$H~jV& z4`G=>wr2d#%OTHfOJ1>9AYh4+K$v2^yXtmPov{`P#hTM3fjKFQ9nH1% zv|-@)GW;$|Tj^#87t=&{;8wAA1{)6V z#Ry0E!C18yAL2YBM&c~hpVzm8?+cSU$O1$AZB~n8XdwZ50RAtuXb@kQQOMBhA_f)s zlu^%GZBs4X``~_twJB1IO!38`THyvH4S}cWjzev+q$j4_r+3Nm4uyJW^(uJnC3>X= z@3@!t4HVwGEj&}f5W<6TaQ)HixuEqof_He{8 zr#vNJYpri$)o_K z-{x8UcC6~RDY0#lX~_-f?2H^R$k2bnFJN$%i65(GCkKR?=y zbRt;+G{pD34NE-p0Si%0Sz{#`6YcQI{GD08mA)7s>+d`GhDvDN`Ywb*dSCw=2N?%I zYYKr1qy~z~twI^^317ejB1gzI;yAkiS&fwWQd2-1pH$%q^beEvSOi2x{k*u&Pu7(G?71mG9p;i@~v zmG6coV`UqB*aH&T+(`wvpyk9uQ=D#z`lIkMxL|y2cQ|Mk$LT6)fCd1Z(m^ZjADynk zH+_H>ki*c-uj+M<`q^KCk)!9wwvi(ooNXLjOMwUr$D6A~Oj`@xbUe)d@Dz@}?x{;4 z|I>JiN=z*fDmGXFTLPnZfB)YpiKAY|yKmZe#k^Z@-xcw$&AuxD@S+lxhJ;}66ash= z%nH2NE`}Keyy$&w{M?(Jg?qX_7c@6T-`?xOU!*Q}=>JIgi@{*4UCD&MjpUM<`h#Fh zaFL1#*N&dG*_&hBcN0j>?mxej^c@O+F$AWo=+oAD+7^&Cn?KY6vL4DG+GKoFO_3iF zfAQcNnP5K}{^H*=EQ8;F27htR3b6ly2h;3dX#7jK9_;@Xh6WmO0Qid?7qLG+F8*Sa zRn<=jfAP5+`{kbrLhm8)JKeDGe1iP52y0QusI2^Rc>KkZRekwq;P{Itr`rtl3F9vY zEeGpt!hD*B?sTjqrC^;OV(g;*`dfeB_31eNi#ZlGcM}WVWE`#+D_={Sco=vmKCxpKk97gYV{J`D& zn=!XY?>~T%$KLN3e{okc+jF4y9vlL0*?T?;{$lYB5CbZpb#MH|Ug(1MlFd(&`rt44 zHY@((2Qs4l4*o*={6B)fC=_iZJO1KX9~5ir@ME6aj_KCMUz{N$5Eh3t{$dv#9d7)^ z|6=p_CxXBD^i;Qq(Qf-93QD6N4u`)8k*tr2zj!HRQ}9Fdn0DKH@M)we7#RKnXJBOY zHo86YDI8r7UQFXJJV<1@i1%@2O~<1@Ia_6w6@O6!V=S^r77w7f^>%TBzxWyou*zz; z%kn1o;L`09KLq~bBBoN#@P)k0;#$pg<_1*xkQrL*3Z!u3FRo$^(VaMA29T9KXmu*9 zTX74uHWqx@deC7%*l9g@%zm)ddhn3_pu>8w!G0jVR!E6V0LR<-jA~^Xz%g1@;kLaY z6TtC$OttneVa*_cmnm&J7PRSEWIwR!X|NyI^wirA()9F&d$7KwsyE!@My|-Sw6mM3 z9#kk7y08iN5G%)FlH6z~vEd#!(Hx@S9$#d0kPm&yr+FED8x4v+vMczS-M)4Oe`7yL zR}cm$8Ipv8Jm)mH4F$PZdGM7toVCt^RQjzAND(N=tF(S7@^-LAK%OUgBB*1ZSZkql zpIFPGG|ASANMYGriz3S(Z}CV-NG5Q^?u|5XOo#j_ z12|%$fvoE8!KDoxIRkl;`WBm`Y$jY`Kd}2~nf<`-qpR!(?mkMxOwtuT0+`9YGP5`^ zldtvDt8SP{YCtfPImn4dK@Qw9>69aYnVj1X8JUvF!n@colXfH$n8^}cD45Aol}~LZ zvM>W?La01oCRqJs9iwiTNuFKtEHIPLD45BGnTuY9G&$P+aA07Q;Vl$d9~*39pjICf zY_hh>npOV`V3VI;4SjMMz&IITlWUi;EwG?yx`r42OnZRiKbQCn!!*e<*bW^Phj~ z%Iy8`_*>_({D|Ki3d?e|(+iJcJnvx-TwYTw+vzdNc6xmDoE-S`%p#Ws+IF770t@r& z>&pB}=}p(iRLg{ZjI!C5#CAt2lI@Tz=?oy>Yl3YHg5zP0);8jo*}UXf<;zn@a}oA( zD7Wj#xW^omPK+zNe0o;5V;>cqfqK3KY=Z#Lfe{_fi1BuMtrb{|v^#JtZ&XdkSOuJ@ zYI=&QDXK8nsshZvG#{S{)9|@)id+6>RqNfV*6=Uv#^Fz{3bkAH+3wUwS(e@KmI2tu zep-+I>DNB?N#j+vpN>}f=y;V$mt(9Q8n5!kj3eOpXQB02{60Xu$^)Ov&hO56yL4dX zE4<42>GB7NS1CDM`ES&*KL=>Pc$T`!;qfYuepWTR3(x3`?`u(>jaTWa4UXr~E=!Ln zaf?LH!qCP$bDZ!tV`yVg(N{?QAFuwuHNoEcUMGZpW)%0ly~BLIwQIB6+NmQOMn#ps*~-_0+-C zm{dr))(*Ue>s5&j7BSo&vkI3(l#5>~y%|uHqs>{WmJoaUBE!uZc%A@k*%v4pfhNc&%wo3AA2lJBIQGmLPfV8FO!#+|tgz6}Xdom<0{Lb)Nd36^gsiDGw zxQt;Z0_1Y64U$RzmE2K$4{q1UfOsVwJxkzc$i|GkJ4Z)5;dRZ^CD;aVz#(5 zG@t8*U=d(O4t0`Mv+<`daJ>+~Q4Cp8G1qbYC{&CbTksj)M~Y}aWe}PkOaMq-9SLeN z?wNoUmBS>TXFMFOzr;gaagxwMoa0&;tdp;PD_=1RhhG2yOLB0m1UCK)sAFkjwWoR& z@?t1PZ4>tnsIRbf9~cnl%XwrL;557l*D*b^BC#5Wwj$MDFkJtscq)FZoBXr=v8L?@sPk_i=Vfl15sK zPTXp-Z{WV&qBLBrzi6&u@#8S^(Alf(H~Nd=v)J@a1^WAK9&=7cZRT^rV+aR;C{&Fi zwXX8bDVbmQ`Zl}(qrumnqZ$hbn>fXA7b=6FfNOyssE?fC-oAdwJR?tAbLMXIm&S`1 zVtM=3gtfc{nTpYF`;4`|U4BWQ_3hgCTF@*qgf3azwe+04oc4vmc0^T0R1}1n*(k9G z(A4oWA%|8#-~}eO%?^&la2|!5(K#5RKHQAN!%+yP6aajH4BXJTFMJ6mrG4$kSitKy0)fZSKhwu-e8gX&xhv zr%>^j$XZ&ja)9*#%c4z*wDKap&-c*Cxb;e$003*y&?^82*lGdD0R{lw#_gYmf|P*= zaOBIpvt9Cq!MD&;Zu!z9(!i20mV2&W`GPSSE|kOPBz0cW3i{ zRT1NlSVHFZOC<*x;=fD^h5(`y1rs z17z$>8!|QzY{K|8!$rDWnYhs>X+-C<^X-*}vSqlP%&Zc+$S?>Wqs8WP@iinqx1f41 zV|9AN7c&+u1}F6$t(E%+%&Q8XnfV)<)Zk?l5Gm=^3{kT$xt(91$#OY(%fVS-2@YPZ^F=i zO^OWGP9AjHwF?ikYlaCn8yT=9Q-sbUPeWKrlY~dxiG;}O*c``YO)c*m@g9YDbAaSv zibhWom6(JHE@gbP3DV;NU@yfu2I2xTO*LLj4uW;864C|MvEJufK7>r{DY*13*AVeT zH&_?kfY%B2gMox;C4>w`;{VC+kNDk@@z7yCaJcG|X(c$s(l=-}KgNwL^q8pm~ z2#p_-`Sl+2E-a)G&{cx2R4eKu!_tz%Sh^5mBGcasyw*c&82rYR8 zfe=)_h9=``QEqW6Vd9FOOD+@?cU&x=0zyDB{t}k?X@|S+m5w!Px zuJqW0BmAva0t4%>&$-eUTl{?_=4X5^L z@1sTC9pHFA-Id;I@5c`_o-^dp-%m-GZ?*SLN0R;#S9+_xs}7U?lWuP{->-d-F_dgE zT}ZNQlN^`KF_^5e9(XkPC?o4zZ6`;^)Ocf#*bxeW}52CoULmWu$)#> zZB0iLE1` zFgGkJacIW$0-%2iQIF=t%3x_T)@AsuXx4W$VQqOjH=Y6GnYzx4yHI1p{AS~IVf`|m z*~Dlsh~@HAP&cKrikJV3%ZfA3oPtZ%psf6~(@_hqA>$+BGmB6ZtCF}w-Zmq!w45N0 zr3tYg#roEgz0sb}t>h^$foKP}H8mKw&XGE{cA#DT2;R$T;WaGv6LKPB%yDSvGPI%W zRFj8cZ&%LbP}TEVbPvjEze9>NPe`wrN_MnAT0`>m9c^WGq3SRXVPPM(pIM2}#^Excn9vkjn|-_KjEiv{~dMDpYTs{&zLB9&!6yJxW7}~^Cx^8?!Tw*`J=_Y z1TMj|yVNuOXtB?$XLqY-{Lx|;sAu=6XZ+D(=i(U(x)(P|cr8<17H6EY{NE|`QAH{O zdzCR$jhAQ-Lc{zXpK_V4{6ma!*0=;S8W4!y?MvTC({5jp|9zQj88O23ZXKdK7vSRZesoYiRfvle}l1h0qf;Au09|B&~EI)_2-07 zQsoyI`FMybnPbgSEYEm)ywV1_BX$hFw#b}pkqL%$$lM1qWmse1+Dlg*dyVt!Z^HLERhR>S0RYP9l=HT2m^*3$bYzeNL}$#?0@R% z{pqK7r!UFK{D*JvP*=R9caZ;Z$q~nYxQwYQUbdt!+w4nhE9E6>z0CSu!C!2fT1r0? zhHVROaft}~QUYz2xV&3EEx;vW-|&L~E{Pq-r5~594=&YVX$q5w(To_how_%uGd}MI zOi=OZjICH3pHmv24(x&MNvsnHW&($kp^5Nrk&>_=uo5}u2s#~)7vO&bWJU=8>({S` zX&<}uU=?lcAUQd34l18$9%2=oM*kQ%90kKFR0<}C8A^6|mziU^24V`Bk<#J<{sF&0 zJEkaH1ektEJQUQe5Y;=G!B8;$@yR5Dzd8P%bOsD%fHUOq5myPJY$dAcolmD&FKme}tQMqqjn z+Ksm9*?r!&P~>85qZ$MoJOI?Fp;7r=VJ@weynse3gD|AYn5N?CEE()kMU!QWlTds? zus(Sd<|mZ5%dpahwL!39-4GAhB*wc7N}$Y3%4d#wgD{ya+^&~X!>;Cd%cpPCIu ztBG?vHlu>;TJi_@aWzTF-c2m^Y!(W)BKY}6zi0R3U;q@nOMelyYCy3ey@xxW@T?Qc zhEv>XtGK}^jo}DYsS<*=LBy9UUzy9e(Z6p9}(FN=Biq(>J%gS)1N|LkS{!DOUl4P@3Ju1d(PEdYC-un=QikI1Mq-w{!IOvu@8Qj6 z2o$B_pq(mOw`s8thhWqw!Pm0Vlk(^~s1y9{mP zx?l@3ZF|1uPoD75_>&^UvCDbKuD|MCo)5Lyv54o!LBN1}tq`KVcv*b4KVBEmVxLA9 zRozqRzb0Wr;nG;M0HPT|&Wj0oLxOlJpjKDG?voEbEEYQN1=~iU* z=NfQa$H{31chYA0_HKMDy&{T;9m7LKOZt5O^0o@{c7E~%pNyl-8c`fGRENY&`W2$h z*)knA_n(-fd&w?RspRvE><-Qvmh?JW#px(c{t7SBmBCeJd2GRNGi_!I-jbOeg2K?p zk~s|C<0C0@nZJ4&`fGx)R9>=8a@!zam#de^SMpqI|kHVwmR7*iZ_sC=0g5^B7dHxzW~x}%v}8ih}PNq>m@Jpe7|LS z=dL8i+T|NO7&&2mi;{(ltGYO#cn%8lgcMq#zv_8^A3pRX7W=Q$roXCpf83d7D^714cM&aq=Stb0Z|6SYY9f@3O&hn1cTF*hY)AZM?UWoh& z&t{XZWEq}uVBvUC3@k0VodYY6T7h+($xeL>jvAt5k`_?|67sT4-wr_)+nrb!Bt8a$ zLWSY1JUTLl8Qut}>kJ*k7lI)f!wnzai(hTykmLsZX0|)ZXhAk29Af(tj|SJ`4s%5X zGJZ5j#jY|BK@jZTj9Yy63^JKcvGq3&O(70%Yl)>Jk~p{^R3jw16T6hCk!rY5TrGuy4i6i-t^WHaa$C8h=(wW?Uxus~c@ ztP}<)2(?+1hT4+X`%xKY+bV;*lgS-sq0?Bn$gF>SN@A`@*V=gU$5KZ1SxW4~(0HT2 zx-kIWrgi~7E!ORRO0TR^CMZJ27E*BwxoBmcU&(o@A7l5E%&A zC38Kd@O2V8)f~)kw|cf$y&svFBo4uD1AMT7{TY+*Je|-~V^n1oUvGn^X3vvn=$-Hw zUu(^i<7MFWUYn5V!_{E>xk+k9ecBiNENZ155? zP_K;bW)_&9QLd#~!m@(?tOP}r@ky=+GP%l<%p&eBx$Kh3TzYD)XK~h$W)!&`&ZA7m zD%8>vQoG!lD1K6;L{8nA#NydJ)BcqCIiJgHK#Hv-`@nN*?GK(~x-{`Epj(^KiBVN4 z@yIeqlDiF*)7ZFU#SdKJO0z$6<;}z-d*PA;^CB97VayP-}&vnTt@LJ3lBoT;Yx2+Wa120TCLS2A6cEO zdM+t3+ot23BdCk6FCc4%3va*+iXy(~QZJ;K z@VD@SJkJ+D#tTfFLojqwIHfF(J=|i!<2pTZ4Q|Wqu%;3$jBCgGDi~|D*wI*@qPmwM zqnv~a)kc6Dk!@rrZ$i~dx7HPpPKUj1B|g_;e_#t{G*@yb9vSzX2Akm0Db}G+pTmW5 ziG8;a7v}lqOp{czb&V}UU;socZ&czjb!kq5mS9`)8&Ez)CP)dH`DVZzVfxKsrq9eX zy(SNf?~=Y@R*^=#l_MA9O7+iDT-}ZIp2(MQr5a9iHC(s?bRusE^dX>ujfXZg?nHai zJa2X3Tzq9`9=;FB?Jhh+y-;0v2VU4+Sg2k|(cxCSu)A=OdLfi(t=FUVlPme>Uue2) z`&ZV!$4?FXr~R^UjLZMQaCItUxC?4waVv6~jV{duVA|sRc<4N_k%Ey64vSL`7bDrB zLCRClWp>#^JNz2LM;)`G#X51_KBoXCV|Y7?b3iO1`?c^YpkZN%gb+-??3Pdwx|@L6 z3i3~BQ*(yLqY@quK+GD9Bw6oiaeB0(HK2>_^LTKi^z&B|b_TaYaSi}oXW~STF7V6q z-BY1uSkJ>nG#Ap320(~qJcgmG176VkrmEW5@5|JC43HuaS(vyvRdwKoVe2bBk-<}| z4qU$<#LsVRGS&$(K$ZiCDxn=uwPYm?*(ZoJqJ7)3-w)xJmF7?fEC<$-gRcOt&Ed5= z)Xk?3b@N5WFv24=e`M0A2!@Eg2&tiK;Dn(f1a+ikKgYK02aSVdS#%3}9pkx(bq7<^ zvY+-O;3b#_mVI(#B>TZ_Qby!n^V`PDr(o#b{u#_B`IfbQtk<^IcfnfUrL6TqV~tfb zIM69NCDwWtZ8x~T$*6;9fNQ{f*nOT`$Y$c3N?but$ri0fqGO#5HqMBSm2nOz8JwFJj7SZJf1MY5N)hcdextwS`OXh>t6tQ; z@{Eg-ALsQDj4vGcjZ7h88{jOVaF8SCJnEf1FXHn##b8X}@*_ipGtCnfOIi$xcj0_I z(IN5nor>b;6f4*ydk*0bu+<(JBOHa5FUClL&XfJXzQ|jc{;(O}DH#X*&zP~e8T=QU z0aO@lhL)BaR?{vrUy3Z`I6G{SCrgoq{TJ!Z7?2I`zC6hliyI7>Iu2S3$%Pl;k$A!u z`VDwcZ4Z*>sY^Fco<(>Nz6yb0E4XZ>>nyWzrC{LQm*70(G{0r~gPzk|ET`ltr%cGC ztr#I-uzp19#pehk$3>(b2AVCW(-uQgbCyV0%N#ojMcSYIB;L}W{8p73$JwGNd8w>g zk#l-Tr{zx$K*El*{K=53;!j?T_w*+REq`*UY1WlMB&2Mf4}1ts~Qwr&6uxG;(dHaupZ`0!y6A zUN}`jFNBp3f_$9qR4#@%v8DL99NVdUeR=YaC_O{JEP1Ijl?yvN8WH8#P~9s2RdlXSKZFx>`WH@&Qqel zW(HWCR*XUY?+e*3j>~xjRBXDO_hG<`%h~I=oCC%^cnCgoT+WUEmXBe+ce$K{#xEgh zIDdj?9lDgunUk2y<-B&1O8;;#yta*3Sq4V7r?jQR`}mueiNE z;U!$oVVH91a%MtY7U7bG;F2z95`;^-oVTh=x}2X=mvlL^O86k3vn>SQPTsm*&Sl0G zoPWjTjA%2C%UOlOK?=4KQY>~{&b7!QM;yv{ya@jnU|ODy{kT{NXUGF|V?|x`L&%l< z0P?_{to~#?oUO(K)(mCgacWF_3U7J-HlhqnkbH!_bu0*Wsd4cJK2Qc3u4J*-0zOd* zTW`l#W{`o(bCKb3|IcOC8eO-$EMfpF~lu@US#{w|}A)E;f8 zJ>nlwa-4`do}PRiow6SFtIW)UQ4}gE173A1$m%_WuaU3g(#eaLo1-%9Qz)P3oCcM~ z>qlStpzol1-Vm!t0(TPW#30`2ZG@#QjaOB#Qv(m+X8T4X3=gHxBo7 zi2pX6t9Qbz8me9_$9C82J0rOOcGD-zja;%0Ei;~gl%SjC`(&3+WER5Sn?jsJOD)(dD2PTO73`N=vwLgUc=%-BY_ ztcAPzK6Qzw;*Nd+w;Ar}DDI24M%JJjA{CND5zLw0A`;4SMb~ICjw$pIMJca4ZXsqPJR~`7W+f*$Nu ztAYLVAtcdvBorJ^tL;I83T#K5j3=b1Wo2&4b0dSYGyhkH2#pl>V2#$l;x>7uPco-1 zCnTSRuR=BWiFx@hgT>M<-G=+LTbi=o?Uw%I!IUs{GxWw@Zt2%h2K`$1p_urDq{L)I z4U@mcr(!?{!!;zlYpZ%9rOC6ws~O^Ty;VbtB7TRw#*(ES5maEQ9TiG=OmjpKglEJO zp7knBz{L!(lvPH?@O^$qmfo)SJq6PA(m%ODs5`lZ4BabL>BVo5R^2I&X zL&EvyrJ3bb4~fiie>PHyS96?Ap4itddpTGbyB*1SWCB{s-@xKjtlR9ZB=7bs5JmW; z^k*U%Vz02t6t`GyncTrg95(3UWaR-hT!OliQy7zTf{Zv5pXtYNa|fMKqMVZQVt_K- z~TAF5akF6kUA1 z)y30Q7hi~`zdCtEk8|FJgZ}~@s((9?T+OlQ-_8N|?+-HiS8Mg440r7rKSBT#N7RN- z?9a$WYke2p*h_G+XH`iqpDt#7cHGN@Ee{8IK#h;qtw4#$%g-Y73|a5@bm(1=QQE^j zjuB53)q-qTqcUUEiE5%6%uen{;CJhLg@a~8+z(SwquJ=m#gKhrAPW{^j0@e;iIvtk z9i=+42yZM^=(x;Lp?YZ#-m6|hyNj4q1hfz}qqPMG(zlDs!zzn&3yh;%Y zQBQcy={I{OqP}ns(x^67ctPwOhP~=Jv<&>#F}~!g#TgCOJFWHVUg<`uAuBarb6oPX zl>$ z389VCGURB41OS6JJ=GKI{X%M>x#8E$Tas!Q6< z%}w5wsh#{5JaXG>d^^1qimvi>ul_r%`Y&Ke6EqXrW#I6&W0J(12#;98Uf-VZez~eU zypj&`!^rjUxvptO?`(O~gBS^ps(~^h4`R}}L#YTGI3KrjCecV{@;+QzYKpC#INFMS zQ1lD8wt`-~Oy5;2JM!`6qHW}TTrvk zH**u-yGpj=%d0T0tW0>w+_fPIp9c3JY^K9rD#3s~(g;2!FF9GDi`jv^=x?xD&Dx1_S(R39A~ z$2NHz57CZ<_pn{4!`qM12Yh5QPnVG4L-Ff6x|X1PsB4Kgc|9(wf$-7c*cKsSBYYU6 z0A?s+e2!*M^sNF>52CJ8FIQgfgxbd-Ip58kM_~5{YUm&y4&otm70g3TaximNFb5wA zKqDr%{ZloV_1EcrZA_9X)TZC1>7lJ}`rz?OZgT47q&=px5~a}J&qBF>$S<0gj| zlg&+@{#?1qh5Q)N%@yJ%Ck+{H^4f$V(mcmK{;;NYY5VZX+v(Zy3fj@3-0V!xc2;io z+T>e*h4%p6ia7vFjTqHi4CC6wGOzNU53%DB;-NZ_Q4^2(=;SDT$^jhD1J^{o()jk8 z+cuT~)5Lip!=~V7C|loo!m`^Q_bD$imIK$QJE0-cg6C3Tb#KfV4f7^SGDZ|Y3#Y<97#H&7gK^fAzvIHJ zHK&;+tl<>~+V?%LIost@UyxAtHEGRAHQre!kV@<03ASsUwNhV=F;DE}b6?>Jk4D3^ zsD=?@ipQioA`(RHRE?)NHJ;_v_+m8TGV>;6V0Dya@J_yDAj!hp@bYd~?%UN%)mantYSa?`YqFc}!mMd~_mnX*@3V&udo2a+n{aE_lxf9dncZbvc zoa0p$?3aCd_Q%D3TLa{08yIGYLLIm^?^n6^s!OJ_MqzQ^6R)D>YX5RV)5tFt#l`*(`^? zh0S!zE3drT$f_L=DTc9}$yaTFk6o^h+_a0n8PbD2Hz3ys`Ks61QZqETK60l)9NG@~ z*0-6XA2y#1hx}j2)+p$(4*8#tQt2N?d;~kbhU1U_>H98b&+3oA1H;A?fBZUJL7o4& z{`fx@LX2he$G?Quuz@8EP5P1i@jmcsVyf4i=&&m$!ES{U36HgW@}CWWggMv;t2&dN zH9)WYfU+MX*#{4mz3rQaS3B*Smm9YW{YZTCw}Nr7h4{#P^S&;G2d(pB_ePyHxZ#-Z zuA`A62eM!J=PQu2zSq@MN9LiA_`%U-=SqAcTi#~Gf7&~kXAew=WR>ljwZS0PhL}OY z0*M&*MM2_VeSt&ZmB;4f z&{lRAY$5!RwZgH&(G_?u*`ZLCr{qRMSu9A!6d4=07ID}VF*`{0r397#0Qo?|!1R%C zT#7!%@S~Og>v)XM2u1OlW01ujW`PIkGBIrY3a+(Gj#>2_Cu0&BU**8HRycdrSHip3 zf;{*yebVX*WVtAT|M*1=IU7{~WsH!5+m04`vTjjNLd~!t1;6JtniEQ#&(j$n8=qf< z`V=%GcG+&!r+r~QbTyyABEme%WNAy)WLW1-xKmJ_#Uu&8i>%+vtl!zzZ@u-~VExuu zzm?W+h`(qEfVZ`c+u?n@3~-wjm|ANHW2ohyMa}c^eD!>+a-;ZoeiJU(C-YJ5T5P$l zlYZfPrvj!iU&+DM8ket?@Y0My#cE6d-PLWO+!k_HAJ+25M9Eq$w#vUSUq&A z57ZT4&lpaY{X9>Wy^`}8Y8B$21^jc>{Kf`w3MOSU1FLBxCTg6vWOxZ$%({14%OF<8NSA`eGk?ZKXy{8)pQqofAV z^eR1J#4#fi&o(X`Za=N}fNa10X0Z`+-YjyyUuvAJo~qPZeueAp<`90io(3(^9Zq;aW>_(e7EZu0~bJWwthUPq7sgQ$V{^d7=+1k z8_0=#K{AUxf}eU%WHWx;?Yn)bWUcZH8^aab30-#A1dN|sogka;t*$IE?sB@O+1Mhq zu>H}?g+|QjOZ5F$l7ydR#^Z~==ja1>z1y!ofbfG_>;be({0U<8ATqOQ0&2IEAjC6th5$UIH0&PQjQKR&VB9?ks%-@+(UQz$$(e%r{Al}bfFbr2!SqTAo za-X{3sZ*I(@>rREF^r0S3;j0)CS*7A?^rL!^~-0%aMJhujWSuxUAne=$2;KXIidK) zhzH@*2hD`_FreL48^lhAn)pKC3@RXV6Ehj(yC^Y>KgA&mbASgh4VqQ)K?oKE)|w8@ z0v7!DeEPqZ6d`VDA#$YXlMTD0kyD#zecVgqy;qAJPlW)UF7B1mHhH0rcyD|w9=oNO zFpr+p9xGGxc}f^KJVI4c<79(RfUmvctrcEkjO{v zR_^J>f#6@^BENkG&-^ZALk@4tP0UDD?bW`rl2qV;?bdzm3xY#duZVVksQ2(e9Gg1= ziJLrnb=%0f(68>=j2`wULYM+u_pNy|WX|E_H%a>dNF(+fEDoh)CyHa(rwx%Q3cJ){!2{L zOv8t&UF1p3N(HEF3co?pT)rDFmx9OyGh`Em-LqviYaUPGCHCj4P2UCDM)bk(#HRsH z4(P{$OWQp2rU{iFhG$C-zmE?})T4vi=ajWkwGGx`6bQ!v&OOs>`tAHlN%`(7a%u2} zA6j*4k58{aOPgN?6R!*w!mlx@zN%;WxEbr$Ya8bQoDpbiPPO^!tGW|wJlDU+F$U8U z#!_+*CTCvYQF0frEj|V8`#Nv*L(h#k8-X2;%jKsh=CW(6@lHCHLy{dGvPMB8M!~Uz zWwK1vPD!Df`XB^+2|iR42nTA4BHs8Q6Au_U7U4~<_{SxeUL^4W?e)hVw3%)1`QJad zraYW!fThRFc&*g+t3+L&ua?lD{<8QZPr?a=CRygF>tS@!3Z#JHoz@0gcb0)*s&EbX zCCyeuDcE5fVAlA9r4waa1aERpeGl^*L2re(27|X?0}$Rv@rB``V7Q?W4CavX4znmR z&C{L(Tna&lg$uwbpOQ`nC0VvC-oDGV6IIe{KDJ z8}!&k(BGF~maCxZE=qiZ=u45vFeFyOx zyT4T5scl*iyafGB3tJ`s%;ulVn&vkq)&OP8CMEUJI*l z^yv_`d$@G`A~HL+c2LI$8(KM3HiLscb&RdzV}psMdEe=g`he6jPh_ph>~^P|nHsk+a;vpwySOMwv<|xrQH9PZt=+I8Pfqk?)ur z4E=+HDWmpO46b>g#vBdR7n-nHDN1yiCp^l$NHk$zPNYT=dcGp`!d`@Se3(I~M+o&c z8-|o%N}vtNK&Tk5q{bu)}-wb86~2IZij+$1?DoHRc2#X%AHcRMH)1x)p3`6$#OU362B7^3OO zDr&kh&~)pCU8bAD2{#3fAP~OPjqo;^z8VgGvTi2Q+-gK=C|QrB0mBHj|xbI zVm%BOa(DiXs7?V09<*6N1fF{%_J^Qzl06k5{{mdzOf`nyN++qwFb3nUrIvYd{)!5H zk4#xhuyU5{sldVMhMS@SyHgzc)mNG-%wwsreNZ1zPY~RAFU22@nWX@qEt17a*6yH?8!4&1CpsWYGz<`KzQ~d5IngKV( z8+21(KMj8>H^qRoZi;_l_YOX=+!Ryw->5A0S#(qMz63U1i+(XR<^}wx7yf~Zf;;Y} z>Z_D-V@fLiif>7LbLyBT<)VQ6!bQOivY?pdqFB}(qgc#EakrIfxF~9*IB`+bz(v8I zp0->R7pp={!rrNHCIy*1@#tqAm->-9aI;)ixIw*?MEUwT;VXm)a1L&=;uf)6*;^@i(27`Ef+!0c&sj6CKa@@rqimg;@&SH;QcOw0!_UC!Ca41{)+3DZYbE@funsm zIMj4mghz{)VhXPyb0|-RHzHZE{2B!yUgtKJ`Lk!m#U>hjlC#RV)WhcICY+ctLkiG>0Z-Ap(4S#D$A#5mRW)HlBxDxafUBVB0g=$9@#3x6 zfpY5UMPs?*u_%V(cc8yVHBNWH>4!eBLb+Xb+qMrQ9h4KLwd#(~i}D2d~kD`WM-hg%~?cUz6~V zu8DpeM_>-Jq21wD(WF!{b6 zx4XWBe7C!1Z^(+=;Km1qCbd?r`ogt%WCQ-m32iD2RW}6>!Q?8${u4L0*E(0CF2sMq zo5M=6i3aC&0C9-R#YATJ2sWg2*0Spv z2NdT3u^SE$8T$b9;#lMHr0ob#JAr6Uy1*P-fwl=O9D(~?9D!MIblAh4gYQS~vui`R z`OJpRDsTb9&*5#{#Qi*D>?!A`XnV!q0RmM15+9+{UV?Z~c#H#pcDvR%ZA+RLuT}n* z&8~G^YP8qSM;j@wL@IoB{>`qcCut8O+zwe&Lv1nS@g<6*x0PSTKDRph{HHEmGKnO~8qC#MZ}8q)@> z>RJAggyl@jMZz_+%r24*hC!CjMe-U)Un2nKcYF@Qn*bGpS^0RwMG~oi9)SgrPX!XV z;CY+2Qwbg}eNPNl@z)ruoBu`!2^Tn%9VGKPb65fjCoFK5VCJw~=DGNdP20H?T(>EHn@FgW}e;KU5T3BS-_&M?OEpBa;o6u|!% zfEu#OYfcg-P9-=DCrO3AM4UBT1dW?om=2P7???p}KtJklPAy{Vl8YNmlQ^??ReeDJNSK4$wzf(;46E9$hYy(zK;f2maealIoint8YDKIBnNg7_0ALWMF-30GjsJ_rcp% z|DFcI+OF?KW>Ee64l=O5(o?AK-dKH?wX438SbZk}PS&^U)7JVom4J(%|7}Bq%{U=r z{uh3u_{_}ruA_~=*dCdO7=I^0azEsWc&QF;pgYcuNdord`Cxrz`w!2}4Z|6M7~EsN zt#dsXXzcvWF7^2u2BloYGvjwJ$*;JpAKI^xnqmL}gnW4{bFvcX%XCHuk8uSTafvOGqtYXQn(&woUQs{FdGLb$b zu_r$ReTMxh9eu{08T!!POQ6r|0P<`84P=vVWWODQC&8(r4O%6#AUUAr17&fojS?pO%g3=yTJV zq0e<3bmQrBKY)B1^y$;DP5KOA$*t1o>isG7InE&s^!W&)mw`S9s?*Wu)-yw&z8ucu z>2m`bbQ<)@>DwlK+$_0O`t*K3g+A|bNCSN~LG&`vXZ?nB^f^OelASr6$J6IZH0U(w z^O3Jj`ZQp4YMnkO-%Fv-8ywO=pPxbW66s^j5T9NT`q0UMgA?7?XmBoud0lv@+M&5> z%ft^^TPD%MwPjvdZ;Eg{X(SO%xXR~yTUY{9D=%e*|280RN;4wrd2OZfqjfLy;N zP4G3-Hb8pN#cH9^jA${M-U!Wx&t$Kc?V^M*#je z<7W;G0W<2YZTw88qyRs6lO_g!mi#RqKVQKY3HUi*65{aVW;2bp(2d8>{g8sw zz)zn(ZQ^GDOKufESN}ByKgWR^;^!j}D+7KGtWCjB`F}rt&VnJ(e*FApm%`6y=$?t6 zEY-zunc(MTe35{kXC)yHKdYF~4*aZtH64E5JTvxTXAZ#e__-2Na2oje2twS({Imfw z*E)VqzLSEVHz=sIe?Y86{KWSEtVu_ox6TZGq8wo2>2of7aT@-gf;Q-RPJ}ZMZ?p||X##zYVGKD9`uq$_Ol{!jMV8#E{#my(g+32( zNCSOt`AbInO#eeV`s_I~^!W`3n0Wl`1CURHJ|P6~wLu^1lh*0;)Q%MT+=xu1&&YQ( z(r4J}bo4oRX6O@!U7A3j*8$|ypwBI^EZU&YY?j| zWYyYbyn!Gq~f07eViZPOJge zs$Ku;ApY7?2kl5&bvt7FS!Ip1yX8_3PM*Ngx&N-|xfF>Z2dQ*@G6gl)D zenxI88iXx^qlyZL1U-RC2&8Y&_9h)KxT?mM-GX4Evd{+SaQ|pepf5H@HEy&8&#C)# z`8&AAOKTq3>odj!Si?+_@3lk=~%L` zkoW5L3tp_9#O@TH@rye~Tq$QT84mMn>|q&wMmmU3EsGLi~nI z6T%30#OWulCBtmN&O8RSrehY{AF6Sd`O(YSd~t+ERxY*=M(wK*$hOk%WgCJQ;ARQq z#8R~n&8oeQ)#CgV*Wl{l?OMtq zSbpF`9B5N+m&e_R1Dz19TNR^spbKb?hUdGM{}`$V$7?Vc=q(U;~MNuUGzQqdiWM9 zhp0D-C>z$t2zj%lSExATY$J!h_iZH|5>;x+cieqKH!R)w_HTiIG<&55{^wD>*3cJW zb69e=&<`BQR8p%&vWJo|8Bzdgn9~b#>%pqE_O5;>Du*moi!8YHyYLg|{f!b?C`KTj zzX3V&1LbC6ycf>=5ArYpfb)>a!kd~vF+pc=#w}veExO12K29EXn!NEq77i#`0HJUe z!!AZ5?F~@hJ2M zQSdYrj9!S(E*!vN6F1@bFGiH%{6R{BH(F%Xq#l&Kc*+2Q(58Qw@=|)jrZq75%pSI{ zkjC_Z$d*_FlaCq=X>rS`Z9`F0i670Pyp*26Rc;iR>~OBgOFzgt=GbP58tk3wu;M*vEfa_aL zeFixy3>=8|NUTrft1wUt`GO+xM%N|0w&cx&qh=^?V~Yx1%gZ2dQ3mk3wF7Z-hd4(6 z7m$QvNM3#bhs)zX%G*~$n;>udgI_3d%Y%?;$Mx@RjT1JaJ$RP2scnx7#|BP7v?S`?}SaT}< zkLBOL&FKHB`S)`OB>qn&|G{6x`fuc)dn);# ziRGVWf}9Lz5){muAR9>Uk! z`-V2&pJ?Mf!-iWcpSyBfc`yBu)*JnKv5o%hY@Df01u z2~P)~Ht-;e;M?dS0S>+o7018dUYCN0B>nVELjJIk|LaEnzHR28k&yp7BY*dpifseW zg$emP8~NXbUS#`!^T)Q@fAFb<{?oSOnr2U7<{ZGgrHu8VnsK0NU_0LfGS!r)0 zQ{$UfqtnF8C)HmV%fG)`HGa*h#zEOjz=qf}xy_Pn8b*$`7z;Zlj&Scf;vhC`A|`*FDY zog`q*eO)ef zV>_wcYnKZ?r5LNzH>x@GtI4cBntHzf!Ht4BW7^8HpvX&=dHhZRb|- z?Df#?!YB8}{)Rc7uHt7}b>+NJb3Ph1@9ZV(mmmqJuSVv%YaZgWEn0{h zVXUJ&qoL4!tm6302cm?EyYERv*je1(Cy+9usn0U)SW{qgA^`Y{S;8yFrS1rD)ia zwd_82bJi^3gB&6lorL3H&d1>d#9Q^pI7i1`F*9qbwoCs$2Z19Y?54&}R_%U!{d34e z3`FcaNPq_~5eVga-YeiN+?e<@>KM2MH#(xtk)dm`BcH%kWqV^~>wc8Xa?#^#obTqV z_U%}{Wl?uj&GQoavbZS@evqwQiGsb_wLB5btzFAwzY5?A_5{wdYX9zPDJTtBpsA6{7Ia;* z7~9jt)?SaYAz=E&kP7~7d6{Bwgs|2y<#+r73jLMkvTB!bzKgZMSzy-RFIK;lzZmti zlv)T6|2~~k{z9YtDQU{L@U{N?=-)VZ_zhVM=?JbsejV^W2WIMTqDXjyDY0%PY_TJ| zHj|zpcgt!X9^Ml4V9&8b&wE{t_z8E#N@x$lM%$?!3oihJuGV&AHI9l4;Kh020o=~& zuFaw#M{{d!{5x<R=xi%rG80hUsn7Z78CuRRvmp<*MCn*#HGqS#E88w*E_r*u;EGOI8}~v z8VMzww>${7dG0-vwD>l%54cTPVHjMMdekY1j96tWxyFEi>O2$Y%@W7dmig>AfpE4(%W8 zP=?3badKow40I0tRiGi05b)leM50gCuXr^^a^8waavPBEYmo?0N7+$_1^jFQ{_q&^ z2R5#6LF|CPw&$)n=RgVqXKB?(_u|g7j{RMuH%soVR&lq3Gm`YG?)_~FmA}R$Mdb-; zseCIAjlc(qcy_5=_4x@@?j-sdc%Cgn(l(x_KXQunE`uCpqBqZ`Nv3!0E2mFye~jJ; zK*&JmcP%mt{)Nu#^%sAgLgzm-Nzs`{^`z>J6TeAA=l@W->WdQS{47QdL9;{D3Wlf* z@hUBmQ>5=F;OnW-_l`gOkI=XLS1I(phe@r`_laMpp>LVWl|rHlC%uF zx~6Wyu>v^8$%CUgnl5k^Zw{VgiL|S@I@(E@A+D(#(6+_SGVU@`}477DEfTe5MQ>4Laq|ltY17yfdyZ3(?M>}ygg^{oRD<0uOE}=;Ngb0>ywZi!l3i=+g6C)_wVk+L z9K>3S3x>0_ZJ1iQaZq{zqR7hZOxN}>DRl7U7=(xPMX(;jWsbV4j$^KcQi2^L6Kr*# zMsvec?coUynV?~+Qzt_Mu=Q7|ngwL1lr<8MeHj<#xWh4Qm8YiiDOJ+u?4 z+P19sR$%@F&h;F^(3>Mj3^fXzHF9syLzYY^Y=#9z&EYY^t zR}I>r0q&VuGqYfbdT5Mt2DKMrg7jj1Rup=xaOF9Szv~deH7_~gsg8*KT-1jclIFrW z`LMcic30>!Ri-hnOg5i>5g{c4wc?A2~pH~U~$x3PoWq1ro5 z=op^Ip1s00Vz_@7+H1?=v1fS@$wD+EKiX+$l;n1;*=A6V)S|qjfrz_SOC zPag>`tfXPQ zU8JGH9v<)DyaSFT{DE3``kUv?iZ~yIXXwt1QZcH?EfKb^&>YG|lMM=-a~9V_kFx>C z>!OBu4P|dF*R;N+e`0 zD+l@~GWHD!zUx7%K!`t@KnD;c#!iZB$3q`AMLa)&Kg;>pz(&dq@b@a@8$t#riw#kPyn=9d@QAwbB%RdcTTT9krVBvYPEZiuNL( zYHuL^MhYAyh<=6{9$a5N*`Y7I;WUP9Pn)E@t@oKKTQbeu#jl60? z@yvCjyiz2tdQx6}X1pqqSBl_OkH{v&Sw*zlSI(FYLz73&BTZ# zg7j6(C2<>NmeXIs+B z$5wfz6it$Ryuep!*WIXXt^U+IaO+)L`D5wf z$-gX{#iTA~5`VY`ZVi3tid3y~cEvC)6j1aqsbS)^t>55}G9~fhMteMoRC#!B6v6&- zeg%km!fw$0-M%+F=Ul|)HL$Z&WI@-Kqx;W4sU7w0@E@4h6;3E^fbSSS*4!~8l#bq5 zJg&lvwK~*ozHp1=9`*w=23yYr9+B_}3MO~C;a&G1(}s1V(!Xw=mA?StXz!~vA z!@7Hv*O;)J_whqJ83|1$Q)!}6RCl!MFmA+K?uPvb)I;*Ax zw;`MIl%h{&u?G0tz?~-_l^*ut^Rsx4z?BBFH$DckBk3gmnjVux_)Z42!33?w$nlnu z<8A&0ld5hPVzaRO)MJca$?+2h0%*@TM|idPHgdsdI+@%xaNO85oIBgJN*WmiCYH>1 zWCcbc!Ue%Kj>v3Ys_Iq+8~+LbQU7F!m+^ft3V*tXIviw?D}#fbqTS7(03;jvbJP*e zl@&ho{+vzvEF>m&`({9u-A0b*Zc78FbmLPNyQlUqj9ph0S|#z96hFDD(yDLWBSN{}D4SQNv)PZM39Mi>UKxca zcJY3I7F|>W#vgA@>SPRW3TY}aG4XqH$L$5LQ^#{{tmx;63xT0l7Wz}CHS&L8;)yPJ2eD85#%m( zgcgJM=SJq)SHWXQ=c*{SXDCy66a2Kc%t6gc0BB{-Fao*+!nixkfa^aaY2dm6iHW@Y zJx~NHMMB><^e6V=cSgbb57i5;CaK&fQ3T2NH6gFvv>VoZ%OqhO{VaYK+$;Rl%ik1w zflQ3o9k>Mwe=1hd%V>f14NoAodcuY}TZTYXG63J>RRO+;+B+Q%_5i`O>VRvwHUS}A zP7ww!z{Br}HcKSUzrKrpW34QJ_!|;qDhvRTwX#8|11bu8>6>hUPw^BQ3~j;8$HHjxNTk$e5hG0c1W8!=AvntUZbG()kxj3c;acAaJ;9pt zgc_n-9+@GONZv1yXip#h4yd6<_Z9@_#>U5qM(*VOPRaW1MHFD3C-FWihlrv_U!bgT z=qC1-e)7-^^(36El_ts^v1#xzLp5mmhIOPTt{0AR1NXI{hsDSa)O69GMjZfb=a!w( zPYh(34Vi2;WM(T3xjNPmqmnf3*?Esepzn|^HRkOBo7m6ufF0ZvKMDdG{g?^oPLG41 z;4hKhOJl_qP(fHz6=^}5`paV()~!vc|8W2U^}huLqU!(YwASml#fp0&ef^2;t-IUm z{w#towY`boKO6ggSbM&|H}<`&J>L(HegBAuA}z%3!GT@QOdA(WT|R*KnRGqx1K+Q(ZNv;1cE2RE^0g0*Z!0O+c49|2O>$uOMq=$(uB0;`}9v?Rk{N z8{~d7qJAtGc!iaE7J!5H$<3#dgh~q0N44&g zDukY5MZ)%a9ofY)R$tI$EF^d@Ksx(&gNVH;$EkRnc!$srHZU^XV{w$fUbsG9)eEPX zKUtr-Py!}q4$)ZA#04$AGkXWC#vUw#J=h0&s$weG)iOZuhPnVXdd&7hn|XXSwpw@& zsK2Z!nHaO5gCgZKuhMreX9nKo6A9ZN_*cusa{Z4gDF!065A)-_pA#>c;`658u6m46 zgmF$|25ru3l;w#@=tz>U+O?(!qA|eNQeN7HfRxA}N9ZJiLuAn#>Na#T4_b%!9(v|= z<)KrUXs_rPDYHc{3e~tnA2)ynNYa0RhGH8?nIp8_rdV1-bE1AES-3EFg*lr>AK;!hOuJbyDt5*N*1Dt`98wq7E{ukkg z$c&{>@!)4TbSp*>3BcFpS&TF}l#0K)TZJ3Mo9m_a=#yudLFtqIFRFfA4mrxGPg3wY z9R;kN1<{PG{`>n_MjI!VqG}-`c`*CJ;8k092;G|4GU%AThm#`=m(54(Y=@U`5PSxj z9Ik72xUOly6>ghRLJ-G=Icm!|W@puQlz+Gfv`(14R8!Q`kMC^Oq+6PI*@kljwpR4vC(Y;3d52O9f zM*9~up#9rj*EFg2JAyTl&|lclT5i^Gv|KS!|A2Ew#&!ns2Erq$wn?~NonS{S#geS7 zwe#^0f))dR=Y_3-{o3Zx=EBBmuWM8_&Z#p0Q}Re_XN+UW7-yi1YhAa{u`YoQp<{VL zS8Y}SE)1+KDJH?-qnUyUOfRGi*KnO7u3H>aZ0h~E@{~8%EbyFgx5&$T4ghf{v*+Yl zMR!jq8pGMNn>Sg-BYMKBAo@{qyqe)(J7s@|pzp8 z{~*DrKZPF`lBib+8}{RrEbNJMCK32AOEM6+^MV8dr|bXpSpQi{sgtgi`Devdnp>ik zI$yGZ5ZZSAE_`H78Pk+EJ67JMEN{G1+bm^`S^5D%)u~z=@0{>al9Btx{gpz zog>({2%UT*0%A$<9Ar&HaMX9o@{(x3)lEZpmHjsCH|^5@%%JrDw8ibf-!=H?RPa|4 zEC1x8WcUm z%U+&@HfR%n_4ueY{59NU@$2_2@6_=39s=0eln}BS1W)!iCCmF_R*1><6wGPwgpkq} zu{CDXjGF}eX#|WlFXr6(42UA;z#F;{=U+U4AGO*5ZMNNTYlmu`r8EXWMz3j=U4<+J z>wIemDT2Kfcqjc*HS|*y1e?pyAaVN0@}C~K5$!|c(8O5#*q|M3gV~^OWo}T+O8gx@ z%Fv#TzfkSDA-O$}SDDEmeqah)f|(3fua}sV$_@{=Ya{H42aszpElsE%(&!gA3&C6n z8$ukRsBmq5D&pR~@u0=CcKpVdC{&lTUG=h)Zu4T|yazwl9p_GBCF`6)h0 zXipsfe)x?T|IC)0GXKh1Nc;G=eIEMMVCuc3`BjOa3iIQZ>s5i~lCp6HCj9zlpuHJ* zUx@K13+sMfI{kZA24>xbAH5ioFAjPHh?;XAeG{v$6-&yk3~a8|bE=4sMLfZ~uEhLC zT%XLiT^Dwi1j?uceGRUvXHXL$iuDLY(5k62L&Z5&#_s8V&PB!}_-)>CnWybEO*^W__X#aIJ7L@v`qB2GiQ%7^c0i4^eEVTOWYGnRp8=z#a#g5QRelwcP=d zKVLnG_rHhm7&~6aXQ(8YSjn#WBnIbytfYw`3e7eor6VfABT0iw)RR>55;DQzhh>b; z5~7aNM7l?dG1Y++;TL!ZqTpnWb3g=%Ap9^WNjMFrbM$O8rrq)`yoI;y{Rt2*hR%ff ziiL+m6<;0?SjRv}tBHpk43+vzY(fS^6q$(lY#C-&35d8B9V{Xuer6$}1J0LC1B!#- zdqz-;qHw3;b*Kn0~##-@cA?NC;<)a)DM3J zw=+Uv@a)#0@Omf#3g-!GO(%(R8^8zKP<<) zBq(gWw>2pI9B&DQzkzUV>4zPYzC0e%=!ZwygbawV^uybWPG3K40N*o$qR)3)1H~_v zCV(PWz-xk{7{qP|C_WIIDHNA6!@MI6t9|SjpmqN}h$hv;!13s7lg;Vm#g@fg=3v)< zXRS|<1s-Jou-Do@TqHAtF_8OWT8jAF&-gole_=Khi;n0oI>HAXaW}q^c?j1=I)oR) zGf;-zWM2InY=b&tr%-L-j?FaGLHID38UKhKmt!%3=o&hHL0}?spgdobtLhJ^FMg&0 zquOH_)hu7ztv>|L;|!ir*gTqr6~QsV#0_s={o^}OI=)SqbrjR4#jIm633TfN@$is# zR}*X&L_PwxncNPTJSN1JjkF2IW-DW_l-mc$V^0f zat_`DHiK<}^FX8$O|GZ#>g9JCXu^yH!NUqzoWyayA{j5m7od(je+xv8=@rwB5r-#b zkHQNw;aU?<$@|d<10xydtVv@I@uYN&iKiUgH-n})^^R;-!l6wuL@7N3L}lNH!>foW zoR2_6O%_BI5mB#Nh>D-75LBGLvI>CeD|Z^8icMiLQ&+1t(uzlK6GT8AWSYvlumKb# zGp4eV>25;R0@cG14JNk(R3nA_vLQMFR0(tEr{`5rRH<0n}uEyMdXO6iST+fqtD z!55}d`ZI`}2|t!TT0h#vPda^62xTBXGvY^#U1j?cKLx~31|_tN&1g#r{a5hIDWTs1 zBLbpKO33+5VMr@VXk{P?L{9w^Lem0KCp9>>M+vPHa<`#`dZt!5H=)AEAbU#dwF#ne zszPgIgO4pi30;NvX_V01Z?&a_CgTfJ39SH;O%SE%ANXGvj}-h^>rLLaZ6o?$sf%t0 zi24&m9-=JHGSWw~0SWMdBh({qHVj^`V3ra)>gRUXrJ*rD`d7=m`8d%gT#hHCY@Rn0 zm(8i+4UXAcpkh57+}=b*mbrAqb;AZlAFrXLzraBQILLG|aPtMv5pqjH{$A)we1Wcs z0cFLR;H;ZpO#{2|p@!&`xREYFQ(ZVG9%TB1gslaz=OHQW7~#GtY)G`O6DrwoZ$c&K zCsZ<0Drpl?CqVWjtz=^%_nmG4#VbH51W*c50Q!&ulqEMMO~4Ykmpwayd$)jQF^DV&>DvL3 ztA)_5K;%h;A%PR-;=xIh$iiWvRMI9y_99azi2NDv)SzWSBoE>tB4+vZ<010d%?ct# zAR{3XhmRTN`cA>HM0}{Z7Y|e#Os?baP~&e2|3ak5l_fo-#gUu6@<5)ErbJoNK38D9^I$WPDf}q&w!LUs{7~2gln9jy@Hwf#Vl< zC4eKB(6+!)45GIK93KdYTLDK&VkOVw`&cELP-Q#7u|QRl796wjE(sjJo7x&U9>H6J zqZVW|G)TJfW&PkYfsZsAWHIYcMu??BhTn2#G{~>O`F4Wj$LbX z?J%OPw%c5PYz#FXysNR!o|Uz<=I~QlS=FCAhg7Xz@&|;r@6Rgr@4^)Z&5PaU`kcN@ z7*Wl5;t|LLlLzNm;olLA0Lfx~+Gbxvs0sT7wjm+Zl!p`GJoCIb>nuAm!sb62xJqmG z9mbK4m4mhF=mU{4?$8Ikl-8}`0$T*E=(m9g4E7zt0~y_+EjBF=4^AAd?>`ybggle* zHO`+4eRwbu@bro}-Nt>(m?Gu(!U1jh{c)h27YE9D-Jwl|{(ZrZas4R+y#ii~mVCf% z$17~5!*PNe&tJqysb*BgK^zlrcn`Uq0L|AYPDHmo*x!$~S&WI3UyC0tgZ_K@asASN zJ3sykLH*yxkLn4EAN6QkI({gB5-wMs^;Pf#2cAgSnTJ9VUM5E`xbZv~qB0np05DC0 zsK6SIcE`ULLR5yPh+z9E{c0Lbj(zc!V#LnO10YJ;g1pp)bN3`RM^YNtv zc(xhk(%^h#Eb5)}%P5 z=9@z1Q9`yJ`NpA99#hDQM93&#MU<~WY2*t>L$@hkg)$KxoFZRd{qQ*9C!43Ajiw1t z)5+J<1J(Ell_!_Qqm|xpC;VG1s>g^58?gwn%V{>G;CxzW9;l|bK{ah7PPm=dlN*<0 z*OGr%U4x9t((EQX=T#}n$$4Rd1 zL_ZlBO!A42YQcGzqlQvH4W)jH9T0mg_%V*wW)Unq;IVX+sh^Id>ZiE!SzsaQ=r?^pd+3+F@ZUneFr@Z>AN_*YDf&H$)@7of(kI;icv%Yl@&$i`p=AKU zJ{TxPo*~Qnwg=iEquhbi3Jg~!!H{Rgc=S=@g^b=57~-z*I2hhYZO05I4Es=u<94_Z zk9~;8ucpBx%L1>wt>IBQmMG8hc)ajhMbB|)W+r-CS2pl2Fk78~Z@V80aKkH*#F zEZ)rai|_E#<_26)5gQU|MUcYOy24*ngR zfBx;R85?eQeG~tmbI^+)Tkr$_pYs7+e~ayp;h(XO!TNE)`q^w+Kl!nu1ev z63C+xIBtUicyGnIN&!@u3Sc4>fE;%X4G|d`rvU!06hMAV0f=d{5)x#AB-!fvHI%@8 zroN^UfYp_t1VsLeME;9UQU1j`YoGjQHqyq95`0KcW}_#-2%lqm;JmVgJ@e`8j{_G2 zFBnDnY3ck>Uv&Bp}7+`^kp=L+r*TI){WC0AS$bI(ECnuKT z@}jH~P}l7W9l&GkQa$~jfW0-8YJP184LW0oIxM;uP!{3`r7Y%8P|j518W5Lbw)?fS#HKw1Bq}9*ygYJtXz#ABWd(fE#*?nlV#glaWm~c^h z_;CbFod0e7xNY?R2l!DqT=8QJI+MVUqa)Mt!?G{e7p3qcvwit(gs!&5mX586Nx5mi zz|Kn&6OSvjCs9nck4$BYM~R77iAnTN3An8iu`HM9@)*U*bw*Iy~}VOgVX z%SU>nbk#7$kG1GU0zd8;(JDVK>jQqo4r^pkoEcnc23tx{6Z{6nFop11{9yQN=hZFx z9t4tNS$DM4wFX~2Z-a)*5AYtgemGMD=PZ1IMSoe5D~znZ4jZ7N7sre=P?M*f#FwkD zKzT+{c;ySwZ!iFty@=Blw+$g+z!^UUd44iaNt*BRH_e@|)kfX1(pRmDEEtCSW~5nx z?ofLDqTS+OuhOdP>ftZk>UwAnwo*NB3-;EUYDNw9Wx)6`z4k(VA=QgR`)6 zyq}a@KLy{o)?j*$dpOYV$2*fTq!kcwl8At>^>Rom z5P^=Q(~p;(pTPfOFjivJ@Yf6ea#5y`f6)VPTK*$4l$7ua>pjBye8qZ$;TKsXH257~ zj{aCIKdR^{{4P}d9_>tJ_iON-@U$JU`#!Kck)I~N(H7x%e$x94{O+mv?M=t;LW|$H zbOXJ#`0X|M&CV)*dlLAa(94$*^cv&0S)uT|(BOAI_+1#sZ?0o2eitY3`#*-n@f+cc z)~>y-S1W#(g72C6J*?o%@mojGW=4KrIu`=oI=`Qf1%Ag)vKowNlo=3b{UCGKK+g<-gck#ml=OaFcQvG(k4Taw z5dEDI*|-e497$9J@d}%ter_J zZyK4MW$6D0&V>H29rdP+f5s4SZ~PFT^na~=E$I*&0(jZnsSg1!AbK@g#38_4JE|(K zPTckc&0lL@Dz&tKAb9u+6xap(f8nrr$0>t;%9!vez{D}(0w@uM8A~~57$02cCE%yn z#LqKV8u%#$0=x!(@-yM*dnNJsiC2vlex63;r>R&Lz)egW!Wu{fFul@^A9u#G0WbM& zjUQWv3tTvUEI1?M2k;`}rQpR|pNtobA2GZbLx_o&QyW4SBTzMlm$*6wFNHC@w09tx z_O%#Zp395jC4NkK9hf3sjtp)uUJiKE<7GBV5Pj1wynO5GHt{kG(Y6`!GJpyuEnWu4 zvb6^0;V=8o^mGiE^Ve!npLUxuJ4KxZDwH?p)bL7PxXtafe6$ z=rDEnAv^_eWyr~WdL!B-i!w|o<*F7gM<0)K^YDd(Dg_PJcId;Rt_+BdvbX{Os70q8fHwwS57&fD7NH@6 z6x*>xtaMM?x0_Yp2%E3qgY^7LJRj?&?&OvOFb{M#j&Cgc3c`leImyHu&u25S7LubCrtyNJh&qNl4!;(?FJqa&??T7Q zj_Ww1$J{A5d`0NvljFey|MtpreTQHF92So6h<~eV85i_0Q7+{nn4|E}DKgIn!Rr(~ zH$0Db>U57IlzxIF9p|P@A=(ocm2O$#s@KS`33ge5#$oY5zGwX*l)v=k$2g;GUayG# za^wN;N~_oNc>7RO=Q)nh2HXYP0GBpAfER&4Sl=2g2gFc*C_9vG9PD{N-r>|vnG`YF zKyMy^Cg5l-z8@p9KNy>Wk+;k)^DfiHxQQh%U~ZhK*%-SI2Iujt#Mwu}A_Nha+iJ41 zaT`*(14oO(@szb9uVw_M>pYNjZdNkC-t9)(GPi4un-{-&wOw_e`?t@LTVRW8M)6{R zEh`++i^H?+Aay+!??1D<)=hEaeoTE4!brhIsjUXi7Htg9rD~m@*zY)dP29NXxs zx`e(lI80V{1gpBb*6ghNRCugyigpfPfxC0HFUV-^Fz)Ka3CmcdcZGhBUZK&pI&G`( zh;YVt)W6%cj39j8Mp|NzU@)fymvrL1QE+c<9QV!z_x#lmyS2i)X0onY;-5C-Q`&v{ z9pDI9fV!5y6QG86z^t|+IbS2c@QzI69!Mi(#HkOsOuaw@wD~v#6YspC%{Fb5)^X)% zH*U$q&7t#ntL{8$V8qEAy;-_z%?3dT&@mPQ3M9C5#yN>cTs*+Y2wYG(0buAFJEU_H zD^Ytd^*hlZFeUju_}KcNixSN9z9b~T^+ zTT{e2jH7JzYss3r8ts5m_Dt00^^^AD%BaRbH?+C}x6(SM>N|~O+%Xj%4SZq&uMi5M zH(+76@m%~#Ex{t3Uyskib@;lxVxqo~ z-^ypuetA6V)`_~D`adr*)2Y3<0ymojf`dU}4%=>=_g7=T+OqnPYmz=kTIbAcZ^i7t z&Y)iqSNZb7+NpYdU!i;X)C#?~>Y>RPV|++H&+rB2x9Csm`h@z<_+;Zr{;B0SG&;FeiXpn|DFf&nE@5_nu3Kb+Nml?OhFX+qAw7Sp7(GXP+`Te@ zaV)aYc0>#?6yM6x&K33^HKTgiEMT$db6E&&IwR zzNJ{%0fQM-4UVP-PEp3vmQP?2R$dyhQ^}N8t3XeTmttJFMpolHF)2LY1X!ch2EEY> z;Gkm37~s78s~^2s>Oe> zy<9SSIeAvQy4!loimosnFp;!QVxZ+em~Bb57cBm+?@0Q1Ao8u~dmaj(r0=QhMYF$( z{-pBv16JD}{tjdPQ1(GL^i_rKSEZF#Oy#I?V`ACq<_j&k#D}tJ#ir=O)erxXN_YJ) zVf%#3?fxUKWsl=Aw9pL`RHF$Bi&3yZl5)=Ut{t8Mfh zlOYC5u+Ft?1~NCo_+T7raM7WjE(~z|tF`G4MqW&JrF+Qd$Imf63CFScAimZ2NF>cL5abn@ZKt%$r z?v=Q?l4Wm4kuceyCUBzt_KD>fuSC3Ap~rRvwyo9#>$Wbd4s(kft=!HQ)!4gPstEO# z>%T|K0U5Imyst#M=}fSBb}Jm95(~+^z3aN7xmf zr;OdhV6Fo}<`{{CXN8)fxkrJk$T^&I$YFS}40mj-*y*bJ7`&qSj%<<1J#6S}`NT>3 zi;8slRIy-c{RVPWrjKsXBukscCMiT$5vpjjZ4tZV^<=wbBf3l5d6IshkK$k+D5&pg#Qr9Om4%t!x={6zVyOcV^=db}hUWzRtTq_-ekx zwFwqu!A}_^5a|QUWVp6%rHfX&8-Z8_+FlAu7am>INtiPRD^vB& z(hX}zc^8LqL zBaY#=)Sx49P7aK+h;uM0go){e=q*^VvMWj9JH~vF#H^hwasjpq+Wau6+*vWbh=x|^ z!z7n8!}-oud!Npxe)Qs!)@1!S#IT3I8eW*6svk)Vs7Ty%BUChKL%s%Xss9vze6Zq}x#}1A z0me9Nwf^m_+x1{Kq~LxM1oj2GgRv7^f}W}RwFK)p3RuMMvK>V_FzlIHt`D?c(1u0< z^xzWAHb%IhTc+* zngKY}44_C%RS0u2d@J<~2MXWp@gJzbDq@>t(VvwqqxeZHUH_IpL zd(c`nOewm8fmOqBT0ffLgxKLi9I106J})W<@djwS;H-X5a^dtjB%n)ZgYU4dj^6UF z+E%)h@WNr+1=RuPARo8azv=~+HwA{)x%A=WYWwRx2dL-RK{dN} zxbHZpYuQ>NZM2(yrRpRpyHd=EjlLuB&~DNiAYj;Zgprb#VdcfXJrU;sxUr6{6I=77 zf0t|711L<1R?rc=DN3$~L79y@F(8pIDD2Uj5L_CAR5s-@< zad6l@59Gq9ApdeO5vg|9@~!A-Jx!8u1y>iuOQ~FBYSs)F*{}>QGEfv{Fb9}3td}7d zr~tzg$ZZZ!Kg1hVD{+dksXuZ!vr!+lW$YJsAr_ZkDh)~u~7+!z4Hh%YTp z@v=*k^b!Gzfi-Aphu&2>=uGmzB>N{GIRSjoUIs+Ohnfes+9BVL%1+U%!}IOF9doXr z7C!14ag>I9#}eE!)hXH&nh6qnmTfbrPyxl^)TiewdRo>xs15&u(Fg`P$K%t&yNmS$ z?^gYe63t$O(V!DdUFtu3k=#d5t9K>2J`T4&1?~*ni)=Me0WeVgn-^e+g}F3LX46=3 zGS}RFn@a+v+72|a99(i&=-b9f8*wX7Uu<5bE)1fL7b>e9se?+PNN`mZ3T@Jw7p{+j z>(O&0txns8I(^mtUD6!f-D9!<;|?-KKS-E=Tm8H2IO$6x*|kR8(jCgsxm@^$VS22? z1ggcqb?zkt8+}_P>LK8qIex<392wf%zt2_L3|nLQdl)4!aQz%K^&bGLov!abCiHbi7UZ;m zlpb4+|6SLJcWp=HVnw;|)3*zv;MVp;Zt8r}M<219Ikl~bK=uR+qw`G4tH0OEZCm_; z?*rdhc`eooI7EA40bDsYw*{)x8{9i^i;>O0BjCc4bKc1-?VTgnv;+=C|L8l+jbBz&FwTiXL*o5&a$FBknLTkD>x)4B)u4PT6we6ec>Ppwq7Ck5AZ|jeOKJfQ($m2q0u)_!uglp}%zl7sg zb!0vW(~P0R5gB_9PMD362=uuGCLX+`@ooCiC^1E#lOy9>K&RjyHY3_Wgg4fj4E~zS z*dB~|<6v(SE^yTd8lyRYrs85AxY&2Jv$9L{HpNQ(m~(@O2~gDJ8qw5uig(U6;b1os&YW@FldEN z4EDuh2lo9pUR$IwLAz%8&Deq624KQg9L;SZX14uFZp zLezTeC-Rt<-#h+E`f`|5>$O-Gg1;nmlFj-Ch7ddjCib1;oHJHL5_2w@hpFW?|52^k zRR*ITQ!vrFw9?CU584NI8x1^~rhziH{TaldF_)qr;9j@~dAP#7I-MH=Y$ zNMoF4aDhY?B>5SoEx+)lYs&%TCUwM8iLA#^7;mpw{G87AoKpP9Jm^8S=cqCuAvM{R zE)`OPi#V{hKQuZX%19Oy;`dNgPKw)N^u4ptWFxi)EYlh4V}?Ca2N^2BQPF}Kz12_LnKUoRZ~pWxSr?znDe=GToq zGIV?r$d=G?Tdd<1AEx1#h0pa3=cHNk;P2fIWuc!Rz*em zM4&{gE!Xce=kA3o3%~>vix)xi9z%BtR}DDGIU@EKksr=mSU0)d<&JsVNd+|RaKhvr zO55z5si1`yOZE#dGWl}`m@#SxK4X6w4|A2;UVJV3mk<#n{mm2+!_7?C2eWCdecTzM zj{MPcjdxsrG~R7B-btLzLPxM5GC^X?q*yCx#t4`>FFH`IKzNOinKHYoz66Wxv?*aX z;V&KH`K-80x9lv5m67l?S-HF+?^uh9o9Q8OGgsi-V#KCNmNG|_WiU#nqsa>mi^zXP zBNJ3hm5Sbu4MUYiI5#R?+X-gwO>Y%XqnrdL zz#{e)aUnG~I;He@dnu{>4WE9Q@{g;Y$Csb%FPhE@Fu#K1P|asLh3~cdY7kE|Sk@0} z<_v)OsMZgz!Ri=JhltphCWh1u5~on|68a)m4s$wiQSy8n_Oz0B_%jdGqkhD%Qib-0 zI1&i3`S;Z6O3*unyFy_qG52lsAJdLi7HGR|8+}_TtC(X>g%T~FG_gY8e>v+bj84T^ zi8)_6RYnJxWDsnu&{T7(8nHiUsD(*W%Nb*)|EjAg+*2F~-x1+vlv_4DbC_ZRjkWd_ zzI zh7*Y!>Jc7|(*)LW)=ZJ3m^_7-Ad(0EV0ZZDe9WzV`?UtF8T5sP>WO$>3y&*|cvj+v zGva(L;`|9&g{tkEr-(jF{bm#Zy{&ExU{IZ;{zopR6!6tESOfttnD{V|z?~B;lyjR|111GwAuKLl+e0T9Dpnohrqq#HrE%6zP&Lsma z)Ml9P4`Y7FhvFakqxiQM%}(Z@1m>pU-}+Z^Z@z8Oq;IFkQUZL6@!`6%L&BF;xG=H!zNUVQ^QZZgM+ z67}kN9fUb>Vl&L&Tr1rKj_OaNB?){O-yx06ttaAtlMwxWJ11pt6|U?-CBI%wP~7V+i=6N%x~J+L@@Rx|)uug0 z=tFJiF~c~dUviJ3iqxRxCQX|;TAiLt{KEhwd?B!P0n4h}}}=|JERjEN=aeU-k5y}-9w z+ZWC+s+cr0i=&dVIBUxFG6Y0x4Ips+6DW20d(efhsz=E?s80rSjG_J)&1gq{03PcV zO`5YPaCz7X9sOE(Xi>!TWB(Bh!x7IqSLrUe|4WZRAA^gG^ti|&?1A)io)GPzHStUP zQoNp8QLcByYotT*+HEkBjn${PSQlqet)1<$w6NH(8*+r2QASOa>o32neszgCSMijN zzpf9#-&nkqmMgUz@lw|@#5X25Dfy=_t=;hf@d5sb$=_AmYx1WaEj0P_KAu&$)HXbk zO~NCL_$GhA9E|tABM^0&74*k?q|6Dl<6sbkV3IK>0EceFT$WSpaa1+16{1(FX#oNeUn?C*3yXiwXczi~bmOUaKATsAy@BVT1~>ac8}=qK8&TH$@i`zcWH&sI$I+ zTBn6#-e#c!c*^yQ>x2eL^GC~H^2h#2oIY%F*+Zp?h{OZ1G!fKu z;CY(}B7*X9pL-{<+V??AdVI%hTN%`Igeyld0jV*s(DwQE_%_2j;o?;Vq(!u5&{3gx zS52>MobG>G4U-RnOdbZIA-x44#{fEuXp$;QAC^?iXG=xD^^3ryO1 zNQfiiSvq&@a^75Hm$($H6niG2CHeX%*?=h?sF&=oN1QK%VT?6_1LJMHLb8g6TaOzM}~G;X(kcDXlpfz|cTyo?`(RfFU($+N}PUfQDyU8>!I_#>nv4 zpG6##@nqq-xcnD?lfL8-UJ5cCD!| zwuCG@#PI-bAA)j^Ys4O~m;=4|=1k9=w%>QswhM$tXcyd-_}o)D5b;|;<4#KJc5N>^ zUI8zibK+EONBJZWtwO&Vo&hyLAZzp*4Bu`WUc}~@NTw~jEpVZ4PvCs$E`S{a1!hW$ zCy2D2q|XNd@F8F&!DP-rkBEI8-eaZ8Tdx1qdfOLDDMP$S(s}?mQlWP{AskZN@nV|J zQTxO;;Z3^uREs~;_klm@<3&cPc#*5Per3js(9a|hBfV6_2zQM^S8~{sc_bzd6)o7{ zXQ4=g>I@u5&Dm)KNIXT+gRyuH%ilr!e~;>)6+hB3RIB=z z5JA!}7D3WIVt)jUrhY8f@A{XtnE@oIJ0*rB{r;tN@gyC=$W|gsKu)SCM3q##s(5l9 zFcQgEE(VBK_3>;)X=wgx*LR-nee0=N-IJ=O&E2}>IBB;H_A^!^0%a#d*K30QGXvH@T5o51xznlpT@L~Pvb95QzG ziNtu5uHisl(~v=q$TcSd4bgSr5d+guLtiYeRUgat8*9`5kGD4gkE+Pp$CD636WiQ? z5nGKCHEJ@TCW@Mdhyg-aWEa65_hmjuA#}4SgAKP^xU_dfanxCL###IvM;Ub##R*Ad z5^#Zl4z45WINI0X$l`}dMDl;%Q}^Cp(t!;8oR8Z(zPPN z9w((D&|Hs`hR?GU+z|VD{zc{c%z68Qdm8p?O*RDX@#rLUpS%(wkfTo0RW<@Mxkl-KCLC{P@G zX*^P@FhU)V6!3vVH4Mg+z^Ry8I|IY_fnQ@UcL=*e|HLT!7$dWbOG-EUv#xwv_YcAY z<@^97@$a5@9i~yJqaL&JFTf8dQo0))nBbd27y-i|W19$o^9fy{f)3fo0gc9P^4sWw z;JeC0MFZnxw`O5t!9oqv#8IRUyx*=7-b8tI3b>$Xe;9_rqU z1ygQ8+>@o@|I|F822P5jim8snQHs9jHB8QJVIkQut&>C)^jkA zmS272PHPXW7jS#vU-k7?(nI;Thza5dnjn;a%hg!l(!XWKpo!kvsYH6aHnN?1j=Mn> z_i#B*X5N+H6y@Y{-?#Q`CSEw*I=RI5h@y}>{#|~VO!!>?me=-XVl%26|CVcjclftl zM*V>PEk+~PZ7zNxvwhI8;5F315oUTHh5&P&TwrkiCn`UvlS>8RJ;3>}M{&Ud^Z!xziI&t~tBf+-Z=&~ zi21VT@Fkuw6uEjdD|6tXr0HRN0}D8PsBlCPE1mgy^sWJcm*?=nW0C8vgsj*&RFL3E zLq7!Q)lmAerHJVO6D1e#MssW>3sT!CXv+5RXouQzl&Ba)Q|wU|aMV^98&Es5A3-)y zWHi$Too6pVLD!bAP#hjp9`(Lk`gU$&Rg_Oref9V7=&bh`eatapQt(26G>`ETOU+{h zSl(`6^SwRyB|D@d+0k(Ib@KH;*YIqK)~*&0|VbNePJNOi}iPoG>4_{B{T7 z5oeM(Jix2Kvj}6YxkkaG;t4g^D0pfVJT(fQniP0)nrj4}=9=OR6f_o>U%O~ONaFtCJSm%pSPy}X-K@ZC7S0FP}D;Z-0T8UW_UBQx8Kg+60pfiVKX&N3O| zWDbrLdyR$psja2APu^j-2cv>Z54Zoj*-ZYSqCg0tP|#eX$WkL@LAOp$?iPA75ItG! zGZq&ZH3$mfZN-ip_snAN>}c7VpPc>Lgi=;Xl=Nqrz~I=4W;Lg+k;nJ7+Anj|>4y@B!T zNL2)QK+XzafCBlqFDb3Yo@fp*-*h$~3Opw#!(-2vm4Js(O#eI;uHBrC0atDkTnX}} zEJp5v{pAkAW6#ID_X~;!0)*pliS4??xe&$=?rk98VG*(O8HRk6d0c=~b3k4_^5nhB zm?QI}V+x{^5H=mtKtXhj zFFMI*Oh!C4Uvx}ibW)))xscPt80^3l8Iy~Qnxg2K;^?GeV{)-kQyd*r5}j0HOfE5M zN}^*1M<)$7CJ)BE3m8?<^OE>IzOhF?ZBGi$4VnQzw01yy8(Xxu0VmvWmBDM+-uyPi zXjr3PGsYItEzl)$YWW;}BZ8O|(IhX$?DsJJkMIo|QIPa4D@mY-t3Pi4JLrMUW%$b< z4G)=Ut#4RuVIXgLPUlFU_Cj0h#PZJ8anX@Q`o~^5%%Znt2mP=>;>=_Ipjr=HWQ>;R zwBl%039N!6w?wwSL=^>xDAbu1E*|87db1HB40tZGj+}v?M z-nL`{hZ42q(tisb;fZj!7bm1@^Glne<9&n1lR*mhjx5RyoDdzKFr2t`E+J)Sak52+ zc)oD60so#my_uU(s}Hk!ZN5=kV2mt8(3k?F))yLI1UE#l)dxzCi|hn^?PERT)ln(` zcn_UEyyNumpbY_lEF57S?_GXuEADFZme;pxT3xwT_Z_bA>5U8=?XpjasQSdbCAAG3 zpC8nKZZUTFcg@WKRER2rPz{h)b;%V*HXIKFePM$P^aXCQ zU+ZhlGu~>z;+mFGE8G9N_S09f^Y8&RyR9g>7+m$!hN9PT)Hpi>HkZXdJ_}jHudhYt zJA=nqFJYXjtPdnh3;z*0(W?t#i~JU3p9Nb`0gyb9trwYNyyj$IWUDrML$rL*e4Hj~ zXd8$Et@-79fs9<^BPX+0Fu&i11=FJ#jaV3zzHYqN&_2+=N18geL7G}r6@|l8=C_fp zSX)EcAD{2vtc}_X${FMH70}2mK;}qLw7|I2XMBs$aJf>4)BrwGiys6@GA>Qnx)ib| z;gf5o!o3YXE&MS17xeCJ@C0%NM`2zPwYMQZkV6y&?qvK3F%Cu-7eaHK7umRAAx_Jd z;;dQ2{(;!P$o6j+7}&F8H_1UJK(grCUReGhTGSIB<1P5lK+qUSm0y!OM%qTFf_5lyr2WdS)YL)t03!;m$WwCHsJS(ZQvr{{pz`u$1 zny(uue_;mjMmnDr+!S0}yj1_Jnn8bkYz^Sh*%N$@rYLpNj%l zhsR-xCNHOeW4cTZ|M)^p4qrW+GHE&VNQ7^)4WAzB?CdnhdW}529&)$h5CFU?1wgY# z6#RLRD0))`Vf_wCXMCy&w$z4oL@KOgAi|sC|6Wh&>4|!JjQ|!g|HYl(?eZ!9q_g>f zTG@VdB%~jJ$k|RHRG>t*6932cQob)!-$!$L&HjcT|IDtW;iEK_q{Hvmu>K#I{@KwQ z3QXX))A?&k}7HFk1dr%`X2{}VmlbBT|R|=v-yFd|9_6K z>Hp6(q!T7cM}PIbOaK41D{1&JO(kjR|FI8Pt5j%wv&w6&A>I^eDSo)1?k|MY{RE7cj#}99b!zX6e(~h z0M1MS(5w-?V)iHGf=WX4e@G_7dWsF}usE#U(Ek;ozh2))&KeBw_&D{`@yi@l-jx>} z*wc=Gk%rz?{6O)`CX^+(+ulz@>hAa@Lw&C|wei!aUB#;ORitUZeyw5`N8XIHYnU3Z zA!$Db`mAXB@GOt;Q|O|hdqGK>%`#IJQnZKi+7SXg{-|e;Cm3We$v5&5oB`j!7^q4R zzEuDDfouhnnYt1vk25eE?MJgJCQ%&X>70hmKDg$2qgW~o8<8EzhGOE0W)~03)E=yl z=HV2)CqYmDcAKlGJMdttj8v3(t}rw7)q^oO@peNV>haDZt_; zTjqqhyvBHut4F{AI| zgfaLa=lSDXNOt6t2w>v4^o$&`~dplxgCVW8)JTLKv`JfCD8Z2JAg( z0jE^jj+lFtI!7tNV;~{T!vC4lRhmR|X`+?s}Khfgo(oDaSL4 zo=oiP1{8=3jOqInsn>V#f(fj@OVzXsr~&_65A$OzX5 zjx_a;k+PKm^Eqa7*gp6+Oe*z(PfWf3Gpv}U5cBUve(US;HWa@)h#7uxVmgoRTGIAn#slSo>-Ly#66 zV#>1+0W$cOw**&LAy;t4QmvyDip{k|FA&|&$TQ%wlt3s`Xy8k z;2q>i>nlpWr_ApwUm!gRprR+6cj?J&(rx`#hn{g5ng0s%Q|KxD;s};=P&tMf#U0|1 zP{ehXO`Xv>4ep&XmZ(Fz!V+x3@j&>T@Av%mzyIE*hifl*M(U7w_wieLe9^2(y%yF% zckKlU+veF~NtpGM;PMWo;W)r*>i+G-m*^5~|RR+C3EGTH_(+-HoV%YGi~py@Rq$_04z9cn9%1b__2{{(6AHVZmTS^|=JK$;?(ODi}`YWGX86U4=AgtvfC(alfL24w!Uo-)bSGM(Y=qK-gc0chLwgUT#~uRN z1L-jg^}B=-hYAoz0;M~0{5|?5C&}@5kRw!pJyH&Ki;P_Yj!zjdw<9ZoHjF||uL2Ur z3ne~z#58P-i;sT;dWSGTy(`C0aN2MQlPJeKL0S^#eDyVHl8zo{{TcKCF>pk}Sz-Yi ziV+N+0}{j$C#fiUL3u|f@b2@-NnzA$0bL4yCLt>UKPkN16-B?^fDWb#mA+2BX>ro} zn!?E`z#K42d?ec+PkM^dMD)^GZJ>a=9(EE+Bx3KKM3C%A^Aj^!5)MvfkLqSJfc#fjMNH3ypaFsK#*Xd^6$|RV9DvdV^84fPYmYWz6W8(6VuO<}ARYulK~U5nm4^ERR3_ z-*^+pQmVFrE7DhPM)z}>2PKi^S^zehORPSPeRK(`2e({HZh0Ctmv6*6VcZ5|gN<2K z^v=)I*#q76#)SkB3VmFk_C?EZFaqHTRg|JDr| z=iRtIbJvpn{9UrW^M*H1co__Iw>F_=P3Oj+57Qy_|CCICMLN~1YUUBnUAym@UZ?mXDV~ku|BiA9!`l?>jO|%vf<3Z{1<`F}NJIPn&LL-CuhYa&*yuyJuGN-t zYmsE{9)Co5CIR1yUto3A&>xBy`mA4qUEBQVNW>__TsJr0n3HYz^#%_%6Ro$wk>;J= z=s;sr=|>Iwdm*sy5}rCP()73R!!t>x?;6bwoxQlPIB-ele%zTlzdsMPv}hv{hR=9a zZ5;BjlbOu}u^9lC=aypUvR`bQ=qVrwxR!0vPM!@gDtDTdJ5kDO7QSl+cFLltw4ro! zWaHvNL?%F&pnfR9x}fnvIg4G)8j*#F!N@?}+!Dnm_T@Cu(;6@B{te9GpbuJ!_z{-Z zqqKDwMQ5cdHPcnk6ZzF0Z<~KlfxuuHT$qpa_!|O88s+d+M>r0Pm%K#JHa3@ji=zbQ zOog&4P3N8~K*enWMiU(4(Re;uL?i}aZQ%T)wzN4&!wW6UQ!F4Zj{9++m1v7)f%0Ou z#h5IJj>|TOtf3Pr4is^aa)Y#Bjk#z|HZluJx0E8n;NqkeEf=}(#0H}lI11o_{8ENJ zU|9-}MYw!)DZnF0u}5B21Ed85Bmr5R&oW>azQ^XY@&q+rWP>w)Qs&dgekbx1GLB38 z*ieul#R*rrb1Gll<|^gRStZRGm;#cv{T%t9AfKyPKg3@d&bG+LN(GE)90Dzkgg@!? zH1ao7eU4cXreYjt=q!sh(+am9&Vc)P(_Yd)wx2w|H9RiOL%gVuU!#fB{kUuS`&l05 z_e>epBV<&cCXlkVuH~;yQ+{s)d*+l+wFjQXFMp{!SL%*Vjbze&5}o~l)VwF#*WD_8E(?wGa{e~!CJoBiqk-K2fffu6%k+`GrCha;tyu~u_A+eEVK46*Gkl4a9ucORsdSelGih_S+Cd+PMS-h1>zd<## zTkv$9d^8E~w;<;=zHiCJ6I*ZO`wd7m{2Mt9H))HT{0)fJu$?2fwY0pmd@By!p2R1N z&A2H|_)vRh$dW35TkW^Tc98>Dd7`7}if~@^q5{S%4&>p4P{Ws5-)?1q73A51Z~Z!; z^eRvDC^fo9*@GE8a)X)uS7IK-aK+?9^&n0I$N5-9#1ZQvUV9A0VX)~0TKZy}DUzl` zu559~2&CYoUTwvf5rzWu>2~ET`cXu@h=lmntK_q69hDX z2_N9#B03>3*8D(2akTp3eN_hjfXd!s)er4Mw4-;~cie>5{JSxK^Xfc&V@-r$$FRdprlymzb#Xb0)9KAH z_IiOzl+BL~#yh9nHJ}m1P|dlS_| z7%>1Q!oX)6WfXHjAOgWPj@UiWK=?|7#I9qNc#XFS{!n zA`hZt#NX(;FQYt3Ek9^~XR!e}e*OLJ9A^Yu%ZR zTgxf&y^`hkNo>QF-`;ihQX*k}mpXrZ{Y!iSMGTH+V3)clz)-!OyAsnHFO-@QyLAWo z#xvuGxv|?N3C#_Tc3@n{1{RqTYodVybD;hvx@JZ%#ox{$#Z!Jbc53V*d;*vg=Z_SA znvLe6ERa!RzXGA4wS#+3fhjAhPp6hfJz2k0rDUnQ45h&C-Qce%p}vW3eQ&k0zF)fa zJ(f`4`3J18fFphgGTjj37!zG8Qgk2v>sD0 zM^XD8Nx8WN@XYH|D*Koy}IzE={sP7lY=NmsG;TU2&8kJqFOn5M? zK>-NiBQd`L&BrtPPw?pSPI!KX7r_qEoCQ!itvN`7g^M7g2Sf75R=k7(;q8MlG!|JC zfTb((I|cuzoA(xfsHFL&NRpO@opW#T$9O{KE!3;-E&fbB1=N$Bc^jTkSRgutI#co`TbT3tLA zv-<=p3jW5xk3$t_YLVOV0;nsD0wOeuWC1n-%@IWxv}xE@UHTnhgXG{IcQ={6uK8Y8oino)LzCTI+%6279J=#$gce(U;mb`wFqOs;4M-bQgDFb zV=rI>xK6~zWq>#V8w=UobYKH;p~pT10BJi?TY4Sa9*W8?W8%)t>$J#ZNoC!pMMg`i z*Bx49n543=*COST>is`jyC;{vfdmVt9lKpjGP3t^!MKDP@B zEix;sM!!ms%#c73Imq$hz6tbEtAjGo;`CZ?>pQ=U+2#~(U5~~8Le(43OP_RRg4uU~z-1>i|Jrz$bfZ**Q&XQ$sac(i ziT)9lLO4%_R~agie_$ca_Q310rFMJw05-r|w1&Cp@DSn@08k*7;YCHXPqZo@1F{Sm zH1u?~gzoO08R*aaf~0&vHUyonK+Hvd!`vJs%UaLGHD$cMSZY!=$}wKb1LT!aCX^CA z_!i$mFT_1h6N-oMdOJ*wfXC=lzL8ZCNVq9LlxG!-YCph2idJf-I7f%6-u5|ML$vjLn(M))haefLG#?O}k`9=6X<0S~IPOBgO z#7=ld>hKwj=zXyjz>F2U>@UDvbG+aEThENE#NG9u?H*45`F;BSt2gQT|E$2C+<)Y8 zlI@LO=mtsgZV+9U=;Mj2@9)QS9{1H58%6BtY(L}i7HHuQP)4iE*E^;M`i45jsO!LB z6K%q3_DD!BWQFTNAr#OeTbZ*Tliw(Cw^lbLQ*Zp6-ch72I|t9v2UlJB!uOq-?{|Kx z*JoiNTVUiEyJ8iXuOjt4RFa{ESD^ynK0i7Dre%Ml7Jj)e1l`cvjV)T_FGw0&Mi_Zq zNk7F0Fr-$8%Q0HY_v)Q}wPn9U=7=cSl$GaUB!pi<7S7w~O)VpE1AXo1M0j?GKp^h`1oIqZv zV>C&JspAdwkfp7`DCHEu#fm53QOMRG39W8yrrthH3v=?++h-7$iaL@1!{wtO9m!U{ zH8yLogN%P7Kl;LL7+_eMnp2CGbWkIyJ%^NZ1n!d6O5j#N$u!DrZAA5lA3`CaJwG2` zBfMa9b)HwG?JAMB)AKy$s;eT9w$t%VVz_?Z=DcG5dD=u~Hs;JKvrmk2%-bZ%>rRKDXJAnml@( zsxsuU?=1W6E`S)xwv9%-B%f8J*`HHakDKfi=K0 zt#p%_eIA-B^uti4MSciL>Ogbv(=zS&`1LRV0fU>EJnw#Hf>RHv!(-eIU&#*t0_`SrICeeib%{~eCz%-OC~%z( z(6NUK(9fuXiFo)OQdVvlrX!`Bv&Gcs#>;43A?mj~8y=vZ2X4&&}D8$VuXmkJn}18!0s((I0(Y=c#Rpx7bnAre6f?%p5Cs+bk*TV-%f z(555x6l4{V&ijNpjYn{33(C$;t`r}C5Z+=fH>i{a&*rz!}X zt`H9EH(;dl;Iw`-szP3Y3Ovl<(1X!C^hT-6BfRlWr1F4(^2P5J^gk!dqz5I=1AV~* z{L0j4i)|$jwv{|uFnqF7$SW`dU=1z`0>#CkdWA4`@Hiy>8G)m~s$&&r%2NEdz!7|l zYqGWQGe}asiTnWx@{P+KBgz!!2RV#;o(=F>mLY|CB>t?h8gFqi;4yM%WKTam5gvS zNeIO-A_(-+Cz|7j;*0MBM`S6fW5>gJY<^i91%TJhuFC1@tf?K#SX%5Z~29`2_+M z8qKX^uns$Kw=x)EMJ%6Av_A#uGK`9JYo=y?ow>=FkAb48>cEQdqGGp>0oWWZLj=39 z16+Xm*e|tR=8!l#^0XxR*4P?!x2&wO*?m zVBWb-@APZSZsl_Im9-z!7_q(ci}LzVM=flP{)Txc8r#c1kf&Eig(`DqXw|P8-}xKn z=i>j-t&>q=Z~0cdxJY}jF%$dy^D0*q~xOKRggCA!RN2rA67lmvZb8e3yeV=!YzX~x9DS~pax zz*={F&mef}F$F=@;X!br3&AJ{f(v>G!4GT*>QMeLaL|5_gM)o4RbZ_>u4g!S0z63p zS9y34w73ww>pFf*;xt>__>-fMA8oJ@-4@^W8B$gCO=xg@Z+h2f<1g2M;+o zSO^IGOz|nEcSw3SZ;uVLh#NK#}-q@mdzS{VCWpe>xAa%{8}Ax#=}kCm3JtJW ztKNhn#maYX^akAQLoN!xkB!dI-JMuNv~bIl)>E3C{G5NRT!7FMx;^^~g|!-V=`iT_ zxQn$vJ6Ib9pn3v9nGL~ub|PVN{x7Bfy4=W@&hhhy$LN{#fp@f+%xs72->VKXsomJP9s zVFI9_y&Cy2A@7QflniIdtc54?MI)7-E-DY{Uwb~aYi9v;uHBIqew4l==L@;j0*;G#>PXgSSaA1b^ga8qJ^s4~p(nc6UtHdQ!QuT; z{RsgjQn`QU%h0?t z3~WDKXvhk%D0ciqiYzbSMb{N#5mtzPl#msoPt}vWNEE1ypAahWVj-7`KOvw-AA)E7 z5i7HvaL0o`RbZ45zVr;*6YhB2<&M=3cbqB^B#NLmEE+kqdg0AMMbLK-D!?9M;e$!W z6*U+&n%BF$TH~nEIBJ%zNf46AE5On;!@_m)J;KW(yZL-Jf9QC5*p)!PbtKS{uu1iV zG99ZF0)B$>hXKJv7lO+i2%^~7>RjZ~WcijlKdwB5!;MQxAFL3#i5i z<&EtRDAe4^9oqjVyaCq0j=JW{uneSXL^L@Q`Uo4e38|o^m}zA~ueL$k&cX)*EguuQ z&9+A*v27@UZB5Ma6ie28Y#H{1WPiV3VdgS6f9P!cBbRCBIZQL7hwA1i8-jPJAs;#f z54%kBTZd`hhB2fkIA~a@aB#`tLGXYJ!9xxN(`b$nQ%KBvmNFKekE~D~9XT_!FpjBq zM)UlWU?hb%+KEG$qo`V1R``ZnVsL?^u_Bxn=&8JW(v#vbDxsvg3CtG)sZc!<D$LYINvMpJ2ve?wfesr6>=qC#kR@NToe z!vR4B=4Ys2_^cB-c^CR@lH+>3s=o(IWbyR?1@ohbqN{T1g%im@QD7Eqr8 zHxl>*oACa}R4DAk7u|r@6Gh>V+~W}w-k(&ez}g4ht7kBLaj$~muET?2mn+>m9qG29 z$1q%P!|*M>I1D^I?ZWV)1H(7i&g>Z;wnr5n<{lmlYg`x_9T;Z!7=|ls7{10Ahk=JT zT^P1GFzmp>re}C~XNAJU{~R6+@3=5*cVM{1hCvoLu53L&=EznpT!Rwggx+;*yG#7o zc{YGsSh)K!9pAJ&L1a!5+7Vfb4LcdjZ5XRPL&l5L3U5N{;J#c zH=M3t-eVX>+c3O`FAf8S3^AB+qa#nH3ao8dxb%z#8kQ+MTyl6YSS}uRI(V1{82rsz z_%~2kpvY(uE;vC;rOd>9+^A`a)UTmJqlNQPTIN1?12U}%tiKKJpHaLUjoBRGn7@w2 z_&}XSX6P}|H55+2X4!-rm|^_-Pk|;N>f-$CTwCBJgi4RpPGXV(Wj`o+4_{| z78f(rB396DH^!kr54v&DJqqiev!(Qk|AD%J7O=IfAxeUVt!*qs*o_rz8m41MpD5pp zgSwjaSGTZ=r2gx;XWk0-ttoVrOTeP0$) zeK`3*ec-}H>{TN(BYSZYPVU3iMsEYu-s4CfTo!D;a0|&30D0J_=~{tBKN&=DfcA`K zUgVGekuylxj1%M*x*PSR5F||OjZcLP#WooNP3cMCYyitQ8^Q!XaPtAtAK7aIp8~pY zmVhpt1<(O&F%7IVt)dG)F2<~3Q~o{7wD)(bU;q?{e|oH6bUpTX z6QgbQ<6Z!+!1i|pyrH2Jf_+8`>GO^D(k+m!J}tZx%)2715~q`X2JBQ`9QdEgNx?gD zt9W=U*Sqkq<#`D5iw6wRu7$6~Ko9wAgZX+R>0D^!BeFJ1ZsE%sc{zif4(5z7a`jDF z%sxl5FVZ4EKti%Jt$|32aqSI!jiXAii!~ypxA)TYpMoX$F8l{1tcd`zd?P`65ev(AaPVGf*FO%&4#yigb z%r$IagI=F)9fMZ_Uwf&_e;VOC#y=B+;CLiML&ph-5sM%|ycq4`_*IP4Mn7%j ztJq-d7c!x~Z&2k*2qSI+M<)Z>O=Cnf6?ReeYtM14!KW`(uH1uLE!o%bwSn!B7pdpf369PVY^Ee*Ypo=y=X^+fobm)b~ zieqP&C=r>@L681KUvxI|r{=rQgLIG179K0~X1``$pQ6LAk6CP>d*QYCN8@TRK3r__%MEm%;3?7T5tP3wBhjb`- zISUPYk(N-5Ehr~%V|fr=A@}sm7DldR)jq&B@6_ zPG&0ud}JfVb?guT1FNy#2^021NQV5Np2@^Q4mTYs2x}uZ`m93)2K8DM9sPS*1j(*y*pULA^9M+k=#y+gWoq=aD z0<;&#W`;Hvh1!ABD^QG+XzbV`Vf07<8P*x7w0tWjFpO`$oB-JX`k;s!4M*cWKpmo{ z3nEktYsjN?h`#LZ>7|$eW1|-<;+W(ZR|^p4;x{-u((DjN?dK(qZl%nC#fmuPm=iDs z3A=%-hk%2sAYTNp!=5ExwFrWS3&*>>o_!vC)JkAI;fn-5U#DiPE_{9k%2}Vo-oWjU zT%11%D9ejrqyv_3j=o;bLT3n{cB5s%0a+!HNqLTjU5hV%{6AK>SdwJWNW?{xg9~Ly zIz|>hJL6ufz=JX-k&V&n5HgP%O_>>7Y&=K1QW8!cV2(5P9en%_ERl$hXF`gPlSln} zl(OEX>>xu7f|Cq(ZpK@^h)l2|L>l{yE`n!khr(!Nc`q5g~Uq06(8+~hD3N$vLlH|Oh(=%I0lLmMX3mkd`nvr4{74a z<8?MfPty3%3~Klwg~_Qrh-tgJ`eKVvO3?cOjxJn^ z>$=s5jrD^JN#xAnCDw34P0|5i#Dp+g@8e8IYP`Kr^{WsiAghq8&Mo1+?QF_J$3?Ln zCiNo3s;Qg!KIAv@H|fFR^T-DBd*5VOMOlM4Zy}nCD!Xm zfJ721T#L|R7k8D%@!R0lW(_s5ndXdMrMuwUrqzw?G#9k!Jh{9E-;Nv?+|lYcI^?MC z^T;r#$`R=QMY42*-heCS_i1%gJIy=QH&Nt|7#rLnAsUQLqzd6M&hG+be693dK(Quw zg1Tc()WLqo*GfLoAYw2sB&?N+Wv#@xNR_j+>fNm&f?d4}t`(G4S+*8~0~}*gwYm8= z40LOW!w{c*VeOLk$EZnTc#^~Na75gBZUuKchQp56z!U~7o(j6?O>sZ=-qK=VYP_}h z6vcDL=q;pHu~}W=i7&3C*Q=!0Q0@h@+=Sx_@g~gZv7NU=%;3w|`Ey{bc>Xl>M&ehc z`lCNO4YmsUD*9lbFgg&V?n14uOy55~@FRWygup0$|E0k*s=$msIS#)N6&VfX^$6Ql z6df>ZMt0!X(9qGr0va@YxbSF0YhSRcFP6Clx8KJ0dP@51Ez^ER+*I$NsU99o2cw%)d8D||-xeI(dJ)fSC^3p_2R@w#HyPebYrw4WKDmXV z3o)@3U}9Ut`@E;}Fh!9$Bioqj#c`EPT3^}%y|MTR%ti&fFv1}Iua3_54x0}8f9m%>N!7Ahh-Y>e<&)N7>kzq=Ho zh_OS<>#c9`Q)R@DGQqk8^+t{|mB>-1BC}RbY`i4vi^(NjE>T4b17#*Iq%L)^_OA^BAXg2#;<^Q7&-m_&AV+66nu2X3JZ+zQ$U zpz5R9Lj2~d;}*)@?PZML*gSBuI#t2=YvkX32t+U<+m8sgKLc4p!)^)QY+js+$)OS6 ze3&2@kzt$hPOz{3YL;=V@ez+r(1iVKAWN&mp|6(m4@9nU5ndBl;px(*g*~WKm8#J@ zb8EkxWbE<3AH2glL)yaj2csjHcV!xWe>2+aKzkS7ZtOQY;_bbU_8J41(P-7kwmSOG zpMZ8${hI{}zNz81ht$74c%Jnp@)3veeJ%VdQgoSHi{H@jS*tU($g@b+80BE7Cs?f0 zzg-Jctzj`L+bE_*D00oKGmT^YufmJ*eE>G>cDN|N55StTjB;Eyx*NvB#sHk}=+um` z6aef8W6+Vdz<8B6h9LcCva#R4Cpe(>0`%`yKoq$htlfGRdbKA|3Xg_Uu@SI3GgyRA zty}R*ify-x;U-)ds`munS&hqJ?HH!6`~mUG>l5PX_28ND4jF)NUZVVR<1KEV2>FFz z`lAuh)DvCcE&VnyT}A#i3;h1ZxqT4uE1J=IIwH?7@G&o{7=aLFo++K>v0q~NB11qSGiOYVtp?ZO1**=x6H(n!dww(r-%Xp*IfX&bLW>dhMw2XrmPKX( zGM)a$8vm!gQ{tJRf2r}?QCTwx1=B;78oqKvoMTT;iGRl4q5qIXkD^LD>iAyMjaS&^ zKDo^k@CCvi;wrNmOc#jHH8(q&(|W4if1Ep$&Yu^16vLD~&!J2qK>XwqD7l`3o9?JB z!f*a{x82BJZ_&KKwfOY}ZoT7n{ALGggV#4_d#=CZ_PKgZwl8|82Y0>g@XVNLqlOWI zj&!q#7zZ3^38xUczPqP$4P=U*;z z@j02ry2i)1=SMf5^xgcz4{?K$0}-+nN^|H!*zYzXVb0IQsKVJ!Kabw!2eMb>;JV^^ zt*)K~TP%8ZV6mU4=@?n1`uuL}z*j&9v3xGIJ)? z;vwe4gYm|Ek#V4a1{{!v0tNR9|Aye`)(N63t8tNYd-4#IBnus)oYAf)+66qW8TNQngK>D|- z6XF1)BD#zKvrKeZiAq%&iCv+3sordp%i0t4ulCqwaD?Sx*U+re&Ecm{4Ff>p>U9a` z1Bo(3iyY6~%?1SR-)~Z!F&gOWs-u5_x6sjvoG~7YD{HsG=sJQ5jo}1a@1@y{k#eh9 z?XN*mD5H?*xZ&*;_PkPRc~J<$1yOtKNpVO3Xbg0R7+d}g(ff!HEgS;j{kx21>WP{s zc$q=ADh)x9LJm+3>P+SRHXaPRog%6zm`%z(1-^2f8b++a39gJcbIU}(g(jwpD zl{F05LofZi0#_N}fdG192%!uGyh{Si3l+u&csUMBfDB|+1Y(Z}HU7HqQ!bhEPbH7pKu#De9^+^yJ}IJGO(P@%+?BbM=HgGV@5`>Qck-nvgPqvSy`rjDdnSz zY>6c!VlXm|Ca}gj&dlb{EyCEWjP?uNnUjev{Dy28Pl7uMWm8p7CQ22@OS$YS<@7s+dC&rxxzGopNffeuGSZnimUDVZ1h zAs1L*CeUQY^@=9jn3t9&0hAD$yvz!c$?~j7hZVx|N)XF%68e+ z?G5(&`V4!0y_ju5^z0{pq(nj>?a(7%Yo)^&Q|!_$BxS-1JI)l`U-qfs2XG>h8UPxu z@&Gk}?CJ59ws0p53fp2sQ7f*rLub$v_5!TyZp}OTpu5t3<61%-nBwXg#xi@uv59TR zSK24aN_(X+rL43IWTj0ji#k{aycb!&fozPexw5@8)@v5Pp!ba})KuKdGtis?qrfHC zbdA^O>dTX>Fw^zp@*FN2cY#Quq0_ZUEvZ#YGgCem!C13$AH2NNUA5B1Ki?<|t@$Ae zLi}wZ4Gt7sU<+U%vFOy{b|1Y+P=yoy{?cuSi&rviX67pKN@koKF2QL6coo0!%ki!_ zG4yIn=sQ?I|AHKI?0$5hz#Q9IuI7-;PP1~Ie@kE?9aazk!Z=5(yFAleG_VChWeWng zXfIrzg$hQ7zRRtBtM#(bnp@esKy7rnNS~?Lwz3`a7aN;w#$vOvJ-|PEHyP#Qy`v&> zj}Uk(V(6h<>qRhSj5M}EzsFM`ALv|z1~P)4G1ik}esV@gbU8<2G$ixg2E;`1H%rO6 zA4RiYYJHD74q!1xz_-7jcc6%{lFuo^`oY@OFCV!DthlMVpATo_7~yeP9hGb?azC;; zoQRp|PpFIVeB7n@g$i+e{Cr&OEC>ZdLQqnowBF?$jFS#$Nrwa1L6W6}P4VJTTrt^k zrzm1lLCT>xf@A!I;D7;Sn3{lF4#&x>KGy#M8F1hl4BjTDVy7UHVo!+28#ONg2Q$Vf ztSm6rZ$k$|71dgV%)z+91N^TcW+8Kj2B0L7y=k3+NmDGOGyAE18BY1QoSo-FR_vK<}n& z2txUk_;uiT@T$M66vjDx*z_0pRIL@7`im-6#CR<6V6(CQSJ?In*Pam9U4M-5T+uAd zoyEcVh^J_d*pH~(^KS#eJzZtfS>Oe%-Bp@+3GD9*q3iIP)9Mm>U) zEVeZeA`^p?P5`({o?A5_#%IK21@_)QKmuU|jr0ARwD5A)k9I@D$I1B&*t~fX{@Hm7D(+cEgucnO5@K#97Y*Fb0M3~M#IR=$_M zFTz&snOc}jA>qNtkYEH_EWG zZi&-Fpff=#TpMS4BUBk{7|{`tiYW&Xl>_! zKsWP4Lq`Vgux>!kN)b~d=oZXTykb-z?Zu1b45;TO@IQ`EYZ@?FV1_)h83Yc$QseRl zYCT+QFbRX6IIE=j5Wg1-9^lab8k+GMV3Iy)08JsLJYeEf1zRgDHy%0NOhasj7AB^h zDM7?%{N?<)=AAI!Xm!&NRJeuo^tT!N1Lww-H>9)|G$C5<+~ZB}1F#+eo_ynMSYFNP z<8c()_%`@qYnHLUbf>>1UNvVmX{}a+-rNtzzMNZ6{NDvGmX(XzJAgc~ovp>Ebm^Or zdiGERz6xT$x=g5D;))d|QEio>S>}I0?sX>(e$+Mt7cO+&KdN$8wzDcA9sIy$VHDTX z?JRARw!?1_Ra&V1lHhH)ZUD^}YD;%vRf7G)yXo{c5c9Se1(Pj+emN2f7#9Mf}wwMceRDjjhemWUlFE(Dod>t8u^40?=6>8WVYWK`P z5y0AJp6m5?R4uM@n-Vaw1!oUH8QT9HRs$TNafsWiI=nh7$LWz^q_rA&0L zci3FS5ex%M(Tm(wZE>Ioz}S(-e6jB_I_0}jj5apbI-l!z2QD_U-bgu1xV?Q*~U@LaQBd^;T3{(nWVQ^--2O`4ag{F235Z4$dR)F7a_quyIqQ} z5PjyFDoPe?mLU@N;M29GKLVVe3?uXiB-K>T_x%Jr0AqZf%@Fw)^zKN4&+k!yKHL$Tu83gOx^ zbGB@`u65Kfds(P0T?THjmxWW@AbGyn_0tvPe+5ZXmxklNkFbL+=InDH76A;lC+ zPeCY@*E`}gE{c7z{&s~opu)H~=J?bdaqO-fA$o8p5J+Ey5m*e04GEk~QwyGGnQ=V6 zV*4*v=#O5U4Vj{%a+d**a8Fu-(H%X4gV)#wt#(tO!WFjj&p;i;Ba98k5y&5Gi&?~2 zx5X?&(j&TJQSf-{F(4;CXkaKsHaz^1D+6Z<5=6U;)ifu6d@&!Oq!{Gb?WX6L#W2P5 zXh{h)CG@~&h8EZ}I-Z7LHs`Dk*F%klH=sm=J0i4O=(LC_Ie57U2J2FIvnAsE*V9zX zJJ}6K8x?+aaNeY1deWZ)EQEDB&H^B&Q{tX@f%vLprM?oiVWrN&0c0~oAlz>xa-kqQ zt@H@3mR_jwSt^DmM{=MdUu@r0LKv9V4Rm0E5~VLoFQG{?Sj>@`na~?GIUz;OndgBO zR@>AM7 z!)-5z?H#S!n?~iGg707rK8a59+A)`(hJCs>$VKb*rv zw^a3~P-cl;w?b6+_0R6Uekv2xUDMWoQg`(y^JhO+ulVzs@oD)}_UD)EsKWH&42us3 z;iE(sHt2PQ5c0V6C2KBi!tO~!-d}KYuo!-5bAu;io$M5ZR77YEdcXYz6JJ*C>)5E+ z*b07Mk+0S5)|)o#`$uWZis1Yneg3)Zm#|;|QRnCUC}ve*h4GlNS*|5%cv5f2Z8AST z8|ChePN+k<_nam=KS6t{9aI0BR+w;c20CHtyVOHA9w6jYuJ!ytwb0iaexbL+SD;kY zSpbiyv~|Wl#$pfiYGfx4p;#VhL2|!M$8B18u7{XdfatB|NJx}=<#_jJ^-1_m}mQoq^z+%o4wi*>~{+IT5q3&K*UHmc-Gr- zwOlcj|_o0Gx`jE{#`rqZXNyTwRB%;bW<8 zpL+PrsgAkU)2L2xKkY0$orllmDf|T%+a-8Xqwddo`$^ieJ}81wxBhS4j1W`reUFT~ zden@2DAmJyJP7#AwT3(3H$1Di57w4Fcc#=?w65Da|E9pEb=}n0sRtU_rB3ErUmkCx zq~U3i4zpC96Uf!+rNbbCR$aWn)Xz|NgQXTawC!E%8rC>Gemb z$u+j@w-64wXpCnCcmDvDb)d9`1gtDl28T$r@Vm%Zk&C10jn9WV(C-a+rd3HUJu1>( z;1SceIqnk>iy>Bowos9p$@`VQBZqqLmAXRh*J_c$r%KmJW5gkJ%MRb%&is(2^Qbb3gq==6Gk|H`hlFGePi|j`madd1* ziDdc}qgrtr=|D63+)-)_)T63y#(x zui|G1V{$~VvEA{012kitoD5x5=0AMx&bXV=MDmOq<&67>3svX$Ks0sb^$mC%=k;35 zxGw7+z!Q0zUFV~yv&RA=Ic}Y)hh4-PDpg=jhCiL#e$0y}_R>!;yMxKBb;DIRz5fkJ zLq%qlP-fLb5GB&}J{+)Pu@kP=z5&p=umupFuHEKKy~~T}}NRB`_HM13?_s1Gh{>hB4O~(l23j#&n#~Aud+)tWGK+QU}|4HeC8C z2jC57u$?OeSm~})-XkzF*xpCVx)+0uDg_RZosQ~49k?s|L?#%9>}VuhimkZk7Qnq6 zBcMrAye4kZ&pSI;z~H(3Cw#{addy9Hlu6I!=5fUjez|QhXKbJ{ZNLI5gQJO7mIp#v(|Q@tI5NZj|PK4O65p zL)osR?p>Kk>V=6z*wl~U(88_pB3HfY;dw`{GS?cXC6F3%$5oj}kClP)tMMT=-OQ1d?;{!DH3|UiY1mAD};GGQClBDbNRv8 zt$C=zO~FZrz-~vef5L7@Bc*Pdjhks^$lKy7Q@>25szuYSvIeBg0Y^QeXsH(g1};aY zi5p9@C1o!1QuMCWq4S+z^<^yUNx$}puRBtg_!qc+naIA}=t&~$B-MjUO?|RTT`7IJ z)EaNgJ<-)n{bKcYtf^n3QWK=ySnK5Eas&7_T)YzWHFckQcn}XFLYQmq@+JTftHSz- z?EWLJlMY7HJrxQMRj}I}6c4HM_3;8X=j&6EvTn;s1mmSv1;*$2Jt!Er*(BVdLyW0pnN~8^;lhVToXv`q}cf_!d(?N2P8P zYTsfFIU)gEQ$JI^oo(vnDix4&vn{V(E&yvEugks+hCPybAyz*!62^+9FL@-~ioAo2 zgk9&UJ`ZO-=|@8HD*Q~DNa_>pil#nPV8u3=UWt@-I)qJ<7`oaKLzg6pp`TjpgJVy@ zCEs{HD6dr60GqU`qz5=YbW?fdd<7_2)=xkmqCw6PL$MqI2hrPl0>(?{D!k$l{V`7qiq-F*k<^`kg)sc6O#&2 z>cqSBY=yebz5_ty=&Y%zyU88Bx2seEwl!R@+dS9nHm}Hf!B!mX$yQh*TwEf|O0EFs z@=%v>H*>A0Y%X!+>;K-TdUY%TrKS;6p-YqYZ2F?h2a&J$m#Yqc)cplfadDNZXNU$L%@cj0rBCwsou$xH);&OKHgue+hX_!!Ib#qgMh0oa?Lr0c6gfK6Dzjm6m}M1?%@`D(vm%8aq8$ab8cInq_q(Qd^cb+^76Xv;})JH+C~XaY(rm=@cBLlG0}b zbK`-4Nl!+5fF+O;hCLe=hm`MqtPsgTwmw!3x&?hXZS?3+oP*@(J7Z zPS%&d;=6FMM+EkN)C0Z#MPM@*9!fB|9aRL;y=*(M3_%|ojYOgh`XQbV%CtKNsZL!0 zQ+hW9h%;?E8D#5}kU`WbMFv$s^C{nm{fBF{2VnvURosqC24U#I21N;S=M!24(&{B- zLd=?k?L#{jkG*|33)_dmY<%e2G^b+dyOt1xbsp3b!hk$t2|4v6#j~UF*}*I!@BKib zgq?Pw_>&CbPV2VOu_zt8^}}S|{t2EHCZhL?ckP|=5L;&$@7VsBvHo`Tvsit?=}E_Bq!UMK z5nyX%wh1t&)OAo31URsozS zViD+)iSp^S_j@3prr1#Z3e_AGs#J~n4p)J^6DeyW_Hb6@%KqsNtU0ka3`mav$YxZO z;tAY8rLJuCg63k6F5rwI77(u2EO-d~P*&OkEEn3Y-Ko*Ew59o|&lz33sljIS<)FwuK>ScJ0Vm0Hj4&1T#2JBswH!uJ!=^Ud ztg%&xGmLFc>mQt|fGz2!^}R+TT#@mm97aFen<3n=Q(P0ywj*qvjd-SK7erH!42d_g zJEm&whSovrO2_X!iHIR+R-b)<(}+Ul={$`{D&yQ0JOsNrjfk^ZB%U=Hhwhxt{-;=V zc33ws9AwOuIAiW})DuT_&&FJ>-S#@DSLw(sam<_*Kzz(uYcbdy_|LTKxQlh9k#RkR z|FlDZ|JhR%?mD5q92EYug-bH*#R6Cn;wtWzr{b~UA_S}>NTR2hTbw+-wx0^5MVcA3p1Fj(=R8JqQHk3X4Co3F$2d(Fz_!oH%mLB5DY#cAZhAm|FA5c%6e})i0Dh3{o z3?CO#stb)!C|?F-VPk1twz0dkQNkYn8{G(1;7X1UnOKksKaQ>J8QODA6^VLQC4w;7 z{#iT(Comum!fuR5!hqOiTr!rhxwHyaae{x=oNU~nO8>0&Z!0K219p-Wtm5c6_wX70 zvv{He>TBR6g}DZlXM_h8_7ELs=ofBc#~wflfv3$_=&|NN(c;miFok!;Xm_Cz38CRC zDVN!G5_io(z3t|vvAHxdHEFP&Bg~pFB27XW3?Z}Hm(PJ_c|J^fFn)p$s`HBY3%E2iqQF4ZiC~5C2oA)_VpN5E zAI?bQ2RyPwQOtXQuIJj#&t&rl>$>PHy67wzjA(-nW=_`&aj2iYw=Tw%ZV#46(R&OQ zL@Qf`lo=KKsSFmHRjn5=$P!i6N{nQHeGfWTktQ@{;z;g~!RL(R58@+v*g%EN-e^LR@&H1U-AK*=`B8GKVF^XGcoVmB*T7m$+G4xsfHr+f_=?3Dz3y zmS7zLmJrV(DM5!LE7vY@Tf7c&^pO(u|FL2~YG~+facqfSkG!Y5kF~*mPi$Sx7Q_Qq z-qSJG;zbLj$8CZwfk7O7qy+tctb6PdKN1*jWgW7iEG4+zW$`#$Xy}gwhH-o^E{F1- zo`_bp{hlz~#`j`Vk@vK-SjBD&#KQ!ZkR50#!HsE)hbjr>?QuNF=A)G0o}~3LR^g$c z@Qs_v#DZQzRq;TQGIUI`UUAAWm@~@MY7w6QHlyNrB<1LjWIc#XM^elxRJ{EZAn1Xl zD9Q+&f*}fvs7MJ{a$bsRL`qa~I^~hEN{ES`NsAAUS0I!Ugo8?4VDm*x!uG-l3G>4pQs2>h*C# zLcA6)R(Va&*4B}HT`OPzD2UgxA1$xBN8Nf#Xeh|Rm{<57ceQ^lqH7vnsi80Kr!ZJh zxZ{?u#xB*nYtRg^f*O>-=mgpXux$zd`0G$2`k189NRveKm#bLd17cH4KPU+Sr5WL z6Bq~%L+?fC$u_*8=VIW%%EVmD_Y|5kjKwuU-qT&d`UHm}oC(;}D$f41VM#V&8LAxk5@W#N8~dqqYLpN1aPre5zKgme5@@pGvo zu)ufLOj62sj);qbdvS}e^q*D=bh*?_2!mS?L9_;RM8gmuPJ{m3d{OdCX4W#b8U|VyLfmTgM+d?;d;I>Qt@S&VE4P5a?(jNRuWnH`Wf*6$2O+_OXaa1= zIslD8hC_>w`Yti9C0ry9!J@&MFDi=n``3ogRGZ8OSq^DhI8ANCZvbHo(5O!{(S@e# zF9)gEF7mo;!HnWLDh<@2QMZ>yolUA;_Tw|=T;mGCO$!ZfA{5{tp7-=ns>QyOG}PUp zjo<`^Isp3A;$UDaB?wX<4E$L>4HR4Wg`qEDcG>c^%CEU_43kfJB42Lk_1JtHmx=n| zDDskgG95*J9GkCM)-og**dm{Xi~5FyX2<6Hi~O1&3~ZNA{Y1X}PK%S58EJuhO!Aq@xlA=858)QA{}YnnD(ZThIX08 zgMRvYBdtcJb!XZWM%v9XEsbgB`oTDvmd-Svk#Dd}b204}Bkf$7mcg{~Mp{pqmdUgs zM%odWae$=<)AEe8FJzjVX&xhOr%XGAY2O*M_DwRaC)0Ez?Z0K3!nAjcw8vzchiQ#Q z+H#rJi)qgqY4;*6SaGT*F^d>WjH+`T5|QE+fg;A^CD77aNBh7&G(7 zkZ$roqmi~;rU@Q+)=0ZorU@SSiIH}_OcOj%Z={vUG{FONjI>K-n&5#OjkL36n&5%4 zMp~v!6Fe}`NIQhV*yMp+Bkfa}CV0SYq-~RFf(P1-$@I%IP4K|yM%vRdP4Gagk@m1m z6Fl&$k+xK(2_AUHNSh_oP9{w1 zkaJItHyn4criU%j6@c6(pYKZz4j+hr$)_Bl%dCL0)+OR-nb1q@&{UJZpX7*B;r?2a*4n3}UQtxv_HK z9xgik6Qje}H}|B3W&#Ks^bbpz7X|~5$tUxi-j84}+48-&TxhFGjK0QEsqlQ;=U>Xg z@WERzp9~+oaFs37Dt@ZZt3%Dfz#92dj~C!oriRb6<$h6CG&LA_OFkLSo^p3`5Lf29RC1DlK~mV`S@7?!x>F<|4~MTjEO@# z82n4|4A!j|#$qNHj3Bg`STM>&FtkjU8J9-=m^VE5V629}!X@5@ft-saN<`f1hHzt9 z#k+iG$uGevGEmXDu)An0Y~CGyclbs113=?J9L(Prf9(5h-N-rqUm+igec-!*Qy^17LNRZ?JXm(}Ih!qvHYgOqBjMDN0Wd(Z(*~ zghx&TaCyf0VuA$U@*F%6vA+E z;}P2f?lnDt)E+=;4_D}ESltq%3($V($9NUQTb~gVAKZgwS#*ihtv-kdrl0dV`f-TU zfCe%NN5#Xs8;O8xK3<)Pk^IgxS0>)-A;7=R631wWML7)(BDjf1D-j!?7g4XhGL;7| z5F7?uRN@RilsKoMTo!QRIft?QR4XXDe$XYv)S52_zRHclf78D(UBm@9#-evO$b)Mh zZqiD{z3}LZIU@><0oyVF1J3C;BOQz3nCCNIBaT60J%2r(a1=mIN5?||mkEEs) zS2&gWIxYqlU!^oGzylECR*x1%)cr*}_4{$)lZd+?neo9Bjjm}1%(X^>pJhr3`a84Q zwq&A19=EmJBzDr9I<|x-!py1J?5aJQn`N5mGnfNKC@T#{LTS z)PI%u%+R;XG2UY4Y{t5q$Km&|?kSR8<}J?ZW|N`S!=YzwI7D^6=a6}qfuA+Z+=9gn zcMAHC7eHs9YQ~%2KLZmIRexu>j;5NXsdSDQ0aw~Rsu@nGFUlG-WKq5>kc^(VV2xxP+O{ff1F@C8P{QGXB;b-lZWmLG>1$hjX21AxW*E7*w zG+`mpq`OoAezRr;^)?yC67v^eNHgO% z%$OX2X!CZufjPt=iTmGuh!~1JpOA1Q2OL6EaxsTEH4bAk-XP$bY)E4_375RInoKXa z|9)Z-@&O!v_;ZOvszol#L^t7Ww{8OfQ?Y;5UG{@6!5#F2@bXeP84p<8)cD92#`y-L zoA=lUeG>d*U~IY3(q;mi9AmMHF&1lRO<*jv6C4J$+-}+y;5HyAuK=|+)6OpI4oIT>R2FMub&5W8>S z0asSa5lMzHnTn{8zuho^QOELCnc%t)vhqL;Lj=81|X;8k6jT zVyyd7!&nr~6unjIe`=?&E!wlNJj`f#qlAVj6uv!zQ|V731f>~%6)7Rki~zvy4X`^( z@oa+m77`?wjALwoX~YYv&tg(%VBXeEGU7pW-XhG2f$0c6X~W<}7HAK$YKg(qkO&s2 zrRbwSgF#We&PfI(%|z3b(_aJCk+CW{gb0UkB674q39Ik;=kBm}#!Kyt1tM&lr<-UHjrj<=Y5w9H=&n@UPN{pbmv2M5T zbeTMgcg=l0PTdjCgk>EGBTTEhA4AQ~t zIU4{~()-y)?g4%fUvG&^D|cU9?h3R!mE|8Gvw0<$qr)4@zK3uG-ZX9~8wZiFuu=27gbIISuaJWiVL%ay zjfqwI1~5BXbS!luq_|eezpR_f9g5#QtEA?F2ii8s29h&F^Bp9#j*dJ^3e ztu`z+dg#0MNca?MFNP1CZ^Xuj+y4=`Nydj`{v`1Wjr9X7zT@k%MBPFc7EZP<_&ySR zK8!UHWz4={U>jdw*(+Y#aSf0?wx#Xvz@)J)Z-KG_mJp9HA+{y251b33;Ah0PTo{dQ z`MYlcb8I~H*#7m3_HP~Yb{N01QjBKPmbHBRp}>gt+5_; zdAsp5XUeXXH|FIdW2(qlv{Mw{9Q5u?c^j$Stm3j{OUjnUPn{{7S5C?+z-MRDLfvBu ziMEtcEwW9k_(dq5maKSLy4oaGDl%V^ZEjC#Vw-QH&3piRF>aB$NNtK?C&XW`jI1hJ zIVZBR*Hy(^f+dcce=AcOl>+RFVZt?ry~S?{e-AR^R{lZd`bMmo(d+{TgDdvQ)if6> zFI1g*$n1pgYznTHSR>YEd^bW9-{eM6Vr{e$AJwUK3+J0cINF6MyqsdY^H8P_bPn#9 zR8ui%jZk;s)=EbcTySLVR;~-d=VYTfl+rvc6;XG``Yr8?YSP-;dAUW!;V#I}b01jp z!~C7`7gi@~WeM#O8-F1dEcmM({Dlp+nY8jT<-h__GD1~YytRq!v{6#4Im#i~%BG5> zY*i7@R<=TCpiok_s)%JPWt6SZnJAQ$nJUs_crm6B7QQN6NjsL&aiJU(%1m0QN5_Tw zpb++`DW0+NRdGtkh0aDH+-#9ps9cE?kZmbV+7h=ZBYhDUBO9^;zs|ff5%;PuF7i4X z7c{Pda8yQC7RAd4g(O!l;!A-D23}YwmbJ;QxrQ+0g2MX!Vv)sn4MYKV$(37jkRBZ) zFmfw~9O$Qi5B5!m2n<4YO8|1s&-q|e#{%-cH=g%(_c!ekeaa#5aWuYbtUhge*W&kS z%-4xN1;0NeOLV~R*i8K5|MPo-4F50S_X??fFfb*mn7$AaPck8?=+&`g<)YB3$qJSC zKBi=y6DL{cK(cb>IMkVZ#ScQU^7c)1@G<2rpYoO^mRq_kZ@+;+9YfwW{-a(yWV z3?c|)lT!bmG%y@;YQ2Nw9GDfVJ(``K{JPrg6kjD=>Ul>Y9caaU;K=6z2vh7gh4-?) zFj-uQ9fe3eI`3TVY)+A3X@;*R_|cE^?$y#mkAvS$5XBANY@;$VSbrblYETj7mHGhS zRNr7dng@`okdNNE+7vPGd{;w;jhqf}S;?3$D}n1cc};_lo;$P{k7hFh6SA4h^%|oY zfs3KU1-$CCUIG`mLl%_D+wk2A zT3g&DY9^S;Yd*_fGbS1aBBDsZYC(3Dp0_tS9z^Z;b%=!5FaiO60tv{4tDV?_LL^jE zx98fKf@>HTC*`gA(Q1_XUaaDDN|xZOt}s3JQNi|=)jBWW0X)aW_8o)uF~$RXjy+9UB|nGgSk2mR;f+oR@#WHQ+*Zq;s6g?K?Fnmrzm_G)L{4E$l)>K`+c#xy?D9l3 z9JIwq+fwEcZ@@KHM$)ws-b&A7a*@`$+U^ctPo^=Bq)bDpKzqc8ZC4yj;PQQ$GjzzX zXUlM$wi|BF4g84-X`$`-!S!{@^1tEXb#M?@jkCj9az0Vcp|iLh;3@Tt=}0S%HPGnm z4ShB+cKK^{RB92tKrS%pKY=ikgK&$ctbs;gzg*r}qb|kGh=PMSKA=~;17#q4wG_Qt z&NSZtVkL*}1{#vJG0LkMQu7g+*n9YiOo_bjhgV7XLvL+2(ZO{AkZ1QnbykkYX*ddk6KQm{N%8ia{w9 zhArysV2|Ouu+R�^W3NtH5A3DZTFMDUnJK#}@KiFOAn2(THHOur+Or!4ah(23F=I zyg_?&&r@B=`-=*4@nB2|(5yKPx&fLnc2V>9GDTxYG$J&2M zl|w?u(0=?c8*(zD(B|e_w=H>N5YYwvn6ymZk$dbd@%l;X~M{p7hq7zhOmA|N5%Zt9GH>KsgL;#tdDJmB>L}7OFk-?sq^`HElWWE zk?_!OZVZAGoVa#0p7x3CKOzdLQva%@X1=Y%7bm{WVia~_R>9}|B!I+UVr4_$#*oTb}s&R08FGU_AcpA79wM&%_q=U|v~ z(fiI~$NNuSx9DBV+?~^V9ZNv|q607}i9>u*N?NM{OFp+Wj#B>zQnHQ3j5SAGLS55k zhM`5)5yNB|%?O4OK0IU?(x`weL+5E5(|m4cntaPN5fA_4{PRO-l>fc_^U_>T2Dz0DPlha7T@m#Bp$N6ilW5&mf!{u zs}_DgM$Tj47r|7}G5W)w!ZLIs_T7kpvtxYIhEMWOgdf<0KNNmoH)xyaSv+jh6Zoq% z{2G6uz+Bpcj6PnlJ$V0<_$}VzyFBO|iB42j>3_mVK=j?u9GG=Y4F&Lk8r^en=Ai}; z2bZvF|F4T0!?$rdBZ|5!^&fyIP!jrSQUl|iIDJ`|c}%IQM2lWMh_9T$S#_&Nc(ZmS z=-wC{zFHMvst*!OSJN%*{p@|kJcr%j3p@7NEg4T=< z&ci(>%o>o%u0(fb%inY**pgZAXV#?Mqm$~fjsplUIeNs2**beR+uwt|@^=?KGGMB} z3M?Dii=Ju{{MGC}&or#S1G9-P?9^XCKpo7GoXp;cPlCS_{NpWm=eNK`%=!kioHc4+ejyy)Qx7iQ{~cB@btcr2`LsdJRl@T7R^UWy>v z;wcUJ=-*klG##}p7f-Hf{`=~dW=!zUSHERjHV;qF6|n~#-+WgxKnn_5WDq?yFW_vE zJWMX-z1rd?o=3!O@$eH5KH^#dR}K-Wt&e>2hJB*V)$xbYiZSu?+RjhG@u*C+?zNt{iW89InZ}qx&WbSKrum)rQ6Ag4cep>UH?JtPY zVi68|<$1vmxIRaz-_AhmyD2o{e)qM3Bc~}VUPdCqcDS01upPW)=V_$LOEqx;Ca$t& zjCWkBx#dmX254Sk>p^JP=LBO+h&u3F+UWAXNoKr*ZQ9NldF~CvT_+>JukFc?AzoTqzChaK7WR31#|NApHuwL)=5 za;f6U8(PTriMH8zkZ5}$aF};I;vH!Fj;QS-+ENS{3r_~dCoC9$EuXxhcMwTk!1!l8 zNEqcskFVezFy3+;Fy06jBpx3?(G$kw-z^ybX~I}&!g!$tqr6G^bO~ejaj@UUof1Yp zE>!w)vER=v_WO;=eh;8NfyV$Iz<#(-c@dMkz<%c&AWc3QkUp|N`qBjH@M#7}`|tpe za9iXTOzHwi5ATpz+Kl`sOvx6DlC35sXPO}0ga^rOj|L8BDl4wRJGkwMhYk6JKhn0P$fgz+>B z#uo#Japh}w3FCL0yAI>i+a(@%$Aw2fE{QnXqIJFr<6_h&@HiI_5|6Ec!?3`n^MlER z`sIhDEq*ndr#pq`81Z3_Y?H8F#LQhCJe=Y)`|vjyTY2D4cPJU>PLF2fUl&*3u`eV;RVa0J`u$T7%*(}#nam|_JEd~X{4H(tuA(a*ye$@ZJ5BJ`qCNrMV|b8goT$_f7TBx76jb07A@&w9pGoOs zpz%Bd&TCHw&N&tfE;d=P&11m%H6A1jt_>W{Qdax}?-1oDk3&pq{~~d@4nO*wff)1_9I)3{v-bhe0pi8||+{{uA#17gqcG%=WMCV*8P1qyHz<{!JGD z&$ReIvy1&V+FytKC*1#Qt@dv;+rQS{{;FknV)Y2O)Sk6!*dw+ILmT8Z*q5u33_dkbUQ* zviJ8m+rPtVf1%m_6R59C{Wsdj`BEFckF))N)&9d~`#D`~f6E(2{}KH%O7G)r{}HSG zC(QPrKz&{6ztR4}lWAYK+CN~npJQ)dKY$ft%0U`i>1-15r_B;2|D-Q`S4Z;RViHkl zi*^%woNnq}7&)#q+VdYzd+}Cyfu%VwGd1TKU2OlYCfVQr&|$r+{f%#bg4O<1v;D_W zUzhrCwC_Ke_Aj$o;0luk&gf$MZz19#nd3j0pPX?2M_BEbo9#c&`A%2pZ?rFN#5z&@ zAGF&4-faJjF1G*H>qh@EEj!`t@fME_Rr{I`)|E!^q<>bCyM{oR{K9Q+kYJO9i#u&7V?#%ecz%J zZu>c_?N^Mp!@1`64Q)PzvOja>a+-vAI&0-}+K^aC^ICoc*S-W#1dREsCLyD+9r1M5 z$~DZWBIxcfU&b!iS5Epb+V`h^`BS-d=PD3)hX)CY z^lx5)cwZyjI33uhz6#D5GFlG;&A1>&U=w)hIfR#>Hpkn!>!yXvGyjB6#>C%^#mBP8 zEPV83*3R)!!4gq^FnxRz-QxP9QwD!4^}9e$ORpT~dG3x`?p3NiV{_k!>V;3`4c74h z#PaK!`+(VrM6dDdZ7mostT)-b@%5LVKQ?~P`H_X+*O|3*{O)~J;uq&o#p&3(T2Bg& zBl@IIa9a3sI8X%`qzwfr+O8+^fo+c}Itj@{J=a8AqugSZPo-;XE`N zJtxcKF29hHL)Q;vh;@X_y+SxbF7A{?EJt&?$rp)i5`PKBw{ z9-U%uON--zn?x%flf>nA5+^qZHbH@#(qAIMmR_y~aS3&&2S+UW?pv3PzSGxO^o<}x z$Mm)Qa|W;kj-UUKii-Va`#f!sr9xIh6?AVKKT9p$K*dVFKVb(;B_$xHD z#SwHQw~O5m15gx7y-u`>vy5&WJUCEvD4Z8{lH*wb1POBS_yO(9vSABw{(vEx;qd2u zMqHNTp9C*+w{;A`Esi1dmvxwOZJj?D28itb<9}r981$Bip}${l%n<~{2NY)yhOZZ_ zG;xZ$+jgie;XIExdvE|?;_xHS9~3phze(T~(1%Kq0-7U;V(ck|L^bf^7c8v#PD2sv zc=!^F_TT&-q)losO@Am#e`e}je-B`Zu8fZnj0YAq|3bu>cK30Pj~$O*PehwI*?1>a zwyF~1o!k!5Kvxh^&_d}`&nBH8^m@?3=Q`x*7@w9reH=uI$AzBzYGKpXo37e4;Ww;A=zt~>&2rdwboLWzDAS$gyO;ej$HGCMr z;^rA5aVE+Wce)AZqY$1zEmRLue@GP|A&fCgv$zoC46Yi~ph2Uk2@jzG9~z2>C~-A70giKdjm1MnJR?aP)TEzb9* zntGG9=`(&~^N)|6ukBcA>Cf57)v^Ax)>qcD1oS7YA>3Pw^S#@BlQ59FED;y8Q(9Pw z#^H?^@+>X%E8;db%In>~72l!v!JjmElCY#ASW-m&kw?{WShO}9L8mIjsRwJMw7^K5 zg#8U8g^9KJ&{LsjOb|>I>K8l>#8~SGvG`lF!ouGGX6t-BpT-gvl;UJ)a%2sNLaEe? zdDjV!=N%jCfBBt-2&G=kyQHz655-lGJCZ>ix@xS)O$-u|eoM41-(t`mgPBvdGc?*x zr{*;WTu#(Fwo%&u+v-!&Lw-|#b*%NdrUr|i(~vOr7}D^YGbf7KoBFGjU=R z4V`flK#Mt(CziCZ=GZ@vr$4yrYo?NB? zK$`Mmgu-O7m#eH|y%m$OC9nUiG*#uB7YD#sbRIo&}KjwOU;^5IY+8^ABLne~?5b`6$=dRml)8Lwh>#@+YuB_R2u1tOhoo?bV z*@^QWPXZ;F=yiyXxyvkkD9qbAeMia?h>RC#@2;#EPKy%D#r1*lZ^4E8y~v&*g4-Hl z1$yF~Za@qT>7iR;P}x2efiLDE5a4Pc%9dQl5-O3G9(p?V6G|w7=jEr?*iXIqsepET zdT3N^JD2j4hzOV-s=+7I{ItRw-1%#X!gTJq&u1My#aeVQ@GXwTgnbDGF1HsDoiht8 zM}b*oIG{Tas03LymI2IAcCuCvP?bUAMXM?HR=2W}B2=<>t*oSom2f>d0TQ7P%}QQD z4y`98$c?=rFx~9iFwuiN4V`}X-BjDY+lOw1D`rY)MY6i4M*;H9!)#`Z%X0_o^3~jR zFKfH&wrTT3ZMROJXVwPytCaBY1hBGfRpndQykr&nbt(FFy3wyo2}YW!hV)y0F4m(k ze0?XzuIrXHy|Yv>CzbI;m-fP%+;1?LJg{a6elTkqi^=zQH**K%80WRu$SOE`3_t@N z^S3o%PGbo$G<1Bx2)T)U432Ac7#^^yY73d+)Y79?q{UHL7;Fr%f{BKR*FT6e4%;?L(=X&_5wD-)mX?C3ciGWE z>-yTq5wh%GKLb*Zv0qZP#L^FYnYDBM(3d5kFXeR7zLjdKvySb(522C`b*9v>Bj%(X zHWVCp!}MG4!Ye}HF(^^FTdVb$MztCGvxAM)`=hn`ZXys^u#nqLh}rWvxB^W^<1`&J zX3sENRmrwTe)dz~=veyJai4|HwanW&KDYl+;uCPwu)=wuW938FOcO$Bh=#y7pOnKsXFnCx>zcBR-3|?s8 zV7d-mc?@}OT5REO8gh1wKTDn;VhPBzA-3rvKp8JVNsmSivqbj>13ICWyK`tmF&Ib^ zkKOLM_4et+c13-fWk zJlA;eSFB8Z0p^HXnUYqnSih)oazQF)HENNY_up|JORie%BToF|tyQRWu35mw1#GeL zdU^n^sBNp%o9pE$ZY(~<#O&c3m$3#laHX(wJGXJCIg4=^n>OwUShcoAs3BaiurER- zPGcqd2J5#=B_NnGOS>8K53D-H#2|C&jgKYUFDY7R@#A)6=mI}R7D#!H?jB)*S6<4K zxC8QMDO*yetI027;}L{4_QWJXzoN9qY=ZO^^Nl3?ADFGYf!yF#bN^#9un?WBVE-c; zW-*4I5?Pn(mjfm{O@-l+e9lsi!|)i~j13T05Vr|pMfUU9BKz4lLWXkQ60;FPvO)tT zY=jVb(N$oRva6&p3Cf;ozp|V!%u7pCBXG?eEM7LCt?5hm+f$$&{pacR>-g_D764TCYM+$|4s}e zM6gi#bGueGclJDAcu_*BOYNmZ4_PW5#xkvD=g@gR`ezB78^=FVLVc1o z{qLXHn(m(1^j-6~QzI(D8Jd*Pd-#(8$uss!8j+)GlYj@3)pcXEF5klAnFN$3fYr-Z z)g_`TH}UE60kHx@cg?ou5jY@ap9xg2fuNb|nfCd>n>B)2t@%KuoDbZ29P@!?vI_Eh zUpA8{&vyT-YejB1MneR+i(qRTp+e`nix12jpk3wC+-p`;>OWuWMaQP9$f;nY za1OGlb383Px{LEEJBtt0>|oH9`kl(7jfOj+&Hv8c-e+^!L94wBt@aAd_R`qi1!j8_ zogFmTn$Vz$&lrEnd7ZYG9^0PlFw!ost#C*&rv70uCdWm*I+58$Ll@f>sxb}}#- zSi*ZphQm%Qv#i9#O|I|&+gd0eqxK?Zd)PTFRkzS*VORyMj2FTDhPCLQXjzJ4zcPH8 zQ4h36)Lu00i+3N1wJ%&$jLBm>CfbX_#)u8_m}FfvYBSQlu-S|Qh0WOTci&howeG%d zkrDnYgYz8fyI6lH-d&UDfG{hgcB@l3trbmG>iGbd2*vo}yG5Hu+c8%wcb2F}5o0Ty zsqTg-V#7>*kA{ZY6s$bv1oMN3E%Nw`Xt*QdEz!Xb*z{xE{UT4@WAV>OW=qs>@$rXd zvjq3Du#1OY$&D+@hw$4;*v(oXgRggz%`~o(+<$1-cL(n#@1Bf*>vOC@+AkGam-<^P z+O*(dn&9}G$Hl~P9FBhI1S7?Q=_({XtD)~%BES4{tZaMJx}4MzXbK*#i! z^I`0F)S?8ee;4rn|7O3V?IF8-|G(MqIJgqHN@nj*pJm}Q!aN9^j^K$y8V%(z!f-QAW_-V3c7H+An9RmxF)oNWI7 zC!0pDv^28tHwYJrN|Ng1azJdK@3ETyyZYGXNWwXM@|oU~K?||IGcbpT?}@k-B|CPe zcliEet}ji$GfIEtOr$@Sr{T==)lF|0{&Vr~*T(Btg*BS%p%^1(#2hcda>uH%-Rrmd zCe$5H^?S^3y}%;%js9Y)onvn&{}x)_)KY_x9m9Ao1`J#zEF5-@5klP5(fSt+=%{5M z#@iPacf{~F?291WAKUtpU4mWh!S1xcyLZV^ok1?mQ%L*_L%+*cVM$>!_JIFd3W3Gl z(%ztN6#vEZH++vS)$hQ#VdwAdoY5+=zEPOWmvFz=@{Ph^?w)ABqo4!-sBFzsyj%Ly zs7;okfdy!FxAdriXNvHqq0azFjajj@++sb?*c|<&UV)CcvKIgVTKwkj}~ zj7=^8M67eK?3(zR^Nhn+ZTZ1eaclNijZLsO_L5Xpzzg(~n3v|>Hv8T{dYVylD%OQ9 zCpvDD9;@bWR9iQu88u^Yb#vzHPu9PxBzJhKug`FY(!e8f(SGnG##zGKa%40S*O|<_LL}Z4!}=zTPPaF{ z+-RKalzYKOP%I@pIBBsx7;a2Kt}x(Dy}&33Axd!w63@v-*aS!)u3(_KCcNP=r9w$z zugQq!^uCr;kZ*3DhSO^-phuQ<;Xd8zw?*|I@+a!Q1pPLEB~Em`D{&Y7{S_7(5E+-$ zkjGqddDTkdogEbk_ckONa`#88OtSwI5bbq!|HoEUviOS>A!DgtV928~{<9QjZEi?gqRySk}pOuDEzASXi_TPsyqgFUdtUr&6 z57&Cya(P}gJq?m(JFn_BLT2n#n^8!F%*b-V_RMJ+lNA#oGYb(i&wGGDD6XN1{USWp4ZTunn8V}y z`$wr++6EC_M1n2?{#wC3uLqNJ<9|H!9t(7W?2&QV_M_P`=*WFpo{-lBv9|Dx^MX}g{N#Wv*VGNU(myuzU+4*N!7G&1?fR$nFiXmzzSYA@{pCst`82}sA3HPR|aAKHdyWCtwCvspFP)EywCqU%Fg`9QPGEQ&@irU#2E+m zuzxq|&ej&W3XTSygNyIW%ke+VMTJ>lI`;QQG=ak!yu^uqMNWKETl5F;6*q&Cu}WQ` zMVJhifbet01u$ds@{lK9-sxO}-@)g7LZY1x^R%>5Zs|HEUJegviFHyr6TrTI!C13r3FRhVe$*!mqnCZs;Wg zY#7{t`f({_mIqV=V|asP5OBIyEaRLXfsoZ?)r}nE?^RdpSV$Yi--9i+Oh{2Hva0@7)*mWYtvDQi_Zi(7r?f=`utI^om}neX?46T+WMGs^nQ%cW9l za+M8;5kAp>3Pcno0w^I;D*S0o!8!8n`sTkAY~Lh{Ki2?2JAdXW4OemT1w7ikL~;uQ zUnlaYj;~Q3Ekv23#!v&YzKs8AQ1-)5N?7@$Bb@q2ieA5$fy@*~tBsTM!4ZX$lLrb; z&I{HkfiL!HF9}6a0Z#5IS>u*vM+GNe64>Ta!BrO-u;rjJT={KraymJgJ)({sZu0VX z_sO1o4FK$MtWCwZ6`@~Hz_ATGy$oe7Y8ana2)@oke17nSudl(^14&T9WWdnpsFwwC zzY>!2gU)4YncL8E3}Kub$Jagqhi_Igc|!aoR)s=P&CDfMULo5h*(LD`Uo8ZwnY8omXc4+keWR7Kg86`V9m7Tcn3^M4Q`dFqDN_+1z) zsC!e2H~Y@48(Qs8LqcFXtUzCnx}jGauMSAz!S|#T7C=dH_&JZt3fr6DD{qtzW_)>) zu;y~~%WW_Q>@ko2@nXpwd%>O^5r!TGBEI~psp)Eq@?vH8W>BcxOrZail{fZO(05O; zuJ8ayBta{%P*0C~Ur%qSiKuESf^^_=x64AcY-K-&|NX>Q!It7yfl~FTKyOW^<84f) zveX@FYcb+$S1~slFK7?6XDG|VM9@gY$NZEJwT@er2JS`G)uzr;8n%h2Znr57Z;B`9 z9HoIr>~M8kjnY8Z*t*&@logt!Hr=N*@CJ#xS{KqD##5jrLlyVeg8z!!A;8&4gad;B zOsVIML#tBB2<9jGVMSkd5cn2&e|H#WgvJd-JAqy=gvYJ6m#f2+O)0@isjbCF<&w0r zAziWrgV&1y`OH~-)V~v~r0xqn$+q|Fqi|)Uy1AiI@?HICwgoEU!W?N!*raR#bd1N8 z_)M@p$5%3=MO1Z#8L14C=7~yLsu)4q4M_t{DP^Rf7r(fdv1c|#D%4Dn+QS(lYCpda z;)0{ayJHYSo}$J8DK~?V7@b92DHpJ+_8f+R(pQUq&B8SZ6fmP_zI$Rh*3=wUD3GBG z*&p9Tt1rShuth>MwMM4sOJh`PSeyumvqJ-fo;J0E;Q!hFr1OzPeeu_7TEG}b3z`Cl zQw8;30!mVp<#qU5H)K*Y$v+n(&OCo_+FxlwZ89v$;42mQ8=e}Q?<(Z;TlsDf`Kp<( zFgD*g$T!1Qe=novTSSQ)@fVi4M_fYk`hlYnwaG;6Qj)s(U7wGZJ6I>%c4dd5o-HK* zZN5PAwbl?3a~p|Zm~yCQ#hoUQJoX@IC~hNx$)R{~(E%9-L%#xs!JQYW>J}5zdWH|f zrTspe`1PsTlY!mn`en!d%_E_&FwK-ZN6UeEE>4Lxap~WD+l)EfuD*BnjD`PW{>^`e zI2mmwJuGqYyiVp@YbK$0a(#RN^L9Ajvet8_u|yOfSR^^-dTv1!LV0})rtV@tP5QF) z1POiF#WHT1wT#Qj9i&(6X&Pq(&&QBO`9+=%{I5=M{dNUJ*uK8?zjXa}&w?naW7cmA zOkRf8aOuT!e81N+m-d|5j_=i{;U$2il% zg;`@)Sf4v5&OS2d`yW@u@Lw0!Tc3vdump2EEs=!vR-TkU`Sn)M|Hyi48}z=NAF}~* zvh`LshMNBy>#a$*6vS%lHGtGY?0lF+##$?u*TrJ1;0SP~o57;&3$1XivoBY6w$S=d z=xD2*o;1Bcz~l?9-e-<$p;fcj`~qzft`{F;q1F4$aV@l7Y_ETkt^SS{TC>fC)}M0# zu@;OwS!kV}bj9=!Q0Nxg-bH;9ZPA6+p-GD^uorvMCW%Kg#`oxSU(D zD$>QdaN)UNdf|d!F4y}QHPaPfoR)?83>=T)B8(gCbICDta>SY~IVR>#PRm0KGYSh#vyiig#S{(H||W9hpJ@O$4aZL@ zz0A>V^M2*7tkr%1rESnOajo{>_lS>OT&sP^R+X_s4_s&Xcf5wg{RpTxEGJhBF z+m|Iy6u*g!*IO}8m*_@NolN$Jm}6v)zFSxkWnZZIm) zM!B`c9%x1O({)nf)%zqr? zYXbdQLkHs<2JJNXDh=kqDcwvs^Wm@yXC-*O;(I#2XYu4_G%(GY?ERqx#508E5OW^ zqKUJ+A59nCOFDQa#v-bXRwqtUSx3Rd-0V0aCvLde#8RTXo>OAs=XGXF#80e!vwx(> z4}INLdpI7y>x>!};{JALrhl4N;i_BYO!rqKxFS!Yz|kXcq=&y8o(Fw`kIcY|b##+V z+29(Q>F-xEs<_#I5KI{qX9z7V2XRmWB~<2VSj~2ZL{LtKm_=4oy9zrPz*8>>xu0P1 zsniQ14rwQH|M_hepDOjgjgB6aUOGq~Q|aKlrF5c=8%l?_!FSU59rniiS&cI&Av_)9 z%O~>Hh4%7d@KT_&E`si{?nO@+Z4N@0Tf-&yn2293lUijswaQ($Gu|Bn=vfEdr^JkR zjJSm;J4u4TJ|3;vcPsN~JyCa5W_}BL)?07Jbx-zm>gcW5d1j;TA*$*_;Zjp&ZX73)wY7|fk+Sk1;zW7dhW>u zUy1UlvZ2?|)BQb4%Zs=94~8Bfo|ecl2=1izVQ7kd7%H=KgjAdSZg51gc@kU>L+Mdv zZygDoEcJ>w(s3@b3$+;y-oVOY)aI|RXUL}H^Pl0CK3Iobo$7;6hMCwpQGKvh)=;+) zYrYN7gPog8JPsa3odb_x*agxmoDyjT7l0ye|JnRl;>H&GgnbD)!XGk;$Fg8b%0jEk z(=eK!F+A13l;528Z}@N(53r4OLZgATFrKDktrusC&2#IFS7F5g{|ZBheJMDL(l<^R zj*(GL*-$YWIxR^<{@hjN=>{N^`Q5O0C6M?~VmtM3(%KqiELz_M5GaXQvs3EVki!JM z^AW70XeVy3dUSIz@Ja)=5ue|Pzsi_>R;?Vt+CB(Q>cz!Nh7+)?2CH&+v~u5N@g>Zyp)QN}-|_!GwAIahP32iC2-QeS%= z3%cXyd-3x3P_f`B$qx)Xhz1O~DkB}T@bPMXl>TI_5vj+LHu%rbNy!a=mYbkNKmp%{Hfcju+&GoM#Utj@ zDK>PdaEVz1{4h3HC+k(qhFJ307gZ#Y$9VizutYSNNpwa9S0=_FY4c5qa=bnAz3IUn z!|_LMl+-q&w&d|Nq%CSo4?$Cd87wZivbsb4^4#TCe=3km_Gk6#=zJ6NMRB4O0rg#o z^s1)v>_Xgk92RjP8nZan5RX4m9+OEBU3s?2)ug)yO&C8qW!e6VFCJZ<(S)@+TQS;0 z@%U2+;SyJ%Wg1)sRX77)o{yFKW)S-vP?t_s*a#Kwfcn2F3eAsL<(V}QB` zaTde4?<3ZJdTy}jf1q(avprjY@k5$ic-tfk9n&9oF3Q7qqY`qV|KdV8^B7vd@K9_) zI(BO1QQnpkmwdyO#Z2_bAK^pWQX;%oT1xU{Vy^t@Cx6gm78odh3gypm`7=cRjFCSj z@@KsK8OtBpA-!Z$vh(}T4YKIJ4y|;7pKDoSiA!IPQy*%x{t|!6H|kB|_f_zUTE1Sp z(xaBY&{F<+IcVKdz9$95ZYlo|+Bt<*QDEQO-=UBmT(CY^zK4i^gr)cE_YvH<^(UTp z3w&jT=S*Sqes^Gr%i+IpUu42}{xh|*cfbv<;DlW00*p(|tzZg$52#@tp)LE6jr4cJ zS?DWgSlj^f2^?mV%Dd5C)ZOgCf!$JqrG>2FtBDwI%G`YX1jq7|l{fgkq@8S?jGsrM zI__!=(dIby9{>vF**4d*Hi|>j*RExUC>@Zs;JDU|qyF=`b@aKqyX_y!_yc9?g3oar zukYqrJw696qiJwz9Es5W_CEndFXUDho{ ze*{^yAy^)n4{yHmLakz;^6VB@Q^>V!Kj9f9gmsI*Tr2lBG%mbutXl4cvM$GZO!w zVZ{eT#o@3d)DQ{1Wgo@y!@f(&4-6dN2i)+X|8%YF1vJ`S3`v9utnjz>(npC+e<9-GOJkj1#2zZUbH*oC`^TH@R0vpt>$yJt?grF{LylC z@#k7$@iri*#^4?_67B)^(b(EWDi2|MHnOUsCJi1zFSF{R){HIwo(9|h3n~n}q#vk| zy!BJ~zemLY{4V()6maf~lzb?3I}BS}{J?nr8&CxN^hPysHYCoA1}7`p){pwVbw?cjH0`Q>fu{BQBBl7LjQT8*=TjwIU0APNR|p1L;-VMkP$(!< zneRA9Dsx5!QJepV)cHy2@jzoC=Wy!Me)}TjA8O_6)iiw=9q!9q`e^a%7Njdt%L-e{ z29k7o52S;Ef`P_XXxy?PAgYMfavsvPrG;7<-GW{E=d}hK(ZDQvd)b%dqn899Y|nTX z7XAdU`gYp~%J?0l)M_l;74HWRP4K9N&_LmIs-H}?(3D|)_cf9?mZDbjMkn+iKmm3` zYYUw|P+Qs$dI-W?L18YJ!aSUMy+tS(*SR1FggOPkW|IbUUISf%2BnOr7_H0U<2?kuyRb=3&M4ea#4LFUIwL~lI9)BSX9>^hil|!ojqg?W; zuK>DR=Ek(0b^IJ9kpB#h2_h11FwjCD#h$^yT>hp70}s;!5n2Ch^-=aRiM)vZTH0*c zCCR}(ApF{~sB3|{Z@g(v%2wIRaM?BhGStLUe{ z7@vM%e)^%2aJ@)yhI_E*f6X~erjqy5GT{N)UJnjrxd0g-lht~ftTp^fGW#iVk-&Fz zx+D0!Kr_0ZC+i)us@#E_qkEvA4q~N`Ouh_W^UH%a~q= zFSe(con0C<@DR=XtEdVWXT>#dj{jV z4vtAdOizB^N(t+V;J1I|szh>S#13u9|@?RYN>X1nQaE$@Loe}`T@>dWm81Ne(DvS@!`ai+y zB<5>pNO?fkKg!2MeQV+y;cHJLJeVn{8v*nR5j3FV{GiW2FC_fTY|_UjKZPctUPmsD zv>V|zi4{H#`XI1`mr^XllXgu`!&W1V@e;2F!+x?`T9t=3JNyeonM0dXm3sQ>EjuKP z&Nf;ahc-L0T8J8p8Z+83si)X)3&M51I^xf+)Or3PAoj%b1MO)_!)bi~%875YQmXa8 z30GG)!&lBqt=5~xs|&CB)uDf&PJ2TL=C?oNuxx?#NBlXWg-^&#wiXCW#!;n#LEtoK zO6{6#wNyW-%!Xn-sMMBzwUHAKu_m0+=D%25lC3S!)qPFvePMZ1uX>TU{3~Qdftkvj z#tAc(rSP~8_h;9(u<1$^nldXzpDCLT+?SW1<}cGw91Z583IyWHL2l%!!V$K;!p+uQ zJu7vJ{+W1Y7rj&TFT{&yV>;?FH4?6+KcfE|AR5C@)P6C>pE)Ky_nr@`KhH?RI8#0* z@6MJ|u^7?<48uZ@VXsMSAGA?ogJk zfj#a(yIZ7k*)entQzzvO$HXNEn99|bc&N=UMIX@mK(2qB#VpOhL5_;pTljds{5YP^ z1$=I4YenWfbzcd~C>yeX&Vg`~&(?=#3bT7m3qH_V9f){GXbyQ?B8+3@vcnO8;XA)* zYf)sivf)hiAAv7wcYTr3HVWZX>;Jy+E9S-l&-?O9!n|Lg1i4c%t;utY&l?|H?7)YC zt1_Wt^NMz&d|y#sZ9)wP$^(t8;a|*xTE^lyDxjE(*Bg}$1Q+Mk)FXJEgu_BpYw|+b z=%_g~i(l+PEboRyepdpAL5LsbvyAuHKlPx151-Ma@u)Sgc$)@z7Tk}z$2blazpn%qQvPuU zuwg4?SE;WAjk}G{8$!b1qz11UD8%Qnj;7#!N(2}lt~LceNkj52&vaKF9g{Z}Un>Kj zC>#4=VG7B4yL9H@3GzvSJ-nY_YH$>}JHP1fz(qe0f}o0j%7)X`-I5;r%1Mu%3%}X~ zcp|&LIJCJ$8FMgjI9C~cFryhW;RpAUFdz`lERV^%U8#Q?(7|@WF{~A@<8dbBX%f`Z z^LQrakTq}B1A$w1LGSO|wFgj^6f^;-+rc}x17nr?Q3w#b$)NzOIizlh3*}v4TQo2R za}4NUL4&v8b1G)dMQ^|4;AD48Mk}h%_v7-a?+6TQf$KhEqPFr89!vybjMf8jw{Hh) z;A|4?t{hQYqzcXnO8rxiH)8V{1c6wCCZBOB4MC)ZGEvyX&%$DK>XuZcVIIF^A)EO{ z{-XP10rL0wiUEH(s$giy(0XK)oneqicFoqAcDSi_*cn2vqO>-l6{s3d-M$#F0v`hP z@*SKsq;0pO*-lGB1j$r)8T?mf(34gENXk?R(Ql9}2i1~fQvtt+Es|v59%aJ=8fg|o zF`yXt>XBySpyH5i3~SO{CVKH{JkZQZj6knAu4NphyA$jb9&BKWVeJK`{COb;qcbTm z2G5{C{r&j0p_u(sk46)c^)Je=3{0D1V_ILjqb-y{MavKbCE3)e>}HsXYItBzTA)3Z z@BThAgVe*UBt;#Ic#hfVYf89>y)+eQ8se(osWdd>qpAJXeV|B=n#R!xTiDb)2>d=K zuTU-XVEYAnl&rT%0KV2&)59cF$zFOvODU;1U3M}))?GV+$T1#cE*y3lcr5v$t zS4+Ln{REP=ho%A1NX|jQA*!qCa9>2s$8$dw*CIiQpiB4}qmK0&Jrjj^%ah(P46B+O zuq%L_JHmNBs$~3^l<>dBkD&^CBBf|+`2FPmE?CdpZjNz1`Xc6-H&4I&3Jf0YFeb4a zC6;t=I3&zD{Wg4vU4OF-)9q(teB=V5KLh07ss98JLJ{aVL??cqfwL+m4Q|xhH(17T z$)lCMr%m_}EZI+6s%!K2LE`e--VJBzA0jU@^uxF!hEV+#CcvD#_CEp+K5iM_9szgq zCYW4^ez1%x6Jo$I4)#1%3EqQasZibcAD<|X`B!jUQ|k9ac8a#5fn2~wchrd6wiwef#NtAdTB?eJR8f%lA{nW(ST1mff79R5RxCxgN zQl#*qtxCL?;EOvra7Z`u_xQYg+i;SzOE20g$B}{Pr9h*)kAi3n95A0sa0Q+iJidTJ z;n5>bss*#b>H=#OJka9PDlC8no^a`X;xa31c6z?4`kmUgzuY$;{MU zSjp0^@<8b@w1x{`$C^rKM}4EvIVOZk{ZuIp*=B@$!fWu>ABqutQ3MG|nJSAmC$ZV-K zi4TvPeNa~X7-%9+a)1*}qReCBBpx3)sl8j^V+%3@Ib4aB_yB{swC5WsCUPAqVq(M4 zz%%hl?==!@_fE0#rvDl&kNynA`my#V%P}aGu?F=xzG1sr$UU|-^fPdP7?(SVnc*dH zN7lED5D4t2f;}I=L39|*VRtw!jHNWp44cC}5&Xr-|NRe;|0l>#`P~C#(-cRs8E!GJ znkm-vW7cPGUe>(*%x)=lM`NO(AFClXTx1fx`~}fQCjSd3>&Jn3Z6y z%8iJiy_kZj_BSBElCmfjLR)N&9tZV#Ku)YawAQO$KLh#@yT;g3ePs(kNx{W>S8~GR zLhl*!Lw_2+xZ;wRRe>C+Zdy0X$Ry8Cg~lf8e}oKmSoH0$1@e#~sPV5T4PxXMgFa27 zmknF}qnUpO@;9eAz%JNm6KF@`XeLr>T<}Dxpie`jm8AId5Hz2fB}!stu{IKOW`Y|@sbT8q~HGF zz!GnYuMkYq_8yYGZ8-TR7cimppdkTZWU{v#Zs*{5Gp5i{7HD_)LwNI;DAK25R)DhD zG0sl$^@0BNw*AAj0L#$w@I0nPCTE8k*+LNcKOiz|Q~~9p!Gg%T1I&@AU$F2sJImI; z1+ss0F!4v>$PTdiRMAJb)kiqY6n=-k4HbRkzySF(`}Z+A?lF7lj_IGr)<2AC*l5@q z-SX0FV78$ukLcy;W-pWXFETk7z4NelKSQq!C7PQq_(;!&MA-K$;`yoeG_D_kEX9;v z2ow6)9~uNUmLQS~L~_24@lWzQ>4Rk?3f-6?j&eaClQt|Z0M3G;;A;DLbvdv!Fpn=L zJ%oP$4?qHx`jX3_)#CSaV)Q-e@v#^5xY7k~Q|cN31y-NIb8X7o5g<6SOONZMsP! z%2BpKB2yH^uMk0w0`R_?47TL;uO3H}gNr!`4PnsleH;D2a5&>i`g!g2gFNL3c@kVU zNJ6i_R@4Rh^%d}gzXoEGs}IGY7Fg%KgG(dmj-S08vI{GreER?EF3@i@S+44 z055K3-M(&y_<75100bhyPlXgIkOcTK1^-l7Q6@NGIpRu5@fX|5^0C5{M^TviQPA^m zm^zUoRA`XvfG*7y_>fbNQ*JNg$(cN5G+`WqmE zd#&C9$T6uxW}+SKFKe*q6VpGkzR|lMf>7*TH*_rgC;hwro%e5=2mKQcDL=%TGrI^6 zddT3d+Wha-Hf7xsx1)u_o1kSmw2nuozc4!6BUl!Jlq&0*FkT|l7CGpV(T#se`imw| zg@y{DaU!VLsd_Q+*n3~*u=l=4ihqb%Ut<4-Mvo%V#KS!FpLqE865!!?`ZxG7`8RHV z=rh#Juzk+QA8ekLX8TlmkE*A(KyUqGy_iuWkx?tc_!yNl= zt~AH&@n~Z6f6|lrQy!9=Lw}L^?f#4j{)OvMg1aoQh$VCdD$v!?D28C=N;sbJCR$hZ zEKjArZjjhv04X!zs&)=Kh|qh~*2*xHv0aRJ|3xO3*z6(1zA#rat`IQhOIy@M^xTdT zTA&|NVBTj11BLu1-dn_TT}oX_(IHy9wP-e|6<&xKV_SUwKufo#y{Y9zTMdG$&B}`< zsl_cdeSCwI7kdWlHP+PhN$Rr0DOe0p_xnF8IussJ&^}WwOI2QM#8H9!F=bTmyFWGP zyC1&$SRi~c&DVVr8WhPy<0?q8R0Q&U;P}lM{V>doJD!3&1dXCxqk*82T z=thpMA(ws?L@My6M{PmR^OSXd7jXO5(Fi99z10@rzj{_mrQVww8YeNy;_W7H%lTd$ z{oSbj8kqV5MNRX1Nn{o`)uiiZlVmQ~*1C`UD?JJ1Mqr|Ul4ZX>gc`vV*}+m;rl{E< zoEVpXmv0gd-#8zeWDtk*HLjs#D=&^cDlo=12=~gOLljq2{*)INrv{xbV*$|R8&bT( zhpA&Kf|Wliu->#M^$JqW|Gw-4$Kryfrcf%Yo2j}agM>%n)$0I7N2TJJn|MYO*?2!H zHep3wDC-hsXR1BJ9(;GHkC5Gz7acQIRw#P&?+b|*>4~R;o~L}Dgr2eZp4+2ieE$Jt zl=yb`Gx441PZ3++Ijm3mYgF857P9+`V1HEUVH=#*AqH zuQ&RCJmu@6<^N!m&pMv+CDHQt8s&Ejwi6CYo#Q_xTE4$g{;}gJ-{^|=AI|cE{>M|k zE?WK%M)|B`l?Ok>L2mHIb4{O~69m$9{T4b42PeTp3n*c2{xJKo&L z&&zHugC1q{u>r=f+*F4CGv1{`J9MA%o@e~#8o$!19c#zNdm$%_SoHaHmLqccL>!LF z0W5+0^0FQNOsFQDtyzy)tVNAlPYkp}Yy)kd^B_2J^Ff#+-)Yw%m=X^`XmdQ&fyKLh zeIq4#*r$Lx#d)T|j&QbG=~2gK!{45bhvE8{o$Bv~6buVDgBX^7h^S8z5XVnJ!*Na@ zoyCyJXr{w9-j8kLZPCV?Xe0c3w0@I*9+Q53(s-45CoU$R`>DqjkHUjjj zj!YqnOjX@+FF%TfV4Hwo3n9P}j@bE!)&AP<6c9`oF}ZPJ6M2dgQJ!0y+Ff)MaAUF5 znT`*F9wQx1@E8z5>3Ogzy}C*q@~X507f+vr{tjS!*eF7Oaii=6vMGED;B;M$7#!Y) z2|hBZmkxG>7^x0yQ|)oI zA8JY!$EJWvWz2SMC@u-}yC+IKg2!+dd8+b21M&yQG>gU1KyxF% zi@<)kssM_@E0|CY!gl-7Czs{~Ff&hLt(Pf01HlvQ_N*v9+I8%l63}ZkyN1 zSXL2u4-NT-Lf0KC1!NBtfkLvx z#aIaf+zwc2PAr!@u=pv|vJ0-wJI~pCXmdKI(5>fedFB@1X&@{rq`n#Jzr#cbX9<-& z@8;4f5KY3l-Z5;E)3Uu`h>HwAi5O|`x>;s=cp5wFJp>S>66ULFnol#;7w3U+zpMG_hFZN z0#Xo{_jz5EsjjNj&oc`kW^)rV16dBG{sNXPM=|*5u*i0R%LXd-gA)yC5$2DXDqL+l z8pgu^;2>-`-UaMt6fU9tl!lLyrd4=&qlr1Dh5pJk11P2bHNHL1QO0UvO|*rztP{hD z0SbJAquFLfvn`a_JQ!)j2m}0aCodcCIjET<(P;1qN1~C&Z)YRTKqFtF@hgu|VfW5> z=UH`(MA%L9%yMAaFf!OS9Oc8a<8$o(uXhASq$u@&rz604>~Bu?fPMdpx0wAWOP^Mx zP+r_*_AgnxFmAN~c~#7XUm?G8-VTj2D~04h44K=iEPC+DV=T;rPY{T{wXLS7Q z*sw4qv9oLE(6An>&n)_^JBl`;%rO2~I;`KJGAOWH);k#W`8}Z1P-F9*dI6>~LZ7U6 z`0ow9N{TLl!+;Q~U-3<&afMMLsNMGt4gv>!_^XU*3NKAmaX&EgO4Y11@D2ss z%uF3ur3C~^EKNQ|A8uvO7si51-PN}1oIf9WBi(;`+m3T~9BR5Hjxbr+Rm%(p2nfxp zj)`Q>r_Ax%vM+1D2fl#+sLSCHoc>(c?%1xCd`DsM=KUY`-aRm?;))-?n=B9@va3b} zrLrhgkXI6tKp;qnYifLoD{KnbXNo|e#fp7R#}!&V;$z*>p<^~eHBD?8 zxF$DH*H;6HVd@(#1&{XD##_Xz@Qv8)Vfb`{)DOyn48;;>@CJHuB+5$4t**jy{Z5~M zP*!$WU1~>I#Qsdl7(tVc9_Cw->j@8>rS?G^fjwANpqkIXkn=c1J$09@{t@(;_>u^< zk1A`vIv7)70?DHf3eh-2pG;PwQg?|%4GQ)z62xBm{V58I zf?6s5kQzCTZ<5gtCz=eEvL93FFv_jBTUwzgzJ$br&523GR7jU?dmg@4Fgh+bC!5r| zWm-OJ3v!JT(lVNrX^ynx&o^f`kw*74d3O(cDoVP|yLPli%)^dAcCyUh0@Zp3gj%8C> zFkq2}{0C(yX~@4$U572%U8H8L8vzpjO*KKh9pV23UPi!wmj9DT&h!5%VMigQK~P|k z#}>SwN6$|=JwN)-GMgIAY@(hSzLwBaHc#+uegeBX25JEy%^42-75q#9uz<}q@Hm^7 z4jz;=XFwZ(ZXYQIv@D)t>GB?lLW5)5R=fxBH38*DHV?+F3$$z7k&~TE(vVMm3%-@b z1lr+Q2StC5XI-)&KHyoGM7y`F;wbOBVHUBB9p|Ah7ef_`;#YRt8djlq59FAmKzbf^ z`B0BWTWs4KU!o~E_PH*YfNhR;i#RYat~p}@1=7kwMx2&0*1HZBa5-{`k}he=z}$8K zAkb8Ty96$5kA1e2_vbjjug~&mFT4~d#^B}`tA$$gKuc3-p4X*Vzyq|35xKa87CMp? zo5Q{q<}e163+FeB^22=y*yW%%K$>mlVS9@*ozE?mS(e>s6`^@0YlT_Ea`JQe{F3_k zU}h2Xe`CA~j_>cBMt*wdg>0$wqH&tOQt>9Su_oAgEgBu_nQZlcqDa`%Lp|3dQ@rE` z|5G#2c|AtRGSGR^w{8^X$2~?9ylXB+BAh4~cP+ z#OO5#+>#WygBxw|*>Ki-{eUJcG~VfGGzo_v?1Y8*5pXhstkO(s?&4J5)B}^LIY^Kh z))WGc9))KR6CNuGPdHn9ntyKSAb#R(2u(rRkdPT8W`IxkfLz|mW5kckQMGG{opjL+ z^tl41KR|Ba@zlSmZKi0cAYjuAn}YqY^Q;n9tnI0pc5!-YW}KKT=R2^KRm&XfUC%n3 z^^kRIQ)Y^#Ig_=8z(@vem9F%zN8vA(^GD!RJjTNT&6%v=MzQ)Z-aURQ3Y)D*=yPn` z{Y2jf5%WO(cR)SuXT?ZIQ|*ydfZL%@ut{xNQzk}qXIyF~dR-a)PE#hv^Gr4f-iy~6 zSiP?QIXqhCXrkQjf?qH5-YsjAw&W*cK14$s5+ZRjB7;K|ZCu+djvk`a#o-(k89-4Wl_?W%;YV_qld)o-vX2|yFq`P_bf~w zZ$Wq|E$Y;F&p+5EIC#Cy!#wL#1n~|(9ixFg1gr>l|LKEN$Bt z;p~Qysck#U6`SesL6NxXTL`(dgl_)wu16<1ADsG@Ke4 z>RF`kHf1DRFgQzMQwBtY-AtMY@et=~8KVPqVI}D*A3*Yyc%Xodi~3p|a#{xNqE7Qk zBMqQ|qyNXQn_;qhSaSw14z@#F5%`Xh5h?_EX?R|TGKMwqp#9H0|N1p{A5+7|M1B$4 zHgRFJ!^D2qBC1>y337tZpfTW8F+;-WYwWEMrrv`P!WI2c)&?C0BI5gCXN zkPU~(2PV*YaWmt^IB2nphT)4W&|))(;fx9N+d-@{Sku<0agpb5q0fe`_e9)Zd88dB z;Oj>lY_zOG$Au%-kJxMz=jC1mtj{xw)`~;+_XvCsh44+j7(N%n7axuf^cwj&2^WS_ z&v8g7?F;7L0pu6v--G3a)|JflIDbJ_)5|qz#Q?L2Ifq0gGd*Abah|+L=PQFa;=XXzYaXo=md5yOh7#@N}u%}dk`)5#+a)>>gR;B$Io!*LQ|_{M?-08+fS zqd@37v9aJT?qeGZt^pK=%O30vrt|mP{v9mfA`}o+rvL8 z;LJY=r|JA?guE1n&}o8|0gds@?Uq6{Ez&L6$gA{YxGL6 z&Vubde7*HK4o^i}jJ(coFA?S27=j*AuBM=?*sxK=9{9ULGeF&_Yu*%ccMKE8RaUhIa)CY+XB_AjHW^5~dtz#F+HEaCE-}I_mDF zSlXO1f)R&>CU)rpzdtA<|Elxy@5GMTi2Pp|$nyU?q><I>`40y(m2^WPg41X5&9bk@O*AYeixv>UDfHo7``eUUyM%w zU3mWw==T`;U5x*Np5LR1yd3TQd(1DgJ{*0;{{-++JxtT_KiD_?ji2?gzSDL5hq0na z`Na1P|6P5>-`0=gt<~|j;=PCZh~$r8;J;XXdvyG?pO@&b>Kpzi{@F))a_IPX#B==i zzTr>rEB;0+$9uDme;eM7c5s3HPZ9n3flpB!uD?|>1Q*bUe?zdOpPtg2W*_v^yF>V& zolFEq;*YGqbV|VYU#&+1s+sqqgC#qEes0pA`yr{%vm#u-G{t{?OslaQNwgO}Gd|5HG<7dUY2?WZ?i(XiH~L z`ztpB8}tL8ciRXoWwDK@**WSd^r=BulhM(a5ekOgX@hGc5V)V4Zh71|yKhGXH3n@CCG3nSeAk|>u5l4ZlJhQN%{7Yz@KJSt>n2th+q&j&O z`Wi6b(CDGRL-}jE z!Hg_WkJFak$4wY+fm~qE#ufB2Z6R>E0eUS1-9cKi+&?5T=eJ+h{*CqBn~p$w>S8W& zU#8}SC}{K(k70Mfb`{Y>YwJF|Gbtl(Waq0dKyie8ffu*4U}6V?e;y2WvS8u|g6|6k zUq7!q8iXBWf-5AJ%927A_71gW2Ax*$3f3yy8p z4wv6k4}RUL$tRnIrJ(F}beEccFo?u72%E3iU5Hc#C;{*&18wz3s6ue)%T`a{$-{=l zHxo`{MnrRN+iOv{67&jr04pW3k<$F{0Ei|`uu+X`hqc$5ox4n(%uD0#!kYRn!iP%& z*man+PRKSipcGhYzzixT-4~ZIL$X&_;1uo*XPo=Tf#L*>6{?8sptc4sC;Ti+ajB(g zE&(q@@zUajwSG%GY*6D)V8sr%^X!OYOhmTg9T1@FkS(zbC6$`hx4!D6520KA`1YVG*8hap z_w0|U|3vMQ?HZud5uVV0^xwVQk0t7V&Cz+c~2&{EF7sn3O=4AZ@f7OhX5*Dgj3l zuxrUypGES6swOdcjTmLCPeV|`Y24Fe{FErgy2IPGftJ#0u7#v+woYY}Ziqm`Pm#tS zha?6xd`+zH&H<4(cQWI2JNLYQJO;Cy*0D=7{Lpf+K3#oG3rY@IKZmVC7Jz(|DY zxg%SBnI~kjcMuuM&Dea8gWx3A=*KNI;a`U1@FTDX<{5ARy$;9Eq|)-W+??7{y<&zG zXSP2~(Y!n5b{35dCKElsJ|)Hn+ah~44s-mvCVova*A)^#9@c#3_m zU7B>jkIM&PciQz?lx2Eg5PIzXTpU4!T@gU>Fex$A=@Mx;EMST9-;89~<`9DuA0(17 z{<#zY{*b&rr~a$6^Su4C5&Fk3KkP|9Ux1w?B%f=9aQzc?gToP2bh<#(mu{6h$6;xY z-4uS_et%3qu|L<&u6n(OY|VM56LYDFBG%5W^QF@`W8I48KwEM70BqPt$((~7)if4d zL+v;(hV?|8@k-irscC;f8 zhWw8Avo2rK4k$^xnLgyZ*)DgPWDK{H-PDdh(cV1{Z*!OQ1&JpRi9^P96PP>{=XK^w z!A|Uad(U%!quzjaT#fN5o6-Jh_(8E_)a-7ma~weQc74T;;oCBI1!9}M1VlgMj?_qg zhWA%Fz)zwc9Mk+`OeT)==@}IXzwg5ECk_*S!(Mei8QFTUpBVMC2hb22-)ya67shpT zTMzG!*}a4GAl!cZruS&HbRFuSA++bH<>MJTd6(RutSq=u4l(U(VejL^>JT-siD9dZPrY_E{nO8C7~XrUPBP5po5ejM$6!f!X7SEC(~ z803JF42mnyv3m0*HJ~e{pnTPN9cK%6vG}s=x%qMvNDw$2>j^gl5`8k12s(d_q&l{I zbr4S~H`9oPZVp`?zE-RjaYiGtcndZsVgiL81`g-A$P7xCt9jmYE);iaJSO{VBH9b$EIq^0wWOaqNjTOBc=%? z=csM={uqBp=};h6tYLq{XoghaIcm;yy5sMM)tM(cHT5YJ(KOx|`Y!|+Kb-gf;?Q~Z zr(a=&`kO;Q=vIyT`yTJq%=I_cVbou`yc-3agMy~#EXzi79hR$pz{MAJ$ajPo^@z4G zO#KclDkz<|E>=Kw#<7!h{&}IpHDLd1Ux5ANNN&vMZT0pOZ}7kJ-Sha*i%acybOit3;!56x)V5scwG63K}y8Y>2*2_o2e3T*B$bsZb&@| z(J_fTb~b?VR)g_LdY%U3(FPvk<4lv4F@6MP0>+Ql89xOkF`eYwI)=R*8F z6O^c)`Fn%TsYw3*u>C^(Jv4&nY2t6fXcp89f8V8xpSWOOfWLQOg4F|mGxgw}`P+3I z{4Ihw^upg~TfYH+2Xl6r`Kw;tD}Q5i)t?3h$LK%I@*AsupmVC3v;!`~4;nH&3GFXJ zhSNqHB7C==t-<1$Z1rtyNCJC$VR6-oAd3rn7vVEpS7jnRC_zILCKC^-5om6)>W6xC zh}A>nE}AX}$67f6cAo;}x;@0`uY>)?tarWvzaRVZJbA9Y>O%a!fhREa*WvtLr?agm ze!upw3-H^bXKUj3oqX8rh2H{pS?D5t0e)}cbBo^iy;_g%o!`Sh2fyplhxEqpcmB^e z;P-gm4$bl%gJpG;qo@8E^8Ip9s?753(EI0Db%8#*_QdZ+XqjR1Jz{)Fz8}J_dCJzr z?|<{YUgtONqrsv4P#68+zx%@PtGYv7NDuOTwu?vi&hOu=;CCD(r8j;T?EeP*euWE( znct6Ic_Dr;2ufAY{QlhNuY2fEK8C3D%I{HnwkCeB=eT;|x8q-Z;rAafVL~zI#Y-dgz8wfDf#tAzz0Up6tK%2 zLA2NU^)?E+6hRK5I+@wUUvEc{FPp55#*|%t%k#-B&s(0&BZlts_g^4=F|d2{kYLw& zV=(8y7T77m?Y+VNQ`?8~GK=x^53<6xd)7w_;x(!U$!r#AF3SyeY|?HZXA2Fih&HFw z?o((L#^!v7RDGKhx3fXrfem0CEoV*jGj3f)S|P68uHRQ{!x}}DY)fdY-$&N)KVnqC zB{w((us({k)L3aGg^jBAT zu7OhAw3rP}!`yJBZDV&M0HipI^}zS~Nc>@^G6J&+pnYR^8$vh$)ywNP0w9ubKBui~ zCUM@@5RII91{UFUs!O(+9z`BIp3I&oaw=UQ?XYF+(#ubKW$n0Sk@n%*VRrkDQE~c{ zqBqCJXJQUJqIwM8*tHq`aV!gS9xy950ZSzx$StEA(>&rqCSN;Xfztr*u-#k5t#de0 zVj0zp8Q56w*HP|Ki+r;!7(wGGi(Q}f2gkifW(|BNeUWq`^?i2+wpk()zG)kQ$S%~x z%Uxrj#%nVL98AMkndgiijhc&+@%1kF9XO)|T4MQ8TK`ut+^PTkryYWSBarWVPc$-nvt=^RS$CyxGZGpHg>f z?d9-O3&CAQ&coh=Lgxqadkxy!D->sYXP&C$ouY{2JmP&N>o{%^Oin$q2BwC?^2yE< z{(ZqHWId)Jdko6 zfkJBD;p!Ni*1L~P7tPLg5oPGQ19Z=H(I3+98Ul_r5Q5{zI<&NU3X| zB7G!F$EMUBmh0N0oo$!r9YbZr-wC^=Q8R7m!>G5z4Gqpy@@{klvZTsc?U1{a)B|e< zGtMneczV6h!ZDjOmm%E8srv`#?$8npi6W6liCVS^Gx%J(DBV5T- zDd64D2ezWBrQ>p5yWA`{b-IoLenwt<&1H&{(!bl5>O8*2ju2@u?lTMY$K9zg0ONkc zcKJ;(z!79X!s#42?^MFR^ex$%{J!_I4ex%2i-HG!P4~>BbaKM2=Y!g|*Wv^-yFZy= z-;>V(+VAZiSrhC1EL|MneMfuuGkh;CJoys!{j2fei9HYQ#hP{T=tB?{88i32?MTv{eb1H4~brH>WiHY^IT=CDMa!crgKZPZcg>5QUuIq#6z-?Oetz<0|~ zIrxq-1Uh>jrZ7I|v1|mXPSk^UFV-NGx>hBtRf*fA)E)BNV=040a+BCkO$HGNX*g)x zy32FVfHFb63}+OEcy0#BieCZ6P^0~ELML1%O}&lU6)F~ zR-CPz1B%p|(CAqYg1(E~u&BBgBwd}Iy$WXWL+Zb2RFGOh53(GeIWKzdN(|bpdWlia zm^+m8d5mXH@GK8Jn>m~qjuTSQd$3+aZ1W!N)VACo&A0{@h_Rk~qChsjf_QIWkYc^p z({07L6tA<6BVEWVf?29F?%Jh}lr48C8G0!C=NLJAA+Ib(LpG;@$hn=oOVk&K5giqv z!{nIz`M%*$5S#4!yv;h=KIIV|is^G@xPTSKXD4tbYyL}d)o7$8d1a>RMwwyHFT zcwNmP9RHY+W|tBJ$!Y20HEG%6#I$%Efjy3S$F;~K5XZdNlXoEV?#Di9FfuSebsy=} zP``Ja+ecX}%U_}nV3{;Fa#?{sBJNHu`-Mr~Rdf?})`$(>9o#AY;d9Ue*fe{DB zutc@^E@k_Zh?TPr$#3rZd}Q>pg{kk^yyq}Awr#ijYAtfzq0I-pM;bld>G&Kew9KQk zY|lQp4M}jX=!2Bh-wa?+w?|4OnLIj6&ilxh*QS0K_GCJIp7#-TFwQpHvzwjeK%I&*7XD*eUAK5moMKIDe&mpt`DeC0{Y%|&;VEAN)uN&YV3B!F#JxD;c!UOb9J1!{Z8=XG6y5~Re%H|)#c$Sus}~$gMQv;ZN^8v zNG+D_epq3|Wg7{cEbR|mvhjE$yqL?{ylw5s>7{WL)BNRcfJ0_->A#;a zI(ZCX_OQfF0Lj`fJNL_*>D^z#pbq(@Hhfs-Z77IJUK`nhR1m5p%#FCHKzoV}l}m9N=r~9GbXt(H_!qw9j*&rozCTeqau*0npJ#Iii2%=6KT1iGLWdJnZ(i@Q*$T{ErRnj1~JtB zH*IBUNb*TY{gx1C+F|8I5(f1;4Ic(S(Pat#KT-(iL^A~BTiL6MzcU&r(B@48*_ihDsw|#vhy12((>DWy%z#P8c_WyR7;KI=^kXO-%H*}p6>p(`XWTv^z(E_2a-MANRRK5(FsdW_dr|2 zelX4U+B}QD1s+fLB|NI;N>BG-{#h7LH@=QU2Q~e_WDrAqRoLj{W$A7BEDptNVlh|P z>aT}P*L>I0eVMKP3?gjz)-kxtZS@-S;P~$i0P*Lu1jB9hEqJqSs%7*K_07fV(MW`N zy05g=I|*gTKMOc&;yv9zv^CHK*|+sD@xNVt8ir}# z);7GT`{9+Fva_`pDbC-YCH*lN#kgSBp6F51&@FE`)IyZnC! zATK^98LSBE8!QV}wk8abvma#JAQmG@bOZ5;6pJ_LGr@Nwt#bdXR6hSI_$llTJQw>{ z!2{XkIqCDVm9h{}7-UhnvXr`BlETU(1YX zo-=XEPF8bDJ!7$L)2{(y+kQ~F|3?!JlhQO?J36X45ciW#Z08!+6&S&65(fecaR;^B z9dHh84s`iq2L#eEv2Bxg1(IkI95{`?U4iz5=D>%zi|!Y@0$1Vj^Id_<@pu^9X7Kpg zu0TIL9^Zv;z9_G<8jQ#L)?I;r+g^vri1z5fBpBL;E=GHx5bsXLYJ8u=@?IcLed0Y> zQngt%r)6FRz6}<+-M<6RG9RUGhr~6bp*4?^Qadf*l`A)c%)Hr~LYhtW#c! z&@X>;+WA(x??r-;8z@BHN;Wvmp6U)`vf_QU7H6+VPhKQYhXvz(1U2)^v@&N zOb55mR0;gOIo%Ed@InX`rbp0e>REJKN<(Wf#<#VY#gnq24u@?!M`0m3J|9uFO0ewC zQGZ4XRx>rfG0Ql@W!g3x*z?urSlv?|h>qUKl$vHvLBeUd7Ss}cxnUvY!fBb)Zj~G6 z;e8&C`Pnv&B=M^EdQkT?X;)yd1*r9er7JK`PhoBM+|%z6_S5F(X8Rh5u55K0FT7{x zHEc?_rk^VO6(ggMxY#r&q0HjnLxrqo;5?Y7vtmDr6nKFD2?F6%ZDkZ%+ts))BAKv^ zcGT&DNy%WMtoPB$h9%Bze=>37My#{hi8M!HAC<9YoRJOt%cBFN_4Ezi9x zD2)(A`F#kXT1-mJrWXL`y{FmQUmDn)xsXx?Y~XFadK871GZ%s)+G0g!ub1KxYa~x- zT%xAq1Cbl|bff>qjC1doe^eGNY|dOsIGQuF=>cQnpdCyRdJH}3GFSuT_GL0A*o{lG zl}wuF`sP?rgLK{q+B5Qk`Sfi}*1h{^(vR6Kp8-Kl_f=WPS6O|T17&9m84FrYKBG8W zIuBS{JnIL#q^msZ2d%{2C1eOfO8F7G4a~QGuv~}unCLY_J=1U(1lh$swHDZ;`%@R+ z7)5i;GwK8^pODUlDdj`kC>^x1n^@Q(y0NcKzL%6S;IT-UzFi6$e0d+KZxLJ;tcr&;XNzT5)25dJY5@e zS*Fz=6xVysER-(ULKcY4j}WE+`s`fEu7~VEh!2NOFaTsrGoV7sSvzqkg+5%CwO4Ld zr=sEJ(%6r^tBsnpSAB`)eF(h8G)R8vDIzj!XTat;vqXYk335qREFjEJT@3c&Id@^l zXAA8FZ$nH@jxrQ;Q%!31EgfoArvpEfPN3W3AzIQj+$7RA00YRCHT_{E7!??r7A;<# zW_=lJ0fKmCV8F{@wGbGhuEty-;b5TO%TTwNUN2r2lb}UQ`#n2|9RjWjX{YJIF9OJ+ z?wH(Ufid`yZTn_of~Q-B2u2zDTjefQ1Oh;@&l*9s!7f7G%477^XdoovcMc#4zj7PaRyv_R$ALi* zbEnn!>R5Q?trQ@iY0kV0IMUHt&=vm`syU>%pZfh)3=*&44c)fg^9uD%f^?mF2!sYk zKsEH*({Q@M=Y1Fv+3HNJBY+~9)E{Efym8O>o@HYWp_lbcn7>^e0aE1#2O>Z~ zzFLOUI7Y^dN`v2u7|3`=yAaR zc);L_M7e=^GVOB11cdk+rs1#LkVLUt=`U({5$z7_>L>3OtsqhIp6T}zdMiQRO8nRX zTP4nS?1DN<2yk~2Zfs4-Rv2ELUZk3(FleL|XP_HEh%Jc!1q}9qhjQuOB}%($P^g&5 z6Kk6>;=8;!Z1=R@gF1)=XaWti6qSz>Z6p1z;RXCfr}ip6F$E%hQCOa zE}u!48?1Oy7`R#v0ul~_rtf>}4o8WSFRMlFl6{15_1jl!KHSxk8o~be>V^E z;2J*6(W0cmxZ?T#N1i}bU~qFi^B@l)12CV@JZ@E( zfXKM(5=$QVSlE-JvmuXit8VM()?nYOPXPt&d?O*E8}}T3I!ZuGjlqCD7U4+az(bQT z_LE251i@2YBrj`ykhm{@<9m_n$=5)LKt{u80$c|nN1cib(Y^+;rC$FhpqfjeO<_Q= zuHbXtT3|2whnQULMM{Y22HlyGu*wpwr2gWiTncyS;}gR}8zr05V~G_!rCNf+Ny^q3 z;Gl+37sDvz#Ignf872zn+Lc$ygL?b&H|j{bD$-8rRPkoWHizH$?)u1PM@xk|GDaJ3B&#?@nl zIDu@5c{;%`gM$1QDMHRb-GRgM0bSe7z*kW)mOZQ!Jxgg|U?}9YLx8 zQ&Lr$OKse<{|`Y~=#lF0L#n~VAhlc~YGVZwiIpgyd=gu~9ViMPU_Gd^=kVMPhiu1*Tld;6OvdUyO2$xN(%j{4$@vKoZYO!_GH z(S!>K)G@5H(gkbOQgU)|%^CH9psrCW zv7`4WBS!O8f&a~VB3s&~H7`5XykZqMZtjXny*p<3>C~JUTV|87oCOB9V~LclyTfF6 z$|qiC!LhcwmA*w5T;5qXTFz5(>0rB-^Z=INHSvLSnsiFT0@iVo+&mS^)4UVezSzI` z;vUiPajJGLQO;5UgOzJm6Ag`PM_@5q$x@XltiUQ3ISOCm#nO$KV!;Preq`v}7%XTL z09JKRK?aE=D8ch$nXnK6S8=`J(rUf6=HEAff@>Rwq>SYYyTfgP_#`2Y=D{Eq) zG+v!%5A;uq7l&Y7$);u?xsqWG41oO7-S$BYt!Tv?_sAE=AoPrZmY(isIGn%%wtkbP zU^LvmXcS(58e90OUdO;eP2pu{Se55**r#>ZO2*2tYam+)M(rGc4Yl5 z_=rAPK9lWpwnGKO+D;7Vh*zT?Z^bI4FYnYXO4czX%=P8RP`X@N4nL!wK|*X3frPSF zkXqM1{2>0=GIs~7eK#gvOysKQ@@A5|&Xdnzl6Atf4wIM|uzyO5DQLlE=+dN1eL=e*PEmzXi zrXMCRf$!3MW|%MAvIR2^Z`+3aTznsT9w-L6f&MfndMtfzz$BnhZlTu7XFz2uE|=!~ zX~d2P6(6X=Z1N)?Hj!i4Yg{crJhdam6nj`l6GjyoV{wc%FW zVHgC7MYL(+3@)-graCzyZ{0CL8cBD+u@&kZ32c{^$J0O@a<&^y_*Ead05>FE}(ecH_^*R*VufqZ-6f0 zWm53pJ-VPFuRZXn(%&cchfdJuCu;z|P@CrBzHICGZ0sz!LvHmuL9{+}J%iyB>;J!I z()}d0{n{A0Zm%*;u4}|@pYPiKQWcx9Ps!VxdZKzbc5Up&{g`e2p$w!75rkh}Q-)xQxi_BCCqq@=#*PMUGIwR*BLJ7z}K z4&`p}xRIpZxzkqv1Z6opPF4tmJQtsT+<`Bn`)R3Qa1O3lCjykaynhQsZjNy4Xu>_tAaG2?ufPGzyC*e@Tx`INj`giU69OWIMov3=76| zO?Ez^Wj*1odqNZMR-AhkoWHh6^OUT;inB3#HU=D2on6U#5(k8wJ5pQRnE;BOhtfYK zXT6Y`wFA545Gy;MVh!1LlXIKxrmUxB=QcU(>A>)r*`JEVB0j2&gQq)fbDVp@%0M)# z*z3e)h4*>uwqXMY_W0cbjm%T`xFF7i)p9r{aaSlAal~XV8}(4N8C^8p#Jh zCAk9f4xyV%XYk~?*l9zbbpF(~eLdaAipkp$h;fcDuO$aPn3Wkb)R_pvenXfYGNaO9 z1RsPoY0@9@(fC>iXe=n5d{VZ*cDv(y0w;!pg_0x>ysc2h6GbjTA zN(?T!J%Lt|`i|}1B*ZOHVp}aIQs1f0lJj2+X|T-a2=;O zU40VjDdQy#G@C(JF7jlIRF(n5Uf+V49N3oH)n^cg86wdo;V#KoCWwJS-WCn}i#EQF zEy9LHMgEi&nBy3y)J%pQCN#oMtH7wHSYU6@_3nz1cjq89pW(HuSDQg!1t^9zJN2X? zP#g#a^`YTRqTx)!y8XF*7}A(h>BB~{=6qa{@E(m4&CbJ|E64cbBgPzT?V^yGu46?HW+B@eF2vm*cL` zV7qBhK-S=-C;1)ZMbAiY3AEX(@~*^ahbNnbOe$`40*Y1 z5gKFXsnFO-_sxdJPU>=d96MiQY%s>ofgBMVJNtXr#|VMhMmd8+Br9hz0C_p@!#tt) zayDSl9g0y?!FL(OOO$M@Z-GUIfkS*SCREymD6OfeY^~*|SWDcvXUWglnE1jLDt7Br z77-nZ9oNA(ynz<)zZ2azK8~@=KN!W9>Yj?iM=#dLDp#UYoCT@eh5;MLSfs0)Gwmca zKJQ+PN4Wgf-ZcQi@2><73yh-pO#NG=B(&rH36hCJ>Ei!^4HK66k+^giH`>}^LCVAX z0DKAZ=wN(iz8~|W@p-YS5MPA>BC@W+0+`l7UFR~jekV5TVH*H7Qd@mL0AM2v5dolO zY6*)aizmh6Ite4ze*k`T%h;FVy=P;Lpe(#MMsBgyH&RJ4B;XZhWb{QE!R$=UYLpI8 zc!m|tnk>b&@U)>XiO#^SABSuWZv!8)l-toowWvk3K+7$y7{6d5r)>>;Q7hosT$F$= zodX_heXu@=;RkUGlsOM#WWzNk`=L3^V`S|2mhZ$E00ItKS{n|^AXH*_(yf-+xWF3I z+hgjIS1=u53?SB0XX9C9$Mw#wGy2=SQ=$9Nc6Fe83i`nBz!!W~K;KKI)Pjh;J|{MG z>`blOUyW_C`z>7uR3bKug=CHhs@YTY55 zw-NlKT1pxK-W^$|_*1OeLw?y^-PDNw#v)PO z6mRG8{xV=XooSB}#{iFyL~cJ*CdL66i7>v?Ea)l>9H1z0456S_TSKj}9}mPvB#7rF zC~sNHId2Ed19>|@nv(SbX8+if zzkggSzT@46+SS#hz#9mZ@7W9;i*z;X?7*|l&b?G=IQ{2rB#%EEngi`MoAXi(R-OGf z(yMbnmeyYI&7+#cst*KM6M+QTl1YN)nTI@WKiI;c50MI&wO=9OpYuSBe-%O*!&%Fg zu{7epA3>%OoF>jouxhz+PwXSC8$Cr+3tSS_D6aHQ6T~9u3<_K7&^t&uAN7F`#x?hc zG-DYtR>n+}b(i90R59L0DAU<$*Pr=`ByS5|@p-xD>51Fr!+<{FKqhjQs7+X%+qh@L zkE7`PJHD;N@7&pkLp#`J3LY~EP2Rv8#rulmF7G-FgdFIe&{J zfXA3&+RD6=B^iYzP#a)}C4*^r@iNgl;-YPPlu3`fS|ulda*Uj1Dj561Kv(agQ5dAh#W*%h}FKN4CL#Ld`O@*$gaB8j8}%e(RW1wkVOSvfWwqqvb#_|3BsD)4^XSYtWldb* z3yh4Y!ay{=$75!Yi1uZXVgVx^SMuXzdteqmPL+BoHjm@(bPOkUv{1DQ`}=@7a2?JX zTu1vZLV2slwz0T|)6zh7EZ{JWJpx&f+l_76OVk}$Qro!a?uR)8sMy+Ptk_HpmZ*=i z_#DKeRmPCOQr6k3A5b!`XFc%(%fh@v*~OAv!%^!VnVd7Eavz$kocr$LGrHzvK+(C>y+e(8B1_tWnpx}uEFg@CZ z_HEk^GY!p_TGT>FgFaho&Gjvd;iKF;2*n6XwT*p(FvC@YanuR1Aw*ZCWoK)4vy*Aj zc(#F7Y(A$T+6M(4=?AxCeN%lHC!T-@_mWLk>e^7Ov1E9~z=$FIFp-Gid3H?TGQC_j zwkXN09aPI`mi)xc67?X?!fo86{E)XwpZ8DYZ29ysc!%@W*kjIeLAM_DJkD5o448=T-;uyLIr9Zl`%je1cX+h?BLZzO9pa&*{jrhE^^Vp2KW8!dS>1${t;t+6L zbDvXp^Y%P9a1;Ug>htIIPo!cmQLkm0eTdHyv0kJKA3DUTiJFl}giQ+B>K}PJ)ObI2 zG5j(PC|U!fs9NXrkIq&VBVKHiPx=P(>39PU=-{NwmwzB$ zwT5{0TP)pd+*5$Ov%RknCvb}xX9>LQ1UWD4fKShp{M9V!XioMqYA^a4_6Ton46d+a zc199nd?6HrKzfY-3a}YZa0_L*Ip60kL(Sy-p8tqy#^>En5A_aI5S?i3_b0SWwki@# zGFO=jqvL=bgkYaG|ElVgdB{^IjgL`T8Fps+HCbc z-i=~D+XS|D0kWA%0o2*RT&O;&b;s7gN{9X6vr>2a7C3TknJu}n|M{%G7;pw7!f4(X z5eD%!1u;u^#9*E=t{WG5abAaHrG>XUkl;(Y4;%1ZqGwk%;+gPkZlsx$F!VZmG$z2`VFg$OCON6t#xJxYR z&{o0y8BT%Qyo$T_l^xnMr5)NSxE8pV%enjO>JIIavJP!2+<3Ux+}x$y-Jz*)H{d-A zu1(@DO6<_4!`%ya8{Eh1xXWMLp~b+z0Pb2iVLf-(-UAxpeg*e^xHrAreYCMd+eVu` z;rZr(%OSs&=oz6bX+xN5i^KjzM{ z6?DOk#(Ni@pZ|orevfu&GvVstZi8F-ICrf-@6dkmiw^A&+*5Er{S|jFKGC853ohxG z9ok^HVNY@A`E7@G|Yw@DROBXMie^UsmvZA?KQ_xl0|_3)ky; zPI3riss{R#?WuIa0R^G`Q9v zzY^rf@EI8+hpNJ&)rBiu#RXzv^=giYXHi)a21+!Bp{;g_lZ3@pE_WeS6sr=vl$VM` zJpu|V9F@ygxr#(bO{uuDQW7b|RCt!lBtfdEu5uNXmXs2Gj7tSBx4X!(rm#$M4MKG3 z-IA+-Dtr2Lse(Pt)n8Ch;i?r2s@$kkN97uqyQHkLMkuWWA685fZzrr$?qXdisy%oiU?qWx2MU^B9W2%HP3rmFZ z$_m$75_%n3d_v-sq~w&T(^7>oli~qzlW>EeV}Ym!tCx7KaO3AfAU{Y<1~6SAhs|DXBJESx?x+wN>X)VhXze z9VVzW6BVZ53nZ>Ab``A=4HoFhCpf4u6CCBsnW*TcGDG%`v81r9+9gy-f$&X(6-ZAMy zL|tD{K7}!}g)xP~m<(aea*he2c~MMEX3dQ0J=3w{ge4Nheyxy&jueljlB=4Y%Us13 z+_!Y4Gg%whvd##Y^TJC0^tU`CuN?|tI zahZ?>EDNLx7ygv36=q8-B#bUgTvej0e7ValEG`l&>A48aodwKs6>$%+5=J0!6DmSN zI0yx$r<9aRKmuWQmXMt#6qXTN#Y%VDQnVTU&1JNfigAwXE3S9AYKvU1;%Y~EVQp!- zR32i#gIX0j`r?8bSK;b{D$yr55gt|Bm~bd9Tk#|0ZO`V@Uoj0EX9IUj~h z8I+Zxx1|xFXeHQ7WK>pBUtCyLP*_yts;(B?=&~xy3yNK9N{i5ou_2h6ePtB}n~2yI z5G?27%pO9~Z=*J9(M?mA$U99M$q?j5F4X&@P-035T7k~Hv>1WZv(YH!Dsz>) zDntkMaD0rpXj(M=LgeRm6qRAn_y#Fm)kTF>AcPt_!!W@CP8T{vH;T`QVE}z2V>w1g z>NH($S4Gi!SGCg&=;-5@a?#5`NYCI2yHpWSO>ULSq!FDGpueGw5n=ER!b!%rA4Jw z<>jt&8fy8-h4EQrT7{|lODhmp=qM?zD1~Cfb&qn0G^7doMFmFn62}d*#($rorrr-i zSL7-NqnEEmIxcE%*9xhu(0yJpp(Rz7xoS(rwSQf z9En12_<${>OeaF)ag;%kD(gdGi(QaiXlUTbN*7c(sB&mAJ>*eTDU}(-5J*TH3ROY1 z3px;!zuBSI1zgaCSGWty%Te&43h5@;Y7}si0AMQXTFMrnrD#Q9A9ZpyC=;rX^2=Vl zWd6+tnn^-l#p;U68YCpu$U&pGFk8qF<_Jz9QpQOTcu&l0{>de3Bdbds*4UYO%6PSRsJrYg|U&E71L-EEC0*g%up*N@3+%l(9m8OoR|f z)j}yO+N*^!q0ChxPF#+T$;G`G8_L$QfYmOM2UQiKvq9BVmsazDYS0Vuqf{KIy4sW< zYI7p`HJ4B>R0tKW8s@K{04OOKCplG>0u)uDN)k3wayp-2tHL|D>s!MAH zE*3^s)l4)*K`ex-v(oKyLE$MY#^0JsL4wj=48n>kG09pZP&ZQw#hvpd_(myfgj!*( zuufR#a#un^!6N*vT3IM8FDtBAEfiIV?lPgcbVaF1^<1?Qx_b?D4d^8hG^R5Nm>eLa zmIFa1pkUxHG!4t)4BtXYpKW*jUmo<4n5CHetf4I!>l82T>s zzeZ?50S_wLNxS{$@!IKQn{;o^6ZLYcV%hu z}))BiM3q8)onuV(bhthP_Xvot z1N{uTP^gUzyBP{KTU01fFBDR#1Sm|Tg)&yse1&lQivS_*+4nc!6 z`qa{OoXRl3HKlG59jXa=1v=C7Lsy^|E5>-u4LUrNplaoyVY$+cIe|gCNxsabuNEC8JB2%uY^HD{{tIa{g|syM$3vJXOq?m)FjJT~Q5ZE-7$sCx^7;hkd+rhN4^cPX zAdDBr&lJXwhaY_-`UsaBnu4C~7-0;s-iZG*(b&N`J$ITlFcP_E(xgd1$||#%JS*L> zVCZvTfs_DrhAT+5W`0;FOmEdIA@$T-@G$)q!wl|of-5KhNePM5LJ+|a*qL0IJC?wT zQMgb54Pa;)losK(I~>B;LR8_}@=A#--mL2#Ct%h9V^5_U+zxs}zL`O9$cO2p0XZS) zTOahn-bGp7c1JMehM-T63%*Yd`9k>b3q4h+MlTp&M2%&4G`V1h4@CbTL2xD?|m zOo11~6P`jh9)5!qhH3F)NrHr8kRGK^@ZUWs0yp|1$_LhOzHz`zSSnBdaV_ z9K@oyZ2BlTkk1Ne53pDn<3P}(OZix#sX1!-4c~6P-FwzI0A>J*OLTm3K%t4cAW^)P}$WUUlB7%h$UHK%XMn}chh{B_E zwNj5V=cUJlgD-bi78Wy2!3@e2O4O!d3M;^zuNaeDM<}R_CflTHVd7|LoUU&NM;xso z(?v+1WX(5BD0t0{4Vw0Yg2C&f0I~%m2x>Z;#KzFgN(^NaN+1^JM!_&j<1v&pU8Oq@ zfaM%P2NSgqtSiEzO)b4GpFs zZ;9?_RtkZKFM&ow;8=L%2o_NYRSGQv!46rLkPO0$p$5}Sb-|j1@B~iUFQNb9INxO^Q!SNJ>nal9ZH`oRpF@HECK>YI1yXLULmA zl;ou3gUVrlcgLB&VdLOih`Vk~%ehYQogSsZ*vVO--JfGIi?I zX;V|D#ZOC^mN;$7w4`at(^95Qoi=S+YAQ%fMfRycor+|s2ofydLJC&HidQF0gU}XK zU`@p-fHNtu)1yvJRU`=4Tz^_S3YRkWw6+P3-b3jV5(v9ljD{ThHvAtD@hNJVM*e)#$hQqBn0=~{B;KT32m2lsI8wocC zj_&Fk4>uVu8Eys~t^miPngC;z0AmzxO@dnjcMDu0oC|IR+-kUTxVzytz6^`m@BpmVMmvDrSw(=5>A|2H^ z?QN&6IJD8;0hbQvfn&hE0Bl3_0yw&tl5iSe@P@sc@rERInz5>Dmd{||RDA$7M<%3V zZd8dO8_J?da6>3lgL>KgqD4yz5)w@6==>rlex{aU0~bSRAFJp9js>qruarX z{$oANpy{}LK5a(;GvfYktq9J5qh}Jzvg#t`G4lT<($)btIRl45*N=62DE#k$Ytdm` zKj5%W>vPJc!RF5bb2U!DE#wuocp(N*aQL{`X^olHv1y+k@&vpdvyf< zAM5Wg;ra3WF742QE-f2R!@2POY($t5*V8loBCt1oFNC|N^xrnDJ0kyU^!&CU{IlvV zZE#KBoKw0u+*a}8Fy{Oy|HqMk?Yh3Xk83XucVi!5%=uCN=jyw(H{ePe_%jjDBb&N3 z5029ghkF_>8?NNBF6~!vZ@`^`8~HPQ*AQ1f-vqZB?tZuz;6l5^3YQlZyGmwf+%(6T zS$p&NiB;L9^D7oH8x!;LNaiW%?ND zRiu*{x|IX|S#V~3%dB6eBhCY70Ne#{8yx9(7jylPNk71u-Nn-MH9i`+?*;Dv)McQ+ zeQ_7Ue*^KFb4Dj zG$))*y+MUD+mL)%5z4E~lAn+izL}eB1?D+sWOO)*db^28lgL_=zSB1nVR&RXx@pGF z<%mR~@NoEqWFtW@nVlC;=}G4x+Z);K$X{&olWmK_$X+*5_YM))L9Juh4dTf z9~Kc0H=G3Lf}>vvTp?T;Ts52#PWUcF527!grw&8-9lC$H$xn0};TNLafT8l!k7(0KD`FnyRJS*V{ z7u7{iFqwK>DV~w}5dB0m)un->Cm5rQ01GP@y_?HI?`GPKc!NfIH`7D!W*X?7Y>q?| zm7DSN&F{X(vQkTX(>MnBR{nPqMQ6g1O3Q;PBan>$xCGXB0YQ!p1t9iqsI}R z-eAmp1sJObf~EZEXYjzF%gif^H_A`-LO z`enlz{xR@VKSMwAFN8DRLwZm`yxv1&Gh0}1pJ)t9FkyzpK+|Cdfg(EQU~qW9JQdwC z9UI}M&s2Tw9#+Z%wm|^9bb2$2h7CTjc?S`NMUd*C$FRdu<}w8HW|rC>^X|ol8S~i9#EMuc=?5s>=El{B;2`^hud4GelF+^c`PczQ@eA|j+cp_zp zG!-KQtN~&}svEl@BP1$B!ndoxUNQ@>%Y@`0J^X;%w=6d;ZU!;-Tt2er8z5$}J)e|s zSN(9&nvcS1Kdx zzc4n?;+F|mm_V8``Ie0+ER*ooqi6D8XgB_xNEuoJ_PD9?+JNRR0zv$+Iiws-471mp$m5D}2Q8*6AX9G3l@-iuSNEJAvQP4N8q zQ9(G;(NB2ur?d@&{RozR1W!LoLqAGKKT1nKN>4wAgFJ+Xeg>{%gO^6pySio`?d=fk zzd5AR^9lE&VFU3@UuXaFRy;jTPpBih=6p?=kdRCxA&EEwBh*%$)t+#NyN|`Q+Mm{hheg5|?>E+* z)!u=l_bjBVkouO+NdGn9m)D=wing59es1Th|b3UaAKaM);3HSdhY?=S8wgJw_Z^`E&|2g=7hq&XACnNrU@uWK4_K#4W zN8ld{xi{zikj~TjYIwLArZ<19DGlM>4O~-AGP3H^Z;rFKy!slRYRdC5`1ixj`7iPP zJ0@QCl^%jygmfF=-iE)g=~~-4?CmG`(|)q|w2$d=MjJNgas8KPwRhntY}2W;+RG93 zZ-zDecOM1KpYSvr^rsPLe)d0x@wNxvb_IH;)to-kKkj%a-K{2nB%JyEyr?K*EwxFzV>oF3wh-7 z_mB1GgNyh(!Q6`5i@$~&v-F%+x8$7mbx1c4=`MwzV95O{=bToCFyr0)+;?-& z;bxfshJSu9`OLrNoEBa5zoDVGaZ#-eC6u#;ePP873NKF~9fK@3}3M?jgNj zxL8_(`*i&|Eo;L$?Mk>rI00@Y+^1U*t{@yP5l(C)yg>RO_G@@iF zwl(!3mxTC5>>O4fiBC+*taR7lfaFpbzUY3yT;md|zT}lOA2$)KaJd)q)53j7GA#qg zcAdD;s}HaVDVcOSS4Tb{^vy4U>y_&GB> zyR$IBpr~siu7!z4H&iq$?@bMju2z&*R^GC*(juec7L^q$8YLPQ7XB+LO3Ocyl2KY& znNd+uVo}$MO3RFj$^vC=fA42zc6SzMcDMVv_xt<(KCdq?R?nXId!F;0=bZDLzjMG_ zuCeBA*m&cm$UIyhc3lj)8ae*@{OK`DA39W%igzq;%)@0qcr_b5+Sc?fO~9{WmeHG9*iX3pG~yuyb(vh<1Nyj7@7~ z4w`$6+@V85`k!rFe-UegA8s^|z;m$_@=2#_?|uK-EDgyzQ@a5%R-26+L$Bmc!kt4` z+&Hr!=C+YFmM*S}wXzQxuG7z@i|At2Z0H$y!FwWBhGTtTNFJ7pW3T8Zo^|Cdv5Fox zZWit|z6sYW#QMZ=)E52X;>%)gAtz1Ju7lAWgW(ina>B!?d(+A>#(wUk$#ksqx0x_J<5V4W*Cw<^RMpLx)V#?tH*g)8Vh_YQz{*J82?a#S|lX$VvaE znTLhmK4P&zkwI&ox zzQ$?Snw)V}tTkvvU|;~Rpxt>HgE3CZxxR1`-Gx~c19`~Mvy3~YsBmL=U}#p3eyP>C zz)fQ@J~(7(ATP1@Wy8+C{F>A9ZoIzm`dDk|iRWL5yJv44S5!!48e=*m{{(l)@I1P3 z<$UeZxftaS$@)|DlQj1ltL&5VaF-rNc9XByJL4Fi8#;7cKHV&WF}~)VP=;5<_~;OH zetMEI&OwF+XAv=`Ff_~PUV{x&e-Jyr*X;HA@51Lvd?;Lm&#~Wxf7T+d#e~xyGks`R zn*OJqssW z!*liwoB}A&jcd!H18}%#M7yugo@5q8Th4SRr+6Z11SvpoDx zz)jY(SRQ>Q;GfG`9)2g#9hZ6dop1||_2%Js!WB4woQK~DGjJ$555E&|Z4}GH?*v?R z$nx+zp%CYh^YA-?E-J;}-^!bC4NfQL;deqljt%GGcfxhJJ2MZz6X*)fJp4|;bx16a zlAnd6!+H3fa6QXGO7xk4f39MA_?>VS4k+Z|cfxd>4$i~xge!4mIS;=Ru4Xy^1RtLX z_$LQC(Pskw$$>WXnSg)7>@tKdAGfA#s^2O~Vzf|*FziMgaiMGGgMzaI ze<>jpHC($vmHv7{Fz%$FeUYwqrs0aq=qC2UAzGFQ#eHA&v+I<@{`L6O<3r)y_G`;`7eD)=Rx?4#pi1Lx%g}GDZr-?pV|0y8lQRi|865( zhW{(@S&mPY5w{Wluf=B@KGpcVfKMYnmrsB_@Y#t^--(C)gYog=PZf4tc-Y?^|5JD% zK7Z-*ap1cLp8)P(k-#0^#B8n~|6%?Wy?Ii4${Nl`Ud-47yaz%C6u=$=h9mWJc@Km_ z807Sp2L>WExnbXXa3x*2hM(Mf2A|a9nhF;gPx*!OFSLk& zUVffHm-?I{-^hiRh|!-SuH)TblOW~jwGz8uNLwVaABFB;IM{RIgzXY5 zc6_S~_4|?ZqX<9BlkOK;4gU<`MWTf8{bFzOv-~LBQO%|#{!3&(3zvQ-vPRMUiO4GX%utmFlX~Q&WnA)2eSL(<=p&GP!rlcaJd zE0x?oOKgeceoA7?rG(WITP@KoQ>0HacTY=M&v_wUC()JE;;vTT;QSU?#EA1l?TrX; ziLtXW7_k>`QWqUmpGp(z0UcpzcIFsCnNL{M=7^+$;a6rTv{yfc>;24Sb@?# z9xdz%e1C#p`Y(Z(2=^eYSNaN3suuY&F`PeyAFCB+_w@pQl&7y1_!}H0&3+Rk)OVjC zEfV=0(G!+N@R_gZnE@>V-@)n60zNHD&xq_;N`;oko1`7UMsToqWcYMU1`D8{VT{mbij83 zmp;{`War@DYa(5-{;=GK*TOH=oT!EDcQiZ_p2{FlbB=B?;a zw}~hCIRBEk)l`yftsrd?cuhFBAG?FGJESd~&*hg<0@6O}N~A-a|Ac}G7J}~k$Wr(7 ztj7fY8b@Dfr?6Hx$XB9g#OHWaqj&f`gx?dSodVk>NP7kTX-JVE{~>T5;)7w2S2g~2 zL3&GI?+6mSZDTl}e0weEwY=vN2YZ|E{?GaLsk;O|N1!slTa?N~wpgV4^+2d1Y5E5J z^q**J!Ds%jZ~w3RwV@h*wDDc&xCZ+k< zV^(oCeX{0s!+iTP&9~oAzI{8Sy(daLMYc)N?dpgND*N{QJoqB`k;8p~_ zmuKx4_|hYNdsw>U+vlS(!@a&N@)rc@c^ZdE&xyQTgzuf_kV+lwUWc^Y!S8bfJ(RBR zQlzz%OCJgxJwv0w5AkBe91#O%KZx5uXw^D z0S+46=LG3Rfo&C}1~|=d?*DInJLVheIj59SA1Z4znH7QQ2Kvo0eB>nMb&;3wo)}v+ z@ys_xzE(KlL)1k9^=_Tm<5iKrDq>Eu#^HX}!8SSE?>P8Yhq+H5!%v(jza;Y8dNzu@ zo@d~RI^nnmk$)|mP9yE)Eh66{;*Nv+9nwP%w#*?t<=_v8Y8&<6nhdmw8+&5d@gmQ7 zP~?k*<0?rKWcY<-jEKrby#M~WD19xmy`uD+$oHG7UqHrvB;zrWZ{-;epsEXl(b+sl zGJHZZ<_C*Nk3FLForpgUFLjE%?SHk5v*kxbUet4=$hYx~$3=dhFl>W}R)FbenV7sv zQQf~jy>aW z*E!gW4)=!+{`!%13fu!+Znt4_=N&n!*R7l2Tum^ z9-)t}1L3zYcFW)r0c%*mf9A;;s?QDJQG5{m2b%hgJ=dac@(g%@2ZZBRi~MCO+xcQL zZ1tds<*y$_=~t2cCQ9=i{7~1j9eK9A4GS*3Cu&*~Pu~uoBV_C#CxptrUQ9;!_p*qo z)*^>=zk^jcq-qCWW^zJ?4?zwdWITcTMtTGa2YR%M($6CMRg~sAct=+~ zPCQ#iAr|$7{yTU&vQ;h&M9X`g)R-eC!^hn(!a!e%(zhb}PLvLc{Kx<0GFFg1;CEmT zxTA96FHck1!XBk!GDbto$R4o7k0NUmrD6yF&B7l42^pwZMLn?|2R*8gtZ*#q+bg8U zJz_EndpYT`UzC2r8mrdMez(vA1zJS)6fz)gscwZy8ZgOCKVF)@)%0G<`-*WI$2i(uI4hh&6hqTSX zU(=!u_oMlr%pCbAay{_$u!jX{gTNmTxfDEy@$~;G|KsQK zCCPWO>oef@XiaxHv|rBqe8Dl8K2?i5|4W|G>4vuI4{kK@giqY;F^BrGn{9Mp`(crk z^0u2jDxq+HmJ(leGrt5^@}4vC6*s%jrM%>3D_j#$@UFxypvme6H+xoY*Gz=;;+ODl zpL6y&r#p9!_>T2gxo7J6d}!+AkWW9J4>(JH7Hg^lo+p!H-T6~4f5$Oabu;!ompVBH zw;}(GwbVbyk8#Zxemm)$jAG7j#mm^GT)HnfbVT_@!2GBL&=wz0wZ!HKSQhz1@H{55 z_r=6tBs7q?W{DjZ`#mqQm5$krRZ0?gt0W1O$D~WNehqslmrHNC(07gB>B5f5;9V}Z z#i4xQVpWp#u8S>mj(p$6K5$m+H4%0l%qkJC_L^Jn=n z>OYh&-MTtug`4f=qaJZ%FY4q~ZcIIAAw17@@-jDj$wj*`4RUY4%=XHKMmc2Y&+TyG zxw9HvtVBHdZ5R6CSqRrit9iYPeXQjgW$?Jvsu}@?P{Lf`vy5(Piy*&KkR(6qmJHI?VxWEQI zdb-XT58 zKX$QiE%<03;DZT1D3Fiv4%A-=+H1l8v-G)~$BW@`{}4`w!`&-hjc~Q= zqMe9w(Zc8gckdV6>=AdUKH>tk{1mkQz5H6FRW6SL7~1B0vK?AJL)z|Sv}E<<>}^DPc{|GwP&9yi-Z^|8b)fq##i>Z2cfj5H2D z{|OO;-|JRmCL&~FnMjlnQ6)-UmE=00uQp)k+9vxK9}O)G@6|5*Ieu~CoNQy{A4VF z(=vDh#vUIFZ&R$1?smj)7rYxBY!9XTshGCPfeEXYZZy3J--YLQ3H`S^*zW>r(S9-Y zX$M>2FrFXBI)HZwGk%fT3l8aBnH_NSywA<wcvkN8G{>`*F88nTY=i9XjAxI!djb8;tsIPJ>*Iza{8ikmLEDToY&)Y< zW*C@#B(uYgo|UM-QuZ7-+anEyCqL*+`(9=bk?!xh(!Q42N;&OInSCHjc<7^m?tVTH zGe7*XA;DAYV2^9||3U1%nhb?1`TtrF>a>=TUFSy zdD$T$`gN){dcDC$40~Vb4*_ig+R0a9>SGS}N1*(U!2%D6!Y!M%`cdm*?@4iWE;iTc z-soZrou6p+1AAM&*eVcL2|Yh@V0|iSvx9vnbO6+?VWef0^@~*2NNb;%it1VtDC=My zev;}i>cWR&+ES<$(4`M+MiR|J|Cb!>AU*%Rn7Y=%?hZU3s4LgJDYN~Ko_l0gEM=p{ zd>{>h>;K%Dwnb(>=U=eyx!R`Vf&EQK0$p* zVOzwLmMJJZPe(jk?DQOpXX{+j=< zG|KE(N6#N*c8`>en((PKq)A4Hk+z+>Dd@DxmG+v<4!P2{$!x7GJtwmoS;9llg>)Lo zmP4oIg6B;K+bFyT%N9F&!OK z?XxMFJ@*kVHY9L!QFmc5|R-56f8N|0_+-B09&h}uo z8$8Ff;tW1|boWOjR3OhPiS33Le_XhUpuco19aspESFu}_Y2FB!z2 z>oX4FhSVPK4`O@MmN@YI6Y1Oe2ZPva8LkHg@wYOd?ROd7?i<89GrBDr#Hx>rfB886 z%yB6Jt5UvU!y3(o8_0(D@LGxO7vifV42%*Vme@{lGGf{s?#Cp4&;fzVBniwZ- zl+EeWdaCC)C(Z}NBZaqwaR;633&#y5G?S$C_c|p)ozhQEWGj&VKH*vMsQXVuho;Uw zku8)c{JEqSpU66#6n@90{xO1mC{y?ex9S_g*2PiSAEzD~!KxGr|Ej1RBiNw?3cs7E z{yu^=B~f^_sva1@b|q7IO*i$I5$wzE6s}EC+eWZ0Jt(}mr~2avwzL<8_w`a+N3fqf z6n?F@x_<nIAZ?4#}*!5&Yg@b9VWHzU~Lz7%duQ}>KuANQm1(_Zzf5$xIi6fQYh zZ5hE99z)^Jk5NA#!S<$8xNd;DdjxysSPI`iQ2lfSTb4oL)(o|I1oI7|@cV<+k4CUB zj-&9#OtonQ`{sBGZ~BYcFoJ!40)^LRsc(;98;4NXKSZq`!4?do@XlfCwh`>*?6fCG zu=&H&Dn_t|;c0V6u>Hen%aqD{MKNuDJ}0PmCu8I}ZAUWSA$ks~{ByAn!kwb0UF8or zC|u+4{HF4HExgy^`BmkI9l41APD=S%<)zMlBK(F+c~iygg!o%!Wj**Zh4;#ywcu;v z2M9IEw!$PJKk>?OOQRcy*b|Ka8jN<%*{iG8GEn zoshafJQ2XN$yXR_@_x*k>v-wNh`Xs zRo$dFx&^uls`K*Lo`q}*mIV=3afFhNQL0$pe~Dl5zbY>Ney%)8$4_t7+qzX=|4(wP z(*IA#9bL+0%(}|?DRkOd-7jEHozft%EkY8a-xg59)DCd?sf~XtsM}PG@Re1`{9Uov zMwRao`yf2W(W^$~m5yT(-sb4FLFFGiDE@$>*E*FilyVXNT1r`?^104pjxQyyUQerh zg^Ngau3k^7{CzFl>grXk@_91FSINCPlKAs734O$^97^JA-4wqtPWe2EKNLstyW^6Y zlejOA;y1@9eVD{Qil^{O#q&ZEe_NrjU-4{8;_DL%5MGstbHAGty#PN-bT3chUnKSg z=u33ZPvY~FzC;uFCRzGEnf;I~wI>Ig0QmvzCJH|a>XXAU6*y|%2;@zDa5y?A3cur2 zD~9tOE(&jw)w1FIQ8$I}jZ^O(&O72L{AIjaI-I|+P`EBZT`-(KnMmRLlGM4w`QaoA zf1|2@Wb?hr6n?LpS~8q(?M~q*QqNEQPxqtnLtgdwY(Bp~g@5d?{*ujiA5Gym zj!}Qi=9|(fymElLKbzlsEQNnPR{bWMe>srCZ)d1qW%D-%QF!BEbze5GI*!8kWU70z zd3z>>TaH&-viW;|q44u3sJpZI#w-dyGDQ76n=cwl;f|r|r`f!87!F>%H>`{!=F@B( zJ7=GakkALTjF9$^FqMIyAA_0n0TG9>(RG&zYKMqTIrR$>%MkI1{z6=cXURvo$0y<} z@#INVb+zwPdg849EI2Uzdwd!1iB*rsFae{wjj?b~DJzf?p3gMak>ftW*&f=?XyKmE z1nhbKl}?BxV}iLuNCLJ?zyue3eax70F8eDc$EN4yCIN?qhG7|ndoip0m7cE=k{bo~ zs*nV%G5Gv(_?y8;UBt%e&nqm8v8-NG+3A7rBN-dnYX&J@oEdQ>JI|W4-UrZ zx9_>qBCt|H#reKUVOC)1rR7bU)c0Az$Q*PVFv^29q{)A$qlDuh7cmS){vH$3a58VN z;Qmp-qVQQ{COu!+FUe3Qv1~n`N1fq$g|o~0(Rum4FL6vf+;Epqa?P-s9S6x{f_5ak z4wBCZey4X7U`2dX96$d-SdDOn)LlD@uJ6mFvUbF^3(9-gdlGR@pS|KpLijz0j{h0m z|EIcUvW-}?+9)ckF+y~x8=YA6y&fw^P}qqnSPz_LarQuPwG*cFulOs9`E@A&x-f_T zAhBjK{S}F?cBH%~Vb20PLkpxNL@%Z1o|bwb_=4YTAaQG@{`H&hXTT?6O>XPh|WCtX)#w zSTCeKgpFCjeNe!H2o_UySx24k!CM)#P!|^QzF4Yzn!7h~wu$2i2H8U^`t3Wf*scdn*jb0~Wy{+k1{lr~A7>*QrlWx12rI@O&{zTJtnjG*j6JdOUk`Dv*O1a_s; z&iM^1fRzc#YJpb@Atvbo-<2jm#d$_5O!#*hr_u`PYca>$R45X8b#Q}`%B?q>%GlIi zSR1-k#u1ffE`QH?OUUH(o{H>+&&iZe4c0X}Yk~z69DU&_?{fYa$FgTYSBzyRD3`Je zP9j~jbqaPR{``ybtjun5ufkd$m&;{d%T+{d=c!ou*w5u=7w_amxkpg2UcEw)*SYw2 z0&xxssh_&oBcl9~i`R(6d0A98U23VzXR){OQi9SVy{fXSnGag z+8h_#<#d1U#O9H_&Bfn#$xSZ4*QNaG;>EJESmsa2GFDffla)r9zbcyyiFzfUuUx|} zr+gqhNx7O`s^zH!$AI)Kt#Y!Pq=im)r~HS+ALlB*Z{n$YF|EdcPvVOOig{Q_ZIH0C zF4s#ObpSC31f|%?i^Z|n6cESbCACrqw8dep^%9(z8|xmsB;{*~|0pRwi7#==E1dih zr?T0}*E)j@hIG0_xshF?>!;*33Kb6Qf6yB~z>fU>vICWHv9u_FhkuWon02?nX44X& z_I%gx?y;U?EVn~X9q;-*ZkmD@u<}a+&v(V$)0B6CW3kQp`JOn(N@rQquu`~9aHErb zOMqw8bV<}+QE*|oe*wq*3UTE7`pAQV_0i8y#BnG(6175DkifP%)RF|YQ>vsd56jBj z1h&w99>VkD5{eU8b=+nGK1Hvq$?tW!`+XFGpzehIMRk|N9u)V$10bFA@Rq|`2wuy3 z`x4oETxm;0A@*OH1WPAYC9wu^x#Qs^Rv{0rOk%&tHz8aer!G%owQ(f`)FqyY)!U?` z2a|Y35=I=Fd8mAP&2n#cvNb~T%TD&Zn6S->gJ>8kP@2`8`|>vuO2Bz5 zxo>G-to5mTQ~9Cfk07TprSG???B^8q>r_6cN1F?#OH~*2<@fhhtNZfT`l?NR`R=~z zkA3;?ebv%5UY@4br17dWv%kZcICdUm=Xo%dxkdS%W6&sn$@xl-K765o84q6~$*;{~q{pY49pZ*|eb&;Mi{?!n`R$d7ViZ=cwA>3-uCN;n59DE&Nz%A;?~CT#UgQ5ipQ45<6Wk>gK;?M z^#VuK1}Wvkc(z+Qvo)S=bt-Sh^A;yP{EM^O`Z!kRihC-KKj^xIu>-ENs^YNAekyho z-A7}&uil-2-Q%rs>IZTBt2nhij+e(P56AO0@yh0SzB^voAI}#lYK_8IDWU2So{v(> z$4<(}^IAUe9r<`f%f}%tABaIdKGgE@w3ZLVARl*Y`RJg0)Nw?umr_26$A00N-^a5p zPGv_t|H9b~@jpAet&3v|U2$vT_)^NpudcHmiDR!)K8oE({aSuFn>{1#LP`bo?lHq`bB`<5|(yj3%V;0b?1+FS8BWS zH@d5zcIV%9S3A4&$5PbV6#jCG(vZS`NKwmr@WUylHRbOAJIq64>-;Ma)j&3`h>_^8E$fkIV0i7QR@=~YSPg%v` ztWcJG5kFO$!pFpMj!OqQ{}DY;c>fw^OD#`$xe-q7MCorKnGxdqD%pGx z_nbPwJM5c`gY|gJhAVits}|)Iu$orC@8R(kq2hp^RCgW+ z=W(9$70p6Ta~zz*Nx+3T?3xrztnLf~k)I)Xbl~P~o`RQaKc|&3eADts_XDtN8M`() z_~H_0 zH_M&aj?RLPtP@YyOyUsEubo6smDm2 zWRw2-JGMRXK41XQ(!5N?3d0R!19bg;Iy$M+!95!t{6Qi4B?tdZ=uzX~&x$>29ekJA z;}r*9Xu2%$2;`FvZ{eA@cn`GQ?|65-aO~r#YJsG*{K*%ockyey!C0-nEadSIhExKt zH&4{sXbS8w-&9-ld|1{Oj2Ug)iJy;T`=G`?-XCu<+#_I{`yoMjRb(54ew#(So=4F? zQnXJ{YDM;d*bmET8|jb@+R0z<=-nz}8ysszKk)ttE+*zmLD?a)O+vpdBGx)6`d5mc zBPuV5tP*F1MNCE@06&oN|9<-Wk^lX?Ki(u;NO~?4@E#qOcl*_ebkqsaZ4~{7puiwY z#eT3tZ6N=5^~Spnm6ZRVcz*=TiTSXg)QebO?)MT_v;~U(jiTp?3JkJb><25nV9x&` zq<@GHSmt1l2;FFrNWn`74MM*byxJyEbh(J=$3*3G5w8>V+l}*uA{IMfyT9Gddp+#H z0`O({$_F4=O%gT>N}Grm=KJj>-6?u0Nmwl^c;oIhvEP>>`;sIW_Wud#|HKC@#>+JH z^pk>ulwTG4?GjmwK+*H*>4!vRCzX7^4bBVK1lumAAsO860lZKknj$n z->0+`P0{y~fR&=sOeNp%BawZiC$E?PD)j%WFx_?FL?Z0eASif=?Q5YQtT0!k=*LAw zKPxIIih8jhD&)5T``?k`7vWwo7c3U~Blsu@ct%iguL;tBkJ6{;1tg$CR2oFKR_yn- z$lf;F9~bGcPTv2Jh?)!D(}L2Z<^L_pKSj@>$L|xBH%0cO*zXOIz40GSUtg2x?-NmT zkkC3ofrYS~_l}4oR1`gr(qAGfP-uQ~d_3h&X5Gf#nv9kf+rRU{Io%d)^hA=g z6uwN1e>Z_05)ZgT@hw<mgimmv&PJx` zoDRW)CoRfmd-^qCri}0L3%H6xevn?sr0+em6=d{$ z1urkoe3m1)T%b-&!&0){n3kR8MnTTJ0ijRvCWlrIa)0?eKIlZ;!$M3WE>#}P)3G2O zj7!GcN;;2^#C&D+(WdwW?)FM^IUg`15J_W^?zoJR-70Os_*BM#WC2Zm3{l#cMmbIz z%ZJH1{1jv)m_`p&ssil6NI!D^PZ~G|9?|vmNLTT`lY_A|K2tF&(cVDAO$jT73r!gG z9SQzuc?Qot&J>@3cd@V++{fEBE|d4c0ob4}Dv?eQ03D^KrF_*646t3qAj$St5 z`Zuh~^+6CDAc(FL6bxmz3rW}u7WyElnH_r5nP#k8pF(Ch4Mx7L4+2YZ(N)0J8Jxdi zz9Vnsd_2bUv-=?MP&fzsAW72cyuWOk6Jbo>E9E%M*>F)?ata7T=S7q3=0PQaTKKREgzyw-XAE^LN4B^>(v$%$@xj;lAF z|8$*!Yi?W;wk-C!dIpuIeDxiyHVgdZp?Fh6L7)gFw~tT5(rLYb)33TA^>+ra-4B#ZbLX%1gWp{x=R4 zcNGTb!2~q<3vgE)>45UMDh?Y3kMp?q>4+?Lb%S{s!24Vk zhsn&1aoEAp3D592Y+t>Aw-*95$iUp_<~VruCEWcO$1E`p+ig(wH&Qi3Bz@v>Uk2To zpmbbbEx-RUjvI zZ1ntQgLhzj^!!c*ui^CQ`6Y+B{fy}8t^;r7S<%yN04?!M%@rSUCdWm`i;@k#k`Vb7Di8( z+Hv8n(bLTYZ|ZH))13_7^x4tVoekc)InmRt2Crgn^mH4*TUpZX{{!7>u$~6|)z5O! z9~=O$a8bMeD%6J~co*vRGy_m7+QruU+Wn`3e*`a`{NETwLR#s7bHQzVAbQ&5)7Gqv zo^~a8Z4bwmHjV-?$K&mO>_#7{=WC&M+zNc%ns)zLR_!<^)Q(dylx=#d-H$zlBjweG z+VLpxX0L1acUYzSeJI`O;7#7x?!U+?-Mmn`W#E- z`35aP(g*LtvrME%;b8rp64J*P0r%pORMc&Heu(*bEsZNRA;cLCPHqGawTm1`MzyI*bhFG0Bl^$oP&5@#@9wcw?^)$YeSK!}HOm;nam6>rwDY~W$#V9NIa z;OXDD`%mcd{B+~_6ihQK-f#C`ZN{~H!zPH!2EGUQF=qTyO+C#QOa^`c_yRMoJ%2e! zA)hfDys3?md0xn<25&ofn2m(;tI4}wOO!bE;Ix24^U0v?G>(u%BoCrn!BIYF$7`o1 z4uX^?IS&5-3#;2VhVqmF+zWg)XhHdby188EWdOlQ1Z@ZtCz`E8AaZ-p&b+7>3=5O2m0}&2#(RRJ~S_W+DzIH#3 zREIFl&U!tkv}(X90*6`o60EWX%8k<64erGK)@gMBYXlZ4tyG+vYX#?Kt9)G?N{iZ0 zF1Vvx+x^EPY|huk(1`FE!1I9j?}DFi;HAK)0Uy)_zr?`T051TJnRuA|D}Z|uRS&!v zc#au2>fbE}rxl!a;Dq^e&A#M0(Z2Dligo4su6k%3(!}t8;531QrJ*ogsJ4-e$-oZ) zKeBJSNs~ckQv^=&5AA*`Q?tFuRu#Z1fKfPz8UCB0W>qfVP`T)1vfbe2|J3fE zYnEf!gzQG1gVJzd4WOj$$a*r>$WJ=(3gBUO)7qEb50Z>raB9Fg&YTwN^)y4q4B+el z{EZnmbSVOd>`(^I#NXQe3oSSTC1vcj2+^UNGw-!lUG)`QamPNY1wf|L4(eK}GYs8~833C^<^8wKm0p^x~0 z3(4t)-~~Ji+)>UBTOXq3ADlHQ9Y^@PK;0?^UI%;#O8IUT+JpG&Eb zjCyd&!8zH?L4K&`Bzzz68sOPo@RF|%~ zBL8OKUc}7+o(Fuq8Q1Jd67(`D17|ikRyvT3b--5wzsxK{x5IfPgvz85oPFR-F>?ZC zGC@m9<8^@N?cL!&+ln_<=TY19_JD5(ui1*X13beglZ_^V>jM|24%L~nbyEP~H9t*3Da?f7ra{ zA0hoSfm8nM@QJ`le+;cc@^eGa=Nr#k;Z$~IM*7d2pAVGX(;+#v;FTa9bYr1(jI#A2 zstI@@@UXh5)suf}Ldbp{;8fYjAYDAY(4K(5gK*H+0bO1W=`tF;k$tRnp>(DJ&j3E$ zEC=l-FjguCo(nvZ->U{^IymQc^t=~%2k@LO&);gu9}PUCZ-;+$7o2LE7je^o=XS-lGNDnq z-tJ1knGTMX4kV)*cnR=Gey<*!MsTKpe?)yX`Moyqci9sccRp56!75sT8AjDNO+V^!XxsA2`a<9sXO)oIsxS zp`w=O^u9xxf|EC(~XvX#_9&!<7ygo&9uj}fM@*09?t{be1bh*0K9aFJzfrcxc4e%Mj!}RUaj+($JjKHCEI>5=g*t#4E_w>iuVX8eo z68N@D?C~kU3#QrQMZmKzx5q0f{VVM8I^gA3+T+c@M_+A^cK~mjVUK&zSyx?SkBAyLOaoJRepsP3>p~@B%y^sU4MpQwC0?c2on-8gOQs z^AgB2Eh-`2i%&CnZQz|@=4p8j&9{BvG~8?7)>6~4h7LR|PhHyDXmIvL;n0<{wODWb zi&+=ghE|km`b_$kg0n3OXB{}cr#t-9%yP7TSP0Gk!6{uIy-sw1H+nV%37jNBUg zI*|o@3h=Nzb*U4R!I>U~Qv}ZF#>i#45}bw)JNyog0uP+;3e@%XP+i{+UhU2=R|Y;*79+! zmRT?2Yrv@oCz6k70%s36(fV2+c(bu5LH;jjUt?Z{=D||207iI)84uWhzHWcw<$!kp zytx*c^+ z>Axbcmo0k`f;`}7z#CYyoVl?&N19h?K;oP}_(y#(6Am{41o2wv(}9sVs=yr)9-fn*ke zTLbPtt+@I!hSt8Sz>~j5zhafwwD3C70Isqpa$efN$p9x>UOX7A<$)JVUUI$ zdATZNpM3B}?TwxnDz{2-s}B9{Kg}!?^`r>m2(KgjoI|!gzZrN9a64Z@W#9v+0h}|< zX#~!#8~b-u-_lP&`GY4}l!5R)6go{i2FkqP=7HOM?jip;vrLRp?-plkh9KPw!EsEo z*S!LG3h+p}*MXA-PS_fJK=<5`&0D~m0p6(=x{G+#CZIg&u3+#od-5Uw-;dB;&}uo^ zA`6@~7a#K9Xyydk0uAU5TM&0DxT(`(9+fbI3nSfU&!bkHw<}6ox*aqO#ZrZt(-L$xRuG z`uFSjaiE8jTeKTkB3ao`=7o#EUDa3?k#@{h6N?h0|e5Y++hHuOJ5 z2nXv<4#t25y6+%PDkdwb=zH?a9KwxpI{DDi;N*g{)yxU_p^dsM@_94B+ve@G+_RiWQR&{ z^M-Z$->}kmQ@9S>!94(OEIQz}e3qLX8#nbt>_LN@Z>0lm?3nD33vLUzmssU(Y-pTD zc`F1rWkjd{SBv&9d>N8U?WPLc=D*pun{B}Bfp4_Z@nOg^wVPIOr=HsBUuDI;C!FgU ziT-U&Z0#lo-07#q)@};G9XT$xcC!-Psb|O5ZtB6U0rwWGyme_e2f%gY#U|H#66WXN z#?o#kg1ZjfA}bxbw3{Mu**VemB_CT2?qqQ3=AEFgHrk_DLUl{`9Sz_$oEux4=>WH2 zQuOqxzNVjy{xwE!9=M*#(c28=Yc{x3!M)!qU-R{RY551Q>AX&VFLS>Z$bXy|%0GC@ z)J}h2v%HDM`>G2Fq?eHw% zMUnCkd}l;WU8L5P?JXY6E8x=#NhE1AW*Oe&{J z@UmXD?&rL~>wtTKV_7ehrsn7M!5qoh4bCWV;>?`!A>Zl)o*5yH)bX%Elr%$=>H%C(}Iu;tsc=LmOkc42WQWKgGZd-p}l=dBM0~a;Mi6U$$%cT z9pFXObl{F-5Bf(V+_fFk?xz>grQlQzJ{W$EU(a* z4Lod)VeI*NfmZ-;8XGx{I&j*+IRX5jO|L})_)2Ls181ilv_0F=Vc?g57JNRiZaZ0* z;|1i!X3$8;IoHfXx!@iBGl)f;9B>N3$vcvBI&ny!8Q@fnKj=?1bN;TUlYzKW;N`$A z*Rd!iqr6B~Ex75Y9}MrKCWT}*8F<)zMS(VEDtj;KG6CbA+=Jm~qV)WYCW*vJ2dA(r zM{7g+Svun6f>Q;~IS2>ssd0pHB!~3Q2gf(zpg+OP(X6P~?=s-6z#k05jeE4Z*q{#F zX%i3nQ_S4FkPVs*{1-DGumR22P4;xaIn?GIJmOt!T6Q3xl@5G6@UyIBjnUJj{7nR} zHG-Uc;Jzqws4i51mp=I*u4u!TF8#jnT1a=&Z5y~9=N$~cn<}t2G(5D1v=2P*1@KW8 zGR4#oPsL_%#*~Bp{#Lvcokw{c30~HP2QB+G(rXIv(ZJ6}_=r4=4cV+1ycrSXQ~@uF zBFBp)>cR6)jqEd8!5Ib4(Po`Y?;k2C;E56NOyE<2hm8%5cBhrUf!oc^^9}imIepXG zPZ@C1&tt|7UqtfP8Mu{vFYpH7D=&#`gEnxAu0Cive3irvlzT7 z1qUtHbG(pK1w0qH-8hKS+78ZiaQl@DRh9#=u@=v2Uor2p#MrMuIb&qV(_MbXXjI@4BRg7 z+kofdc{{uX_(6-hq&`0E0I%^j>+vC# zwP&)9$5Pfg;HKXmy{z-W%LmV{tji4CDsNOi>wr(i^LBUx@QJ|f%DUB%Z&%jJdAfd< z=NLP6AFTO*@FvejIu>OuTn3)8=St~J19!$9_IWNgaJxKJ0iS~Bt#B&uZNPJZTb@np z&~+v~_JNmmr*(Og9Qk}5k95|a@}32r=Prx|t@3^W(mPW>3rA^A1$R`jecopqxK-Zh z`IW#k@w^pII&TG@3Orig_kib^W1n}&1v6C#t8@yg-nWp*WIs>=MQv>jPJa31$0-p-pF3-w8^z>8B>6`MLY2dTXxJ{m?fZG^D zo{Pcrl-uXI%E0aNv<09O5i+p+we26*ErnPnAB_Ka0(-EC?C1tl!Fsi2aNS-FYp<_Yof>~ z1E&F;Vc-XKq0J0@_2RQ`8rByh$RJK5IF%1YF1rKZOkQcvq5OC*L)m~c0^y)8`j&{c z4l|PQr@HJ#Xm#XrD69_z$=^={Z_U$@dE`$^!E1ZvpnsucN-uDB?Pe)VW-YjmZx8yP z6HVN}oOG>z9*)x94c^NA2mO~@@uq~%%{eYdeQ!VL-)v6X@M~h;H-(lsRn0z6iz)jEm1hF;P|3&R4l-G-j1wu zHaOW)I8(sMi^7==PJR?l6*#3)INQOgj>6do&bBBVWjg9i6iya69Z@)w!AW^1vJH#C z$%??CHnEKj@lWo>RtH=7L z9dUBO*#^$2BRKjC6_lTRaCU<;*vvtG0{0%30dECv*B7iap6_OU{w&=;lKh4!cxx0~ zxk}g1PJU(-d}0(l-@xtiR|dQR`L|1dT@<__3f>w8SFVnner5#R3;Rzr@JRKf0GxeM z>PZDSjt2XBQVToakhe!2~MQ?)&fp$6giG-uwD~IP6jx| zQRGYnXC*jcW56!`eE~RiQ8*RgG)3T$ud4$mtB3tNw9UX9BgjaH3?DeH;FKX8>|Zo} z1v+u94P?B4(yzsM@m>3Tk*r*B3c!gbs{p*_D6%TRIS_-at>8_4FS1@O;1q!qO)ohg ztJZi1@JzyCgD<)1`M}u!HQM9S$Nt2f0&Zg?-i5N_ zcKO>0CE!*hAF{o>x*B-(e*1CYcHp(Z?feeqZ6E0a4uykxH`aD2PQG5psG z4B*@Fyllo1CM*XSrQa1Jxzm8H0hVlj?o5~p-w7`^@Kek<>I{t<39kZPAL03J5pXY_ zZ!vIeeTDL^`#A071*PFAz~}oeeGPQD!O$TccslSwW*Im)LR($*d=Btz;EEYHo$Htm zyb1VOW?azMWa#-4O25_qoN6`j19;x5Z0Pyz!1qMJ_ZaE-FsE;NXUTDcu3v%~H_l~w z5tj~pJLHcu+9?U^o0*P9RX02qpo8{|u zCnumSrIQ0*$#2%}lkn-l_e8);fFFo}R|9waZZCg3@RSJn9^mN_aK}xkzcx6PTRQL@ z;IEqP5GXg=YctA?@|p+k$o5X#`&kQsR{|esmW6skb6R@79Qc|D&({F2i-0!*uaAJY z0dJ0gtA+5D5%4VF9l)*h_fr0W%N>z@aUnSA;81?8d~t<=+oe$pJUc=fRA$ZKOgq?V zeU>t`M5na_$3M~j!L{;V)DF^tA2`$*@osI(%S7-pJMC?g4}28xA>an{Z5kg_TIJwO z0cW$B6R2ye^|npe!d@ z`n~Ct=2mc0|LF8TVdezVd>}l{ec)Dsn`h>Re3@nkj`_Twf?~@9^$rbHolmnju+)f6Sdo4J7#`&!K(Z@pNPTUr7i^lu>bIdvg z>d4G+u5v5-OmHpx=Pq(bf?II9&;O;B+?PXgsZLA>H#^rCepVkopPG*scnR$52CyR^Wt*=cnR&6&<4m9R9aD71 z$mnm0yA9ka;103U(-YFu3vMg8`DgjU-p(XWP zwmKXAJGi4Q(xz7@NM1HLDd+n9?N(_wgltaSY2fagTSqE+#xMD_|KLu!*k^rK{IX!uTAM2acOAH&Lysfs-diCqwWT_6r%msEOUC44!(QwQH#<3fn(V$R35sFD~Ls9 zmJQBNjGB->i+fi=~6x>f}<3~Ca(zGZ8t>rvn#>bUFh?}eIIF;z`_C` zFFy6)7T*%tZ?%F`cB_qlc{@;Ydb{+@MSpdhO`mb4USBBBqrs~L&+>lKemp3Ybj$~L z$}tEUtz^1-)7>Lf?IGG`bjIU zX)Z%L)Pn2imIQ^UFW;Fb-FjavzB+u-Qjbf~x;+>&CS_1%fH^}0*ER`6QED@C|# zy%A_36Vb#=S%CeCIX*wO%a7z;7~+irZzXuUta$Yy-gJ^T*Jr&}@pOn+23{+8(d5;F zS3NJfyxri9Dv2)7aX0!i@SeBIhoK*}yG-!bE%5o1Ey`N(BOj)|dJ4EzcVoV0mZ|li z`aHM@cn$D0Gj3YDtu*lNX53h_CSB?bJl#qcnl>7`PGOZvY7^Ia}*g?vcU{u--mK_yDr8P)3C9NsjN-LPM zNV|(^t%{18R#a5jK}t$m(~4R|rKFWsTC>R{ljQuK?>l!g_s-l&_S3JQhwO9ieZTJe zywCfbd+xb^<__n@=OS^lZ8!E>?1iqEiDm#zBbp=lyx6DpxyVI&K~k?VG_fBRE=T)5 za|Y~7l~aLc63tTOtU}XtV^034kDOFX94**euveO6HPyEhdpq`};^;-Q9*x)RL$7c4 zS)@3cD4L~WO`;h_Bkj7FHf1?&8V{X(-n z)BdLOck$JMwybMTecY@y#u)Ln(Xd;7hd%RMjgw04 zr*q10*66vCD<0|g7F{K}T6C7{(f!)&FVoNNS(NJgQU}_aNY42f z@yQfh>bDVleF3|aHGsWsUOvVL#5iy^+f{ ze8^Z8LlZ%>pIJi=rOigMmEF7ad4d~VF&7{@(B-$SLw|>f-u`I%(Y$0XC)2LaNLJG0 zqaR&xll{0LWd#j;p?yZ`v>r_tK62|MIg4V8V6!`K6?+`JcHf-sJAcHU!0uhb?&2gU zu!P-K+#RFY@ay{k<34`d`hdSgEOO zqYa$L>_Q`C`}-EOwVUVE7CE@&o+s`3af`P2CXVl;bLu`jzx`IfUbMmgaG${D{JECyB+2b_}iEcrJE7_BeL=yjYg;4hvZqH0-&3TaGCb zOW5$gr#WYtHZIPNY2s@D?Z{MqU&;6y#XgR`PIk`RJ}~86teBKratm{W?dH|vHtp*C zNw!?k)}Zas=9j&$D%t?r!1nX%3_HIo9hMln(5_!Gulnrjez!G-ezYYYp0_{mlWQPG zKa@O;qisdI7oQjNp#N%Kddw;gr|pH>qyl>f+xMEc&y0OP&6efH?nkSAWWL~ciX@&k zG;TC@<%xYg_KhxkyX3SFdr|$ox=uP_rd>1dWWF^Uk7&ox22Pt-qjvef(3;cIA9K7o zgFe7^i+(fpyx;1#7HtpO2X@HUIzP3;qF7>RMqAx9ufAv(!%@~g5Ju}idtNQq|HbbB z+WK?m)iHK{56=3PoKB!^Ik#|5OK#=-1N+a==GEPF4N82~pe;JDu&+k!rPx1d7uOEf zxI$=Mfx^Bb*ge=Ewexki)z>iEzONScHHm!?`)8c_b#(5N9S@|A<+pJ@d|_cE9uAADB94)^99G>IQAg+Li<(%d*rgh zcGr6Lm&@(#(&xO`gV-nR+T$|qrme8A4(#>V-F7)N&0i&lJ!oscS=iSQ_Ep#| z@At_ZH%_v)M-pwvRfT<(-OlkA`@?o|-DUOVL+fcT>??rXi`{9Lum4zmb)hZ0y0EWa z>=k0Si_7#I8j`OqXe+NN>}w8tEq2@Q)4!kXbJFG&cQ9Ue%&VR3_8Zf0%ZS#GR=ajy z71`BSzkZsXqjjJi32obPr3Y=(_m)1c45Mj7W7qd(J~oNHZ^OLxHz?Ehx6aMfSaMe; z7wtFN`;j`@C`mCW<@hs>w&A|QzKVa!{2%*H+mqbPd@3_`Zq*hW zQgZJ_>-%M4Uw-U=E1_gHe#>GzTPfh*IDy5gtoue-j~EZA@+yt z?XpjoY~XqZ_K(|@wZd9f4cdWU753GLeHc5ZA9?w7$ny%Oxp@e!@8QC}BG~=d|7_=L zv(?uy+Tv(oUz6C&u(#Tc&1YMW-Q^qUU%#2RUfey_pV*}cnfx>;J6?-FgyFTM4mM-kg*e&-C(#L20?u2NfXrgE?;`3sj zvd8cu(Tt!eda|%a<^pqQR-ySapRIo6W@vf`6`kiE`pY)xR-x-(Mko0WqD!E&%Yp1S zVeHydjGqouT$!;rVeJP4Xva6(`;yp4u_v*AozIJP%p9MM=eOOMiX-%w*wS->N;EBK z3dOw&dpmY6yXBXaeH2u0pEk6k%aqrRW^Re{`mvWhy=~+5ING9T3ddf|NpC6kXSd6b z-T9C;=U%kYXYGAS`}(oRu$S<8G3Tc5Lj{fP?d*E{V~?=?Z_V3h+HBKe*VLa!89-Yz zIIrGxn##)bmFKPJvlD3Np0|%%KmPrkd=Aa4Pub-_|GkCm{Hq3S=^qOFYQ*lw{-WKr zk;kpqMnY&~FLA9vv#G;Q*|~?r*o$`X<#~0cU5v+N+ex%r(9Vr)+i|n_UVOh&xIPuw z2e3b4S8mSvpdYROReN9h{*OI?-LCz`9yYeOvwN^dvHRHmQa&&Cuk84zH1auL|rNvD>~EJLmaxKibG>VP8S)QS5&+$Dirn!`c2VacxA~ z_NKiru@7Khhy7@?FYf)wBc@^>#l8u9U5;ITQdI0k_tBpU*efu*v5#Y~v}^Z0v;9qc ztwKBTw|VQmP-6M2QC17~lDF*ZB4u@AFURh(E6ZUms}F7ISYcly*xlH_Z0G9)t1s;r z^w+=J`;vNjum`Z)^+&P$jO`2A1K53Re+b&e{%Yh!>K!ut+dj|MW{tHM?cm#mV;#mm zg59n^NLiEEli0sxmlt2QEYX(V&-Ih>c@^dJV%(X2dbhQo)}tLjyPsK09W(bKnz0XK z|EJlW@ik)g6-FEWhrKV!cNBXBd!ahUvB$9AW;cJh-&)6_9*!Rq^D1Q**FUUrRiZ8V zSK+u;VK2vS7nj7{g1u?detW(DV{gIEWr_TJ=UfNrLpxf)my|VveG+?_*_ZK*irABe z{Uc_(>0LTy52Ux>-)uLYdzCS`2K&bU%&P&jo%VK^o&l9|)}X8TuYH}x-hsUyd(iC1 z=oez&h`sFndF%ai{T_Sz+R}jd$1b-m7yGDwho1ePRioGk6Wn(&+tbGiAFZpOgKOOM zOKj!b%B(SdgH7t{5qol8-DS4xF*szH)sHuBY^%_<&v0xu>&QuFHZ7V~G<|5kkfX^w zK_QwjnlUt|i)P8tI{FW7%)MH&i!QrB8^Js(}Lea=Ag z+=P7#_S`X1Y;D*kZEO;27@PL71?%};W~^+q#yWtue)k1+Hrp-s|BTk?!xHN_x(;;5 znsv0f+$I%!@k5NyWrgh(*o*eauZxWDQlEP4rPzzj{`oAv1K2cdJDP3BXY&}so}g?y zyPIty*vGIRV%}cg|I!1JXa>N*?BX0nHwKUhGSzd*qddy~J!co!70xKEd{d>@C>06!0(o zzSFQf?ef3hyTGMrqoNSc% zKE9x;?9OkuvyPWTXe-?d_UEsr>$g&V5^eP-7t|%@^3%t~(~WBD=hyCE6Dzs{Y}&+G zVl96a+V*{D6FcpZS*@Eg+t6;@cftBSD``LDnvC?vZZs2UK5358IMzrV`mxVp|BGF2 zelO?#>0FPYi|)6u?DPC3zri26<=WVb&R4OZPPD7%=dx|wgsx@(1@%XB{F$*imTlt@ zI?n+M>eF`f)zNI;q|Uu)D=HV%^L9Rem-gw#HiB*#-92Vqx_#wafcm&Rho+m3VfSFy4lW#@54)>?UB<8gb`SO^&GBdU1Jn0R zr7m4)%c>Ww-`%IK=NWbF#omU!P%ehCuUlgKN$l&Fu$OYtanlm^YV3VW*c-497O=ai zUn}+z?5CJ>k?s>KWzP{!7>#zwg7rKit&#Wg>HAh6nmRP4W(CS(TDZ>Qrw2{#GMZsDZOdp9Xrjw#%KDj~FQJjX zT8pOgu)^bK6ZUfK1;;;Q`$FSSH}={B+e<$Bv9H2jXwF-XW)w{`8u`39hMLCcqQ}$r zLNU0pw=EGv9rkt0#1KFeSt5pzVP9#Ek$t|6&Mt99u*cc{WV1apejFovMEZC$gl-Pq zQDz-}WI84FpTJ)3T~ODU?Zy}X+^j449mf;wmN@kNF8zgC@llOt6B@hmM`CTj-iQ4^ zd|u3VCf2cZtZqzg=(-MHQ2#LN(#PjfQAt_dXqt{#P@-S-B?n&?#olk&Yt44*`*kET z?ry=}&h`)5%~QUXomYsj;wSj0X2JR_48G(^7_nDicVjP9Rz3DQ?7P{`VP3J86-4X( zY~ixP*!|e|q1?rKpPj9D6ng->*KB9*DBtXHvo4N3gxzwkOKz`s%8WjJT_}mB7tIl7 zAA0`NC-~y0e1PX6me5Fh*P$6l)5_rn$ zqG>@>jegM=n#^}$da$=IVIRWYiT$9Q?d90%X59q#ZtQ29?dd+JpXEuPDdiwNg60gf zCewfA2&Kv&ui{T8bUmx1o%5BrOqAfmd+qB(iR~^4? z+Cj8kCoI@sUpL)Tl0KV2>#wKJI`Z?InT|=Dm2alMoVcLwFz4X->z&tW&L3^}%rVa% z^K`m@i_dzrJFZ$#+vRB;TQgG8wW50qon`zyR(!6_$n^8$_2}M4cQo59_5odY<)Thv z96&dZ?tZgwrTDvcd&gaykI9H-44XjP{>25=A=*{D6o1dru=DngwR$bwtSX5yW@5LD z3CD2!*qpAZ#9xi(-)L6yc`>f~>zvnWmrG%~FNv!W-G@$IP;Z-cnYgxC;|ihOjCLop z)|XDMlo`SPOYA3_?RuH*i)BjvhR_Wc@T1os`(xNYX7+PRx*V~WJY7`u5cXZn_7k)A zO6(h!@V^TC4+_}b_-w&`IrhWM{>g94)0_2o6X(z&M)Y3JEGtC451nK7f2>|l;&D8g2^^i&u^H{YYZlZSd`|l&mQ!Rubv&Js>g|v2ujnMz*%;D& zu$EQ5*q^|Du6djxS29i8e${t(@O7+k9=Y9)Pe1$2=BEZqw$oPbbfSFL`&SLyPqO{! zxjEwn+f&DDx7Rm!blPn#$K*;9bIN%O)@RDBWjk(KESc#P+pJ-m=h=p)$kxZ`YyR)< z(6PdCi@CTnGQmnNy4m)OwF^1l4NvDn^52jBH0(b#`}XPm%+a1nDmFPs97p>wT1~Y4 zC+p@|caLeEv{UKti;8Yx-E!k|4Z2&=Ej2#7@wW!u1L*eU^J2R*S3AQPE2Yd3njSQk zdg#X)$9FQ-5M2+t4+oeREc&9qrF9o)bZ%^MbZgKxm~}D+oR}WSMUzC+iRRcG4I`?a zV9}I6S5)+iB{b3ob!Z0BEO-2o_*>APaQ=ezoo(s(TQc#BE{yIrbid&9V$Ssa*71{! zPRi~_x5rl(R8h{pAp74`Mu<-O(m2|Gq5UwQ(?09jSJQn-#){(Si;7;ye!G^jliSRg zc%x?C^^4p{YS5o>@q+p$pBMMjF&zo%a}8?i~5!)QK>CT>^ebJjBF(Ebgr_+D&7{H-?p$$Ix6=oe@# z*BH=bj@gxHd}!W9^J8;A%=Dcbw#ybO{`d=`Z@7Fx9m8jHx$UNUtVeSRnv2bvOzzIj zx|H%`XnW9hn6>mBpFRl;X2sau{3X!Oq5q6U&ofg-`Qo$e1;&~y7Svbl>eP^5r+V~9 zU70htIpI3z1*UPX1d@%o<|*UsAnGuNA^|uZ@a4+ zR-IO~U3>A0J0InFsJ-^0Ppu;s>3{MUKX*zWd$qN1kVu)!vcGb!cp*ADMUy(L;;+&% zt+)+Vq@85aWzOg10*mo(4bivrSMHovcZ>c=8@;@=!1OMT9(3L44;B5sCOvV;WeSNy zj}?0~quZ&lZVufLy357i`>$K-b*bU64x7C5$D>W_d{t>?o2sJY zs!IJ;rKeYw9$UqMPwLu?k5PPVkg}e&@sT+ZlJfYI?_V@*Z`AdElipNU@jHO78QnX~ z(X?AkIwLmcj`F;CI*Fp6L_bn8t-l}CR)1FZTvPOJ{BA0pRts#WU2Eh2cB{SteNEZ4 zdPU;7%trqmi6?zhFaA5wjqf?FKZB>O&DT4gUzF>4>_tDam!UsldHpE*!SZSS-3Qu% zHu@K>{!5))Py4u`-*tI?o#;O~t*)gm+WW6%`%tED9GCU)M$?MEZJ%lVd3)`pe7$JG zXuO{?G*8%T`q0$vKds+m)b7vMNN%^FX{nr6oA|8VlCN=O9`L~~`Vvjw8pVr?6sa<2E|AJLti+%$APsIN@Hu|;Mx=K7P=(~?F^hYnP zccbq{zvUQXKiE58FFps*G#_i!ai@HZBV>(X5`E1|_HXtL?cG=N+S7T3b$oKKpgjZA z`ulCQH}duR@71S=vm&`Z+<<=l`P2G6cx|(desxvp#Z{%5W|hN(zVEGLyVeV*)xY(& z&EL-XtaY62LtlOIwAw@T*XQdUa@XC6OY$_1zPDvszc#Pkn6G#0&k>|Ikn@SNCRo zb_I<%cU{`&w#M0y&yp()pYQ!OuP>YPxvf4+cO;)z8a`kAV0;GfseRM%`QQiRvk#vg zR~bHU{9t^R?8H3%TZYd|KNz2D@Y(il!{;dbPQz2s9N-$=u56O<{$6o>*>P`IE_`Mr&N_PrpVo{^lo=T zRjHIW#P*$RFTapgY~RiH+sRydZT|L->#Xq&p>O~Gw2Di77w7ApU&yIH`pO%o z^>=}2m*(poIdhvzF4UKIPV3))xAX6K#2QZ%`jQ_`>-V&@3vB#nj)Ia~{yNdG`q8vH zRpPg+Z`kU;AAS3c)B3xMwR3FzcUkol=)1e7_4jXRt8MhAxtYXMzAOH3GU7keMn8{# z)BI@_`u>}zRjb5rqvs;jVnE`*9sS%b%;5{@&A%5Q`X2O6>!0pU?ik`;;-Q1E1r))9Q0F=G>d_ z)A6UpA*V==slDiHer24G-IK4UF6lYK7pqDes!Go_ww6;7eU326_I+$G*TJ;Q^0#*e zvtyjZ=l&@3x9GI~`*7No`Fiv32oaGfGj<8q$_Kusf`IGo2Mc>Eyvc$JCljsKiELNEH}$GKi2db|4O%n?S>um9b&{{3}rcN_mX z`qJIGUigGDN7&6qpEF0OL%(Ujm?P|JqtBTmw4xt>(wHOI=yT@?8_`#6Hs%O6dh;AX zt|twn?|XJy|NRZktWQ7Bo4G`-&$s5#4h>GLuSnlff5{sooVQy0LS-5AmFJkxi{2(T z&h=J(6Z(=raNS(=Hhsr=iB;c;e#;BfY6sCDm7h!JMOJ-3`u<@ZT9`#cvhir`pdNbOrmy!jsL5x@wcO2HDc&DEU)iDU;Ec-b*|*+VH>^a zovE_#Zjt!6OzZD8(QL+Rr|FqY(U~=xfo}jvD!S&qklqUM=X$|2D1v z&WGmAKh8P7Zp}}(=*On@?>1@s=Ib2~S;w9s(f^(Kv5XA|+UUP%)z6`Ce|uWV{TC#TgeqTky_pOgEta;{hXcUozpKg>pdsnvfy`qqS@KVf-& z8~TPRL%(`?{U-F)Nkf0>^7;|p#Q_Ik%gpVMAR^bOl5)ddny zDqrvTO13Y{*ii8a;#rYYpOJlK_xy7xN6vkdM)Vttlj(hNZySBizPJv3(T>UVzPOi- zK4)L-6a7v}<35g!-n1`D{NoZ2_i=9Hvu%Clp?%|A-i@YgZ|b{iQYA$Ha(;fqXDynZ z(xj^3K8yBjzQ)&NGA^m7@#O&>7pWxN?ezv`n& zb*{wxu*pC7jP>Wf)0g-4XH=4C8$O*>cZhahQ~uIpQ!o>W`1QDX<{_iqt*|zLwgGMO z$1|!(?yopa+RXh>UzOXz+}yzhJjXF|@w}?^+xp$|GpkC^ta4voRm$B1hkVOdT0<`V z%l}`fD*XzxdHtTco|`_(=~_Rdwn{l~nChDOt&;W5Ocjb+h-)1EX!nfTi~E0edIzOm zM#045;O@PH(k=ieR+XMyRqZ&Lk6d(QJxaYW88gxzEVw-v48H|A%~T zqP&d{WZKVke9XLq`~z;kvV9rfAIh}f|5)BOwqG0lWgX=e{bokJqPJgud8@13(lxJ6 z_fje=y|YgChib=Zd~B*JV()N7s!F*k_VudLi}e0z>Y#M$v#Uza(O0u=rn5FvtbFNd z?6)&&2PxZpPG#gaTXxQ_ktrN!=Wj#Tk+NDTtN00{tXECv93OC5Ae7NnTM#b%Xk|`ukDjm-xK}O`TERl^#Jw(wCnM$kGFg0 zYaJiZcw6yl=3hfI>Ke&q>d)D8#msoSclKB(?c9jI=#Mk%BcfONdKqA4y!|GB(tjD? zrAIT+O3Jx};~SR`q^de|Tj^ z?IvYi|38*R_t=)Qx+$ysH6w>7{f}jBV-Abyc*AcRW$pU^Z&^Xg(%v@O>!o;JU)rX= zu?_7d*hZ5r&{55K`=@?gTi@)V#jN;StAtT1Uw#8@R82!YkagYk_ zIIBA4TyXkN+4eN@cx9FQN>WIZG6iAmlG$(9M|y2NFe7XGTHwskip?@ z{^-e^qGTUEsMjlwkY>YmQNux85B|uk{yQw%k@^0e`fpIBPc$V*9in&5>c3N??QPO$ za`eM=jxPQ`lNuP=5i`jT2FZJlx95Aa+ zmApKWufK+z&~c2Nh|b*3;BV9@ZwASXQ+6WpyAi+5m9y$f@oQ7h%c|Tmm9Xrax3Plm znAtZ^w%a$8`0c8iRi}&J3rz85`p5NEMHdkBB~?YZT5LyoVpu;fmz^TF9cBM&sHT5Z z&#E!mzYaF}&9sYo|B{`GLjn_KeOJ3#o+d1HFivOpuk`So-M@PAU*VliUjv^W&h~4= zzcVJ+-Lm`FDEj6jX4RLap6{CUnR>DxNImJV+gwj+mzqO3m#LXm$BEyE?fu$}ZQ1;B zB0>HvW1INx!f*3uXH}E<{g%C7WB=Obc=i4-@z&0&+oV6QH2KZ+=OeQHS@dOm$zrsQ z`pN!sj!B=%^J~`qr5=6J3A1XWzW5k3* zLPv3Dv&XE~e9D#HVI=Nh{I2`rtU6rcz98SP^KFSc-9LQjiwnOD(|4ssKXv%&!cSl0 ztp2VqZAC#p?Q%})cF4D0tUfm4BaRRMS7z04F|oY$Vs;-f+M=2IFt3zZuAKXxg(LRn zCU7Bt^;K@!A=od!30kYFrJ#nY>T|2y3^tC7tE!nZJ1&y-rP4|*`YE!TBP18^+%i*@ z&FiYFPs1QjUrT^e;cGMFPzN!#c{%o7GOPY3^YU{{F&cU2=q=}c`eAr2jyUcTODXe^ zujwa_)PX%n;+EA?6%IFiVvJ?5kp3bU7-=$@j2@epCcVw(h@mNHw0-J@Y@Ys)ZSOmr zd|zR-{Y%UFDcts*_^E9(+W!86ewJ+eVSJ2yb5=dhv%%W+CLjMp+dq_U`>Pk*{`z#= zuU~BYJ8av2WmWYVh1$N6whtb`HI5(6s?W(W!fA@p)b?_TSf*h7(Z~PE)510bY%{WPRvn^`>!xjtxTJO*D5$f(4_#VS>fCQTJ%x+_>`IJp zYtxU(NH)2UtsihpPpc{-OKix_gq^b|b|=Y0bq({?$gKLci+b&yU!L zP8A5)9C`Yh`~>C9JwB`alB;j!my?q#7M%yBbH%{IsZWcgpe0kK&uN=J!}nvJoK>57 z=0-a+zdWbkwU{f(Lnr#qmuJ2m3S>t*4v><%GA) zsvBhNeI&n}OWDm%(f0@$JY`Rmv6Lf$;{kYlRh^9WB%kiVahP*UCaa9J48Z2o>g?G& z-vaqUCLAt!uz@ri8}TWU-NTofHe|D2drKb2e@m|vce3pows*dups7L)Ni z871^wurrejE^wr4!)J1FzA>0c`IcOyr?m9Y<#N$YY@NwjwX^ismxr=rnXz9;E~IrX zCKp}n``RG- zQf26`Twb3-*3TI1T-~ z`MJ-{&p7&C&CtKNyuR%7oO^C>=pSBQUyr_P2SaZj!;QX>8&4bhjunR9JQf$wZ$jT% zoKm~X@%J2?cy71$hY|E^K4kbm+D4z#e~ORhc)g?He_tDYj{h3;bvqgUoi_R$|IO&D zOAP<-|4H;kyBhv)u+iuEuc)K{XY`jY zuWv*@T59+|eR=&l^ur%E^hYkQ??XTE5ktS%^7?V~y}KED^?Y_LEzsY}j=}#SN&UCs zw72s0&MNEkJ@x484ofPBjD@e-=snr7P{y}5^zPcEx?ILuoAz?{@3GjSMZXDs>zPS) zk<1NLet*mTe&`7L-Y+NBy=<#Z=j$Eqi|+M%j>X5azpqZF-%s#zzW$qrT*h%PT31t2 zy(PXM%hzVcaS!%2Xh+a;DC3x7((+7-93f@OEcIK5uInt04cno+-lWSMOZ0b{rzhB= z??XR%HqS4KUmLySxNQAIKaRfooTLhgf1A0r^ApzgEL%xDYm(|x@o%GdQHpN)RCRlf;+FZ$~w{uTLp=i%AwUYynzji4_&Kbd~6 z-fnz4fk|G!QO5E5WqtiPTI!>(eKo22rJPr7_N&Y_b=Ej`21S7uF}84=)D&v)t5y7aK1kCaFS>T&^DtzTeP?3Yct(k;+R0&jrK(c z+Hd7+oflib`(1txTdTUEfTm-xIKRzJIw6o*4(a(5^%K65DAj^0kf!tbJtwea%&d?|1UYU9;~A zv^{8b-_Pf3&Az35%1@xbT%A-ulUVMz(XY(LBKlS6%dbhQ*F}GWjlR#SZ%03bUiW{o zjXuYJ5BgOdhX0dn^f~^wi2v^<)!$`bKF~&gu{EBOdirlDssE0!wx5kYlT7L-^{qwU z^1YwB=%9XHMbZ!|5m;>cT6fhk^7@RPO5yzpX(cfdE|FiYD+KRsI&ZOF3`s9oGdh>NOiGQQ$yOZhfUp;T5 zZ_MUK^uy@Oev(xG;KbNp+fr|4Z}r&ONMo??d15T2lY*HZ7H}cbsMQKaRfc z^`w$(9@@(``kd#z%ScEs`Wk81hx7H$>#gltkAC3Iq`F7^?_@I;WF~u(Oa9u>5C4sR zAjj5s^8IJ#kfM#CjgJ{xn?7LH4x=4;JDI-zYqRf}wR32P{$Xfs+Q_V}_#*Y2NUCz_ zw>JBQS?fm|{g#6=&^Er8R6mxy9lf-+2W|VLq1|_B?FiaQw3Fg@#nM{sWa9mg z;rHF&=Z(wex>cjC_-|7GEm7^orL|3HC(!D3d$_Q+k{H*aUGsiYT`&2)Enn-9U!pLs zugj&IKJ)_#V@$p_Uw?7>X+hb-xBw^5BXB{CZDqetvVHZ|r2bBK?M&15?Dv_&P!yf} z6vj7n59}cAW71`=`*X=ve_rH^Rcj2+AC^s)#L5l?qBeM~J(W>npRee{CMjwy6=f zvnM;AY(Zb#fIh`BXa)KQ^Ysqu$vrpxONF@!!>0@6lDJW8?g<*T=1Qq!O{Ugdou*b) zmn+HqEBEQRYRRQ}a)Bc@;X1xN@5eIP;9n~7Km40b0vB7;NhUzbA(eVQ#;IQs*MlyQ z@oc~R`Z;%ZW;+;tu?Es^&})#8C5PNMeMY~nVOsGp2I@f~^PzuDLb|xzTjhc>x5(1}a~*o|GuPJ1 zDgTm|#g%+O!y4{woBt*C{78i-EX7M8LyhrcN{#EopUgf*QG8RH%@)EGwKl0zh|RA*{b)V_a8f> zZrTz3_4)gT^YhkgT>Uw!W0(26OcH-g;`w+geIBx_ zjox$~BDqYUkD%Aj6W%k$WAy9Hc|sjp_Zf_(Xs?yy(o6Z;wdwC&oM-e7Mn1XS!%)XC z#~xNBJ_7jg?48noGeWzkppVQ9j62==J~rW_&YevLFl{qf-I41DX z^2wB1Ek0H*>*G>8AJtrZShtViW4Hg!M-U&8eN*Z8-n?b%KSutIx@1~SzYlLpsXjLK z;bYj7QY)k`59j-E+-lul$I*;d5xH4bwEZUCI z`esJuP5Mz^p3BxpV%~bkNX&4~7>*zD6~I?`|CG8$e66(cJ)eZtdlKy?NjB zps7P&ad;{{k1~(>rg@a;n$dL}ky1yB-+N7d(Vc5lS9D$I)}uRAbT?XcnGPYkK6I@| z8oDbB>qgNHW_0Hi))jx5^E-5Ud?#3SnfPSvs76;-lhWU@tsQLA8GZNLMqOlFYC_wN z_K#ARz4En=4Tc!I`0hks`I(doh<=4hpZ-qf;t@r(eP~son)Iz3qy z?HJlIv_BB-t0t{Y%%xwU&we(QzHa<%zSfa*9IQj%cvMPl6yJ7wc>*jQieAT7^n>WH z68*y_|LHoOm{Cjqy3v-`rj#c8>^&x}5%=PLf>!#(5c)avdf(Y#($mK>eMj<83X|Tn4@(@C z=t@pbsoVLisi(7jE)z#)5+Yjun$WkS|Gwzou+huoB1Yd3eJA>sQw;x)+30ip_oLr} zUiW{ejXuZ!gy?Ti>A&-&-IlL+Hdx2b^0TPN!>RN=v1{}7=6h%o|0?t)ze%O9JzZd< zf7DvvcJxE&qmrM~ZS);heGmGkM-2Z*+30ipZ$V$)mrB2{Z$BITXx4uU=bn zzGt{wzW&=)?(PWqTmWG-dvC&RM6#GRDwpGm1X ziTh}q?d#Z{hsyNdn$|Bbq~{;iYuJ|U9+vI)w%M*L+ou}PtU+Hqm{KRnbqJ@8ULG>$ z+J{^mkmo%))s++K`o(-Lp0%dWZ)@=x#i#$dlsZA`{?_LFJ|`#AOupCfEsI4z37#WZ=-+Bs*j`hotaX{i2pZi^kY`N zwif?iPO0NX|E`VxA6C5=eQ0$`9U*#UqkqM!517ptz%XUee_($dC?ze z+NyVP@)P*3p+D2ce~#XV-V;ixL!`bdZS?=P`VXS_UT4(TCjZXYt@?=Q*BSbwZ2afw z_sD#`L;9OB|C8}e<0Qf}l2YH1&->cw&#~s;i#~*2pLf}f=@(e_0rY{_ zQ|eanZ#Q1&%PueH(V`1f2u|9LZ& z{vCz2Hu|fq_4T87{VkRL-Hnwt`s=d#I_elgANoh;*~5H2w+grdaAEq^flP4pif_SPo`9<=&#S$ zo8K+&CZ2JL|G%m9edLSt^&T`O7cw_ZFz)hMGix{x%6ucS0-G0|wl$@07TxLjzSbHw zlRT_J+lF>nw1?$u&DQ`#-zECllsesse&2k(b6@MV*a7qv&N=nM3iJn>^qKoSLpxaV zJc)kY8FT92JD}gyq&LptoEL9z(Yr6=T6bVhjf(&2C-eK&Az8iTrUCuL)C-q-xqfhN&X@@BKple?Lty^thlRn+Yp38{+G zwq&A6>zmQnoj0%65R>+>jXrbYie1K{_2^sCA1?aaOnSzm%;8x22dI}wDy=?N{-p3^g8FYj^lQ5@yU&@8eQ?%=F{J6yf@b;$5=FeG~p}f z)q)(uHkdS~wrxYx(LS%vm$rH}U*mW(6J2`$*@S-J+wU)cgzT4`5y~OjK`Sf*`8*TJC@5LTOKa768#Pcm1{o;`~ou8!m|L(kM68%~m{o1&yEfHzLVLD({l(PTHntM z?aNDRThTV&JDX z#4w#Go>CRUou^cTaF;3723;SXQXApe$EMUE^p;JjNf_O8N|kXa54opQ9gKf+N;N~j zXG(R!*#1+hPu3s6Z=XW#pea?%v?_S$l&XfI!=_Xtj2=FvI-uvMDYXfDYp2vO419h{ zC1HH!lyWmg9`jA9dgwY~O0^0brqp^EI&De~z}T0j)P(SyDdpny&3oRIs)fO?5*PHf z5El$zLR>J=N?gJ#h>QHjt|TrPyo$Jl9mECW-ytp-3Qeg}@*Ra8Fb+4u1RQ|g?@g&O z7=*>#zHzO?AB_G8y|mkn_?2bY2IH`o^`S1}fH7G7L#4Ev*batZqwwY_)eSwjOsOFl zfC=com3rVO21j55CSm9{^2KdS*Lv~={jdc_U>A(S9+-ebvi^4b!O$IS$E|Gb&MD>j z5&g4!O8Hp!{*-*n`VCXc&wA}H;$hi;H~j&|;DqoV`U8(5#3F15y+0%GFbun7{m-XV zi0vcyO_3Ao`wQ{~$L^=SZp7~cYzIBRoKpR=-GftVT>LyVMefkU^-@ph;_(vCuclOl z^oQ(u;~*pzBw*$YD~M`0VwV=&6H?`iVJas-aD z9DbJaZYIxz-|II3r1lV zOu(ot$JvjioIm52MRC}|Hk&P5_Wj4a$9o?M4~rU>FAB7+eoS zZ;}`2{TuyLmfxbhaq0s#;vRz@=ozE_Faf(|`R{B818@|2-=^JobxaUe!YFKju6Jl3 z=!e}f4EtdmjzaG^dEk{z0ayVeupVmvAkWYTJ7Ea+z!)5Yu7A>>U;viz3bQDzh6&gJ z1MgB#7=zu=H9h7~Xl>!EKed4>@fh6&g&_9^veT36@>EQ9jE)Sa%!a zlZ*0Mc6}7G9Q_#OvpfdJSq_y^KFd*9yPkOWoK{^hyccn>J`M+Dnct-@x*h!|s6X`W zJ+0Qjs2e>D^1IT*V&50t9gHiVLI*>iMh7GNp@S}d2YLVo51@W9b|Am$cPI6(oK_9c zS2e9VVD#W=)eAkm2fyq!@^L8jfpHjsV=x3=hfS*p^uZVm!EqRaC9kvIJFQ0X6Fh?7 ztLUa4N0L9*$Dki3U>o$*;2(QjeuJ20?X&#u4avJA_9g5RU3 z)f~$a*ut`(-vBOugE-&-%bu0wm1RG4{gmT@Z(236>^W{)HM1N$epveRK9;qUDW7F8EZIo>r%?VV@i&lnmLsRq-f-+R;$Xe! z^l3FF%g}Qd`ZLG_41bAyLRTYtSq~FXTaE5+{4}A1v9r*@v9r-Z{~G+k=(*JI9=2ag zKZTwE{Sb!Fr+uJy0sRaHn~94!{QQ3KI_SD+TJ=a=a7fm}2^fMUZ;}UC4Yi9Y9|mE& ztcO|ze=Y21EJxq~jKeXgUBY(Q1D8@BjC`H`C%gG(-?H1}G>xJSkOgpgbg>e{wNf?Ix z*dw=+PZ(cMzt}_^cQ8)DL^pYa+6M9uU3by1pywX)ejokpXY?27yO(|q{romvHw@fQ zJHg-s^g9@Oa9UOV0)G$Duc7zhY1Ih>QOX;monXJ%`JJ%|=z4_wvEI{1eW3Ozdgy{Z z&hKXmXAM_5=KVSrIf^j$qwcj)DK-Y8Z2mhpf zpcjT=BlHci-@p)zz!)5au0PNZVH}pf%XTl&-Z1nc^?)%LhOS}q2;*=Z`u|9OoIv*{ z@=rZIFHsJR!@-Bhf1LLE5BY%u(EDfh3z&f2N%H#_>a&^t@iP1QcJyZ$j^Ss7_Hoee zufRdtb1QMc&;ogaE=9ioKwgWIsvX8ZlvF*?|EZ+fBJ1}{s*)Gz9~DXE+8%%VCsi#B zz%?)eBXCUCqYE9t_whx4U{Zx)6b_0Vjzbsk>?z&>|F9qX*g;7(0sU2cXYECn59a%j z&|ghFFb*rxyAB~Pmcwuh^zgom2G+-6I}CV}YLn=A$4|*H+aHnS93MSQ!Wb-DLBEAQ z?9rN}3PR6k_+BE^K1-Z10243<-G5~J&ruF^)g@I2j31L!y)b%gQjN;`m6Z1<>I-XN z;&|#0T_>_kd4AXgL$Do2U^moGlJ7fF9vp{JxSs9&t5^@cUnC9~hwhiKpG-N$#04v1 z=#->tgb~;V6AiQj^qopQU>Huwdf34Bk<*ADhE6Ab==Bpnbe)k@r5_>>uo}i-6C8u> z!Y^Tu6GvlG)xohZCsiv9e1&{t55qyx!Aa;^jebY$a3ea;SxGevHQtv|^k>$?8nN@f ziU5rAUWraPc3x6Np({Z9LLZ!iVd&Y3xS$WZc&|hye!{R3`gmW&Iv9g}vi^dkYC#u= zT~OoQ553R}hoK)%!T>BSq1|9L48sN(f#dk`Ur2xd3*}u*eOd2^K9*y=V<8AV-yq-6 ze;NHubi9)wjLrkKms!4?@Ats~jEY}4BK9k=?@WAc)C2l>-+&(`zD2&FtDXJc#)4~~{~>vYAz1nm%7fJ~3L9VywnFVk)DwDOFZA9>USY6{yzYiS=z$UFgYsSY0F2#4 zKZ9ei2PST&-JmZ_zjV<~&<%sI4u;?w82&N&fl;^#25u!k&~+R6fnHetQT)JK=!Z>k z42Gb#p8UWl9D;${8INEHmVFHWum(n8BlOjKDD%gPtDx4-CMPa^iv2a18pP_W}AH48bsr!#?QwCGo-_Ec!Tp zp$EpH501eAOu!J-9;968gM%;xCtwVgd;)tfy_5-*3q)Ou+Tx=P|YuKd^`O(Z}iUaO?^C`zvg>new3L8QKNUJr?EtsHQ0a^+9>w3sX4EEhq4F73Bg=emvKa;rno)7qdk&pZ>t#LP zDIA31&&{Z&3YK9-CH4M1%gnR9upI{BMi_&GFn;t5*M^u+*3GE0e=#qEH82dDU;>7q zm+v6}NT05qWtJ`^CiBOFzGKMtNC| z!U)T;%gFabjKb=uwmi-%Ml#w?@K>}0^IX@jXVfIiWBg8)k7Xaf8RdI~I3B|>}wD-U83tj&qUoiAO^?e-uR@xVOlQYCh zy=L+EJC+sxU}$^Z;S4?e7Df*Y^V=2L6XcEGb13;Q{R39Q;BK?35xV%@1~2x=M`u-t zWk0{S&@TGjXH_rDp|V*OljS{T)fScm{Juf)0Ojoq-=|%m7kWLjYK<(zPFd!62l`|g zj>+<;XH{u}ezD)Is)d1yS=9{3U|5#-pH%}e4kw`Zz*$wc74m-n9?J9ZzI>l7!vIXc zE*L(1miuAYkDOKgEXQFR%l^;Is&SSz-a|hi%SX*B*A(SJ?J4Se+^ni&*>n7?YJm~B zUY2?PdrX$$q%7CZs`6=;VLkMnIICKri}${F!!R6_*`he zLl=xgKTN_fEH7ezfpyTemU5v7hM*5dU;xHo5RSnR)HvUc!3wAaX4NX_gRL+G!!Qh^ zFbd-^4in_hbs^<&o*w@;`yGsSkU!4XJ=fA7pJw~(*iuao!(csD=mgE97JmP4=!#$X4G!;NqZ4nWV- z@_QPL8&K2O9(rH|*26e#hOTGmSI`H0UUV`YYu_@2iwQ#P(Y#9|m8ed>DS6@?rE1%7^h$%Krn~zezvf`i1Xr=$XHH z-l9C2|GbU;HMaZ5tSWM&haTwqC;5SX*aE|_OYATz_IGF1h}hwr*rEHA*r5-)Cde!F z!%i56y<&%PvHy#HD|T4E4|Z4wV{i@B{!P5l3nMTH2VoRWzyvJam-ydf9EM)l0R6BP z24NQr!(JGL!!QmfVFH$VC})!Gp$9fVA8dsI*abtd7e?SPjKN8${fGYeDfF-g24N!% z!8RCy>tPJ`!7(@jwf|CY=z(RQW_wrz{jd=RVH*s?^)L$iU>uIX1WZEL`)t1-+re5G zhHGFPhM+6K_%C)iBz8C{cIaY0>Do%U&=1>T7;c1~De?>hZ~`WvYk%@PjUL9}8mJ{H z2Zmt}jKg8*nqgdkepq$@c32DJa1C_LvK{opO=5>ba10I~h;EMl1pN!tbChLR@h0Uf z#zPn@N~!hG<4CD3Fzn>}`F|r$-p?F>{vG)40F3eeo(UM|y~pKmQ7-QvTLry4vptOR ze%&z`-z}wFV{HGil&Y`9@9rtp3tU!)7&Xl z_BQ21AB^)(j35l|lTs0wfWuJZ{Srm*P!G6~?ZR*XdU%gS1?z)woaG4gvz&m%)!09c z9r|HC48dj?h3nuL+yq_wQGZ#69c=HdNT~$N0ocQG6uJ(<4!zLDJ0$$j2ZJyO!!QD) zFb?BTI{-h>2g?q{AFP34*a+ir1pko(SwD_{*v|S8@0HjjI#|s5*g?d{vZpGgCZQje z9)=xyq5t5NYJ#q6>IDOE6O6$jn1B;7eh6`Rso$Zr7YxBQvV0i*Qqy!iM&K~($KWLN*3fROkHbkA_zZrJKnJ}r z0muJ^Ki(Zs_HX=ro_2$tx|C{z-eaj3^!dme^dC=t-edcE;)012XVVUrDJx7-(YsG1$*ye}f^u`_~Koe5Y><44+4N$Kq!# z@j}n})E8=e$F38OHRA`mE@nJ{krvu%CH}ugzG3WA>PI=TuT#JO5Z7hY4@NGhesJtc z>IYp{Q9tNwCm!;meVce-81_Q{)x-mR*AUN<)Du>~7+eJt9r%Nu?~n%=hW${xmhtT$ z)GI_BERVs`8vJ~Z{J|IuK<#?kPu9bza9v7`LjU*qZs}*JKdgbSAJ7k=_XhF^qc92+ za76e+#^Ah!yPo<(-|f^NMqnJe z?%;dVvJ5@7=S_Kd?jcvJwB#cNg`A z-n+@qKZ*Mu{GbcLRv3qMtPe%l?^%w*DD?b{a#`>CIr{^Q-%Gt%@7=`s^?AyH70`7b z?T0-9UGEal{fsB9k3t{Ii5}XI<HS@(ee0)bub14PF{TqnA}(4L}$r6-VYSPc`<54|tbA7Bu6!wBq$Q8)tQ zFbRDl^yhl=0DUn23jGx(U>6MkmAuL_9EGk|X`e6P2Uftq7RrM$*bcSV=zq`$`-oG% zJ30sDJD!#QUwh{R-)3Fs@dwt${bLr1-q4){ETMzZWn0NM99kd-lpz6P+~H*Hnr1C_ zYwSW8P_SYN8zL5sk<;l_tzqc&s^%hk6N<*%JSRpiVd_qMUX4>ha+-w+>7ILk`{W_N zwi%2+zV7t;yk76UpFiKv@ArFtPm*;{nx(*a|C9L>|BBZ?+&IR#aO&4Q4)I8ipC6>1 z-|#q+cJSiEY#-u!zK#BIJ+8wp?8ScEhx>2>@5a{Oay@VeH<3@^BeMNFt~1-#-}AV} zW7vNg?LEQyV(%Xq4^H4wT);K!80VAB6ZVVQAH^=560_f$r(NvADcT+U6XTIwfyX(H z;tUQQW*oAO7hTTz;aY?Vag1oDwFU4bc9WLNbT=SNaeiydlJvfCA z;1PTT7w{qv{kco}YV5kCr2BCQ_u<54C4Ppd->XXc5Zit}uXs?7`%3zpD`{taNpHl_ zYZxbWp-m;dneCcZ`o(p45BB2yvY*c{9>FfW_$umgAGt9+guQLFk5hQgQ{)4*kNYsc zildL=wdAauX`gNXCrbJTwhMzLeFq-7ucRk%bT^-q#IAoX=?kuA`zxFuPJET~!!`d> z())2E9>QbzAhsq;dI`H8DCzZH#)mJ(jsIHGL)ed_c<{lJK8#23C@wriKks0?!(0bE zhS%c)-Y)weF6sPA2)|cb((h$Egm)Za|M%I?wih43u1C0@K91u$9Q|QQ_uv!`;<_J| z^j+AC_hRc$O8Oz}!gJoq{zsWF+=sn5k>zoN$M66yJjQjvH9zM%i2s9r)>DT)xPU{r z?iY-U@p+GMzHF!PUOA2r;^?30?;qHY>#_f7`omEi!gbHkpX|pe*^kF?s8rHxuVMbM z1CNYz{cz3ElHP+8dP(1n$M8NJJz-og;1ssLi|twCdJ|6JW;|9iuHS{Nv&Z#4xNhFK zegJ#%5$vBouGeiKhh4bwBtGMX{rHfa-@l%cnqgr zJFeGmqz*gq;9@=xghy}>?)&?3eK$_veYnxayxLdD(x~xW0H3`*9Nv;bt7I=Q`jN z-Xq&*a~)(GAHgGdQ7hLAuf~Jt&>xO2WBzdp58;A?`Nwt3nSa?{#r*r(UOTRPao+{w zdN20BiGFYt@5kOI`jO*!Q5*a5YCMS7W9x4O`#III$O7 z|IEDo!?@mwL)S3w>li0?VAs1CHxA(*9L2kE0`J9RvQ5slfqBDy_#pdT@8iL|m2iG)nJ+K$|Ngdw9_FxP1#dZp3q<$06r)Su1Wt`Z> zXJDIgAKoGR@jmK9ZJZ|_!PZXZGr;`dK0HKSVKdK9oM`8~OVoF8z8sI@wQLt~kL0f7 z`H8(afkT+Tn)ER|!nXB2oF8t))-9aJ7M=%qY#Z~6>q3l+`nv5rAJ}fZk@I4E@FwO< z_TN0NKfwM$ykMO1_0T^K-9jE)Z)KjveExAi9>FC!-plLBQMU00oOnO&2&*@^^xE?p+ zOK}Ky;sox;1)PxMJ9*yAaa@w)*cRkCcHzc5$Mtp`!gt{W9>OCygU4_l7jW%+>HmXV zcU*TD=Z!xdJ02-k5@4&czInBNfnewz8feFHpiW&1NcesIladA-F}Jd9m< z6#KDuJ=Y1_Z~`~sG2D!;pX0o6BObthJdC4w6eqA2roBP_KH+*raXs59yq#_9=eaI& z9Jk{T-hl`4Zajkb;hH$FKe!RkxqfgvuSd8MN3kC#a1@W= z6fWQbwlWac{XE|AAl`rzxChsKf%C$CoWdbIhDY$68)^TGJic)hdvF1Vuy+s7N1VWW zvGq&L2d=}~O&rHI+=rWR0ypCV?!(qEbAH%`Q#gdja01V{nf`G-uKQ=^4~K9NCvZP* z9OC-pK0G4(aY6hQ9ydLl=U3?$r*Jc_`5M;|ClWlLZ~^bfjsL>)346cJ-!r#xo_IA* z;q|!Y0j?wV;$3na591L$hF#y__2O3g!wx)xJ-FtZj2AcJejLRKT)?B)wU^xcsC$t9 zaNk2b|MA!`_1N`o<`pNt!{Y+ieV6OlOFL=K3)k%9d5#PCUhMxq?_@oT43;0jC{x;gdm*Pu*#ChPWaX;?BL-+=q!MEW& z{t&MHfUXbYM*My3#aSG}Yktf)@h2YR@s7{^5B`3~|N2Y%>(lka*n@xiE3OkB{4e^! zony=wUiE9{>vmm#O^){Q>#!I1{D#LrKI;(U!H?mZh^~L?x6Bj%CT_-;{EpW(d>J0V zSKtJ`2_MAYz%_U1-1}iXxa0SX2an?I*zq{mA9v$noWNsv;}e|s4*JEb@%#Tkf8rZ#1By0^0P`HojA`Tw!h4Q2gU`=#W$j+sqN ztr>fTaV|qQ*Jzpc8nbM|dA6ngyr0b1_SmbR^Q6FEcw_3=rMn~i^Hfl~UciP8UTFQ~ zvo~5S(Y9c08GoAXztDQgODU@!#ud{Fl=c%d;*YymWqf9=n;xZL`Z&)78(hVaO{r(nRL5`Og+d%WdVuvo*&J z$8KwYV;MQVy;37>{a$HnwA@zj&GZZEQrk0m+dP(Gzvq_O6W7pkpfawd3ygE@y_L2= zU25MqdD}deVZW!>XzL86tqrFv)Pj#OR|l%+%>0c1I%mLq&b(ZsSKE8`xmRx7+96rR%#8WDXFz>S%KD0&@ptdk{bnobe)X{}$7NeR z{&K9FZJ3sR)OFc@xt9J;rVrS$1}fqlN%zWV8B_&EBS`tPC1XKrkn=RMVORDMpEW!g11i{;>_=4cLhzU9S? zMcO=`F$C#2 zbmm30e?0Bh4yvOtd#i4>(j4DZn@P`Kpxu7jw0&M3h1pwmSF3C$pMQyMIO04v;CPp+ zmG|-7f#Y3{RhgO6hFND?+CSDcGW)LGtyWiFQ`EiB*M{e1XrupSXd^SF4LL{iJWR{J zspn&E%Q0DM?^mmhed->weyWX1z7yhk@@Ad5{{_^lxnr%X<2+W)vG)I8$);X!+@tb* z>G(z@RUbH9xyNNa&B$ktGe31cq`l86?NvKIb)UL@Jfl`?)SolecFc9P*4(H1`HsK( z;rZHy1pW?Rgs*;JzIHJ_m2DS(9exY`d+f%i;Y;x8_)`1^{8oG>ej7duUxt_9b@&{7 zIX)M^9WTSOti)H~^RNf6!dK!o_$vHHd^NrR%l8hw8NUNxh~;~zF2?V~Z^3*expoQW zYq_X!2@5P(&HZ0%WaSN6?y92l4o%kgDkC?B% z)dtH>;`7 zw41PepHLr`?+dyUJMrCk8IG2{3)|TKEDqs8JQwfAEAf}{tvG>K;0N&a_?uYf_hLE!6R@0@_)PZ8<5L`2l^pA&z09BHYNL<`tuR-sg<;6RXxBU~kEPu`uUIhQ9_%lV zW3Wozc6f5Wsc7U!l-$88x!}q3Ci>N0HE*I{8=={xm{Iq8S2zr zeyfrDl9C&#lC$v`o0MZ)uET#SxdmrWKR;V=a;|B+kvnBxWnNrWazX0U{%kiHxi>4h zo+>#Hb!x8Z79)3)l1o&{1*ubW{kIyq`<2||RdU1BsX1G(kvpK|>du)yFCOaDT;4fXSF^Or z`Q10UzhSl|mr`eO6jkC96&Id7Gm_NB?Wp)VV`aV2+GmE0(G zYJdGhMsDdzm3c{3$qiFCDfd+)*R149)pFFSxzVo~xqFmcW5e`$sZC7I*}h@q9#(Rl zRdOEc)c%^kY2+SPa)VWJ{nV*B$6h1%`h}HwIanpvOr4tZe9OpPrR1#3rk`Igb!u+l zK_hpkl3Q0Lm!VG01s^hUdzD;YmD~VzYOZ(K$o*Ey?X8jRD$t`tEpO*}EYA*j>Bezq@`K#n?>B%|AzZtm)l-#Z=xn}Cr{)WG2 zeSr8_l=ybwlXgZmRC7H>eO8Cej|5{l5ENZmv(Th3w0y-Ue$sFtHn9cTYzMy_AUMXTh7shgDhsge7hlG{&i znEmo|b_Q#l*C-zNS!F)^e_`aFR&q5fr=Q<2b!vb4UmCe(ud2+;+A6u;$0z5SpD=P8 zlw7DvuAe%!KhKj!?n6p$54m3U%lY+VIllp1o3ET-Q^ClkmE2gB{({u0{S6#8a!)C_ z#f{VFB}1K>8!j5TC8t#8#Y-;Fe#cYuv>?bhhw$i;$~bL*HgX%4++9`r^H8Vu7kt{t zeNf4zs^kW!Q*&C$$UUUwO5_~uZvyk*Wggc1!F>MNjvBc?D7nV-7HS^$tN)(sXFIP~ zazoq!lIO$gtd)7`BscZnfuq!^{#3Yvw;Y&e7RM?rtS_ zkX)^0a?Znc^PEa9IM>KMsN}59>Ej%rP90~{JR_Gc=bHC(k2h&>9qZd60v)iP{lX2b z-wshQ>x-<9!|Wf-*Y^=JHb3%{DSl?hmZu{u$UnUF4WUIX1MW zdjIM;ByVoZJvUj*ZPUiy%Kn);b4CoC^E5LrGxH)d@W1^yFt38V9t4%wgUpoI1GR2Q zsT-xvT%?V>axDKGZ8%m}UYBam=RGkG{jY;JPHrzarLOl1Udt}y^^!XCxn%Y)mN5)X z$#^d3wb;#T``Tk?@=7Lu!Q?SGIFDM+OI|~RZ<>58s2pp$xN=M#)A6oXJ0CNv9y`{$ zS^HxALfTYotM&DA9)CI8sy5c+*=LTyv}DwE&#qZoEsTC_mhpRX7cHE4uj z!VrNN#32c3$U+W^VA(iJdkxsZ32yK~0KyP~7{nn7X~;qjiePCb4|Z^Z8+;IeFhn2* zaY#ZMvXFx!SX#(~9h~3>9|Rx_5r{z?l8}Zh#2^kyNJAEK zPy|aWd9Z^M+~9)%gdqYkh(i+6kcAu+!Qv+mc5s3ld=P*zL?8xnNJ1L2kb@#v+Q@?) zoZto@1Rx9%h(R2ZkcKSepa_-#d9Z^M+~9)%gdqYkh(i+6kcAu+!Lpe=*ue>I@Ie5= z5P=xPAqi>7LJo>xX(tbMaDp3r5P&d5AO>+rLK?D=gCbZu$b%i6;07NAAPf#2^kyNJAEKPz1{s@?ZxixWNYj2tx#75QikBAqzPuf@Ldtu!9ra z;DZ2!Ap$XoLlV-Eg&Y*Y(nTKZ-~>1LAOK;AKn&uLgfwI!2Su<1$%7r7;07NAAPfVEZyY64o+}`4+0Q|2*e-`Nk~H$ za!>@zHu7KxC%C}}0SH3`Vi1QUq#+AAD1s$K9_-)*H~1g`VTeEs;*f+iWFZGduv||b z?BE19_#gmbh(HYDkc2d3AqPdUgvo;)oZto@1Rx9%h(R2ZkcKSepa_;5$b%i6;07NA zAPfS!46JvgAW1_h6uzU4oOHu7IIJo%Z=p04o+}`4+0Q|2*e-` zNk~H$a!>@zP2|B2PH=+{0uY7>#2^kyNJAEKPz1}(I@Ie5= z5P=xPAqi>7LJo>xc|UougA?4~g8+mf0x^g~64H=`92CKF8+ovU6Wri~0E8g|F^EGF z(vXE56v6TV@?ZxixWNYj2tx#75QikBAqzPuf~Ai<*ue>I@Ie5=5P=xPAqi>7LJo>x zxt%=N!3l2gK>)%Kff&Rg32Dee4vJujkOwVEIY`99h~3>9|Rx_5r{z?l8}Zh z#2^kyNJAEKPz1}JgB_gU1|I|<3=xPy9FmZR zEaadFmb=J<9h~3>9|Rx_5r{z?l8}Zh zlLtFE!3{nLKo}wrgE%B14Oz%R5iB1j4|Z^Z8+;IeFhn2*aY#ZMvXFx!So+C>9h~3> z9|Rx_5r{z?l8}Zh?4o+}`4+0Q|2*e-`Nk~H$ za!>@z$H;>noZto@1Rx9%h(R2ZkcKRni`);nH?UCK1p_b$yI~IuK>{9ty)X2{C={uX)bdAMUW->>ID<`Zq$8^r^;{KYI4tIV$m+#>hJFA@Z0Lo zTjOvz&Rb*K)UvJ3Z|mA>>t5+R&$)7W>k?aQXUo>jws2ebwhs2MX>c^Gw$-?#}ZrpvqM?8&Ud-d@3!#P zCE6tyUwpo;{*t%9V~MS?VNJt!+FX8~WBH1ew)$XqTX$P$8|ScOVjko-Pv!h6);4!_ z`fbY_mdo#;YYp4lw}rYxEt|B4tzDtE2Jz5uOg>|orgP2Hk*PYKMeZreXG7#ZULy}k;a(+Z-rqY- zsoPJDP^Z+Hk6pP&(x&9(o~7Wp$GDcPPFz#Dhbf;Mk!P3G$-PWL?q!;bxpomdisk!^ za*tCu__oStkIm#$-*iWcCuvQ}`I>c)aQv0!I=R=qn%{-1oUJiFsr?zqojqw! z?twQ^XSTtviFMh|fy}Yg$-O`qb+rt{tQAZ9Pl7o<@0%BDUVhhXk4$EHG3yI#n{^uR z326N8&cr~b)Qzik9%`BvPI_LN=QNAPWL?HLOx?ZI+2lrld1)$p4t3J6qr5G32g~as kIVPOUAM$!&E};vJ_Y2Hz^E{+h`ZSk*>gr`@c`;Z22W)3dW~yKe7#*JbZb3*wyPx|z);;|MVQ$<&TarWkR<^-Mb(V~R2b;m#1#U{ep=4@5BJ zI-V;;G~*luSvrXB&aOKDnKhS3G|naqmm`+a41J8>4}JRVv*}_kw>^ZPjd?&PKeu5Kr9V z0>APrs>L)(#OtbF8vAfX#@Q$zofjccF74TAc{!PBrvA9j8*anz?>|P_Y$HaEivHaS zs6P531R#u`c(>`w&)+WibMs|`PV6;pb|ugI<>u@|3(lvU%5!xm0+C(t4)A?Dk)P59 zpVI~JN5Y-ynGO5tjDHP$XZc*;1^+NArZYXycEP_1-slQ)@hZFEw{@ZCn=bh8y5LWA z!CTPjJInvIUGTOp_;FqEv%BC+y5LK@;2%ZD=&ase1K(Nx|J?<@u?s#hxO4r(&`&$l zze4Gp-`)lP^}x>c9|zx={)-27&i|nce)6TA>wg)1XZm+`!MAk554fyzJrP~-w|BwY z26vv%hr8fQyWnrXqH{gURh{SasxEk27kqRV{JYn7uK(LVbe^B?*L5yGs0%(ntaCk% z8#>qH>Vluz1%GcBd}@N5Ry5I}D;ETH8pSXnlZ6A~C3+@ej3#WJ~+V?7xV)ET# zX3UL(e}MVzKBlsNaY9TlOb_9rFZ5W%!2h_AAA|ly`g1pMB3JM`gr3H~aUzr_V@eZx zir(VVur&u8)>PSgtiM?|M|L%-p~x550pI+V*dZsfRxpG-9v#HqXy zEu8S7z3JG5Kzd3w22Dc*zm$zTXx}BA7u96auIGBnf8_jFelm>-qJG-fq>A~jG4IVR3BOJ4RU+0GVM6|Mp+B^V6K@N9n~Hi1FUx4`4=vKi_r6&Xm{72Iq?nT=qQJQF}o7>fawZ5UVuGQxtc}(g}5mS0>qbl zxt!52z7cv{FLIvdmvr>*&Gna;F=#UEHbd|x!58z}rq8eA^|1YUUM|CKr;GZrJj;2P zkPj05qW&dL%oY4G=EwS)T7;bx3jR7YH09qU+H1Su?V^4nmU3dE;CrFrSUsHLgkguV zB3+m8V}}2EMC3n4^lKxZi9&yUDc57z!vs-pCebdTBHeY!BH4MP$iGn!AEN@Py<%SB zg1JIo6MB+GJ4OpWQOFm)&IyRIqXGSx^+&2uB-_MnLRHwk&T5q9hre!wCe9?X&*yI6fHCi6|)&W(INYY}$4fy*H|cDNxx z_E{#M5Ov`7UPIf-qoW2 zmWuxVDpzBA@hYAlS2HIL3%;MQf0yt}%LMQ1LeHI|eM8^mf;J(aCdRcE;RldycHGYF zwy!By_)nw1JdKWKF&%CVEfWP2@;3@S+l73T;6J>E=RZQ^->CnEXcuOO!XBWO9Y2Wq zMvQ0|6rUYG8g?bx#Yp`dVGk8$TrN-CI3fI7c?bW0o3OWze&$v1_y6}gtpE)+{>bh{=?g^qF74h4qhef$e>pAhD$o~WAAT%B=7vqu9 zF0+GpKEp(QLWQ2m{ds=MMg8~%f0L-6a^c^;68wikK4J?eR*G~lf}K!3EbmZW_tjj# zD*8*2 zkdGF29wWx7C4x^Dex~AIoIp0%aih>*ww&XK1V0jXNd3K0$QyR`SvcoQMLS+4h2kh5WtHPkx}RgCAHR+C4_}FJnGmAnZ2u-&~I| zZ+}ntrTTi#?-c1iegp5PEw36S;y3)z&&Da?Fg_IWi^O~^Qq1S$1ix6+XT7K&!w#rD(u{{ofD4;-YL?ZC(s|MWf%ErhC`rr zP~Qn$u`ypgBHF#8j0@(8bbS}`b}thB%c#$5P*KbuzQN^DOm^(OoXaN*|7`f-$3*@^ z4{|x9Tlz;rK1V{~?suTd3%8aBJ*H7kus}j(z-Ox=*xw@|&D6 z+VLl0heew?FWil3KFUqyDqq9-GJZ1c6zvir%9|_rA4I?IIRA89&+}>yC6#k@8)MpW6O{THea`_6;-;MtJqUhH#f;aSU6!qZx zFINzb^3d_NC|8;2ScYAFi;AWE6n(+v#5BQlWgnjZMp2*7@!O^{F`r59ARj2&z3~JW z94qA4iTbge=7do{*TCLb{fK$BVYmNcg*^5*(_30QfgsJQVNu0x=m?WNty2S zJfNi9S!sEsBrS`ga;c2W?3Ap`htf^Ar_4=BO3j&*l$x2Jnv;~Do04~bQVM^Zk(8H% z8*_l@=W!D!yGJD@WvAV5vkjk- zlAoEHl+SKBQYTK1NV3^dXQkvNx${yo-T98xIEY6iMW5l({q$iI`!hfbYEJv)+BPXQi=cmj}pOo%S$wb8rA2l=G zP3@kPm!6NSIsA4~MpnwqxVdfimV{e`wJ0;F_$J{wgZ71T;?6S3Im&MGRbcf9*nk_G7PJUN$V<}f?<2xh;yu7v%qJ+-$ z?3wOaU5Z6gUUS`*%>)q$=xKh8TUIW$M6xT;k&b7Bl$T6*=ZAVGV{}&>2uSw z&KD>0tT>Z1XQJ22k=m?sxGgD3woB^Lb8@mB&Kb72xZx2=N$@c_4<==?(k7+n<>ln@ zbSJxQwyd0)Fla`O9gfCGr8>in;j*}>%Xmk}8xW44(g~TC<)X^Zeh^LD=24JTQZ9Ow zTlgW-N79qh3q?H}4ho&+9Fi3R0y7H>lXBDZ@^i?Ex#uO#jR2YNPD#BV-st|MjFikQ zQwn*ivkcEPCw)$8?mSallRD6%K-?ls`7B=4vxJ-6*CV5kSdRBU>+m)9&Cnay5GbKBn*LDYu!y^iE)6i9T!@|`_#@JDGI2XM$ zBLlgxr_Cr@OGrhIrwnrqBqQw?;Xh)Ebe#}s5_r00!%Fb`7_ z@-N)kOSf)HNt>I3u_f-DJ20GcxVDxaCHl8LKR$Jc$qAd90gvCX6ve z8gTiD{hNd@F!ODWpp#6rcYDdqB6HJI?vHbE`@2K7&B%OAhFSZgD;cv5qiLu!Ic%LI zLN_LNDn7X@@hM&2II9=Zke#2|Sx1~`JI9_d{mhwzZkSF+4F}BXx)Z7VoIJN9J1xBs zV;7qjb)qWLou2Q;Y~HYnF64#}Cpn~N&&x}hC&`OJ=bY4|GO{vrdHy=j9?d+?sY-N; z)V$OY!;|2v=VGi+qcI#q4O3w>lVOiWlecLxCbu1o+%|$@ut^=80nkX_u8YqGkQ-j| zjyHtONmgPcPsY%0J4V{Xwws77E3;w>0@*3&WQCPgGGb)yT#rcEMNQd8@!$6PV%68d zWgE^qX}T?fdGDkG%*f8a(&%iBbIuZnTiyjNsN~c}&4o|JGHF(aWz#ISY@+eDZJuiz zDbI3e6lBl>>_YN30@FI)r0vS6lkuc!?u?b}1B6Fk71}w`a?YFD$c!xHwqqrV6we=ZR6b_SdGics z@f#D)%8#2(E!!Tg-5^mpT^eLuWd6MDb6WiZvz?_sKR{Me)j(oKevG5-|;&$fJIsQ{g|Z36`~&7IwWJ$GV^|C zyRzuHIr-S~Ns7$Cg(G^-3@k;l@8*vCojRj(=BDSdmSPU|H#c*1E_GvC1;_nP1^Kgb z9-NbsJ@5BgY&3Q_L=o69`kRYzt~Wq`C9ikY7+Cbb_0u&CkW>oM9yvTbF=loDC;<~jZCElHTHsy*+E;L zg-^#K>+H@Vcw@QSE}!qtDagv=1H!rc(HAn>$GPU5?HZ&xnA{O)3N|V;J3k#O2UM61 z+l&w9rR1__3l6LpX@*7>nVy}3^>o zMOlcXnvI(rl>|}zch>N9Q+C0eBn%vU-V!Y)2k-;!x$1NZ3AN`mRNJ62Vg#0FY{x5Y z1~!Li-<(R438#ncB(_c2p)K2@^5r?(OlhA*wA~$%y9I%GtX}aKm%wbh?ccKSgTF-%?MV$NL@iBrEz~>uFZDZ4^9I zn-BUQ^odD8{Qsp&KCs8njY!HK9x3PZf_$Zsqu(37%hdl5YU$iO{Vz&cPT5-wGty_` zi3^^dr_K@&1hLT}Ftz~aV1)#KByF%5J2A6TFzq;ZC#KyrM3raY>3WxofzDU!7Zmf? z*XkFfrpv|l1;zetOP32*d7tz4%0^@aDG#TmT{Lb`#Endg; z+81w=?!eYBd8Ib1Fcwv`!052MFbYpt@f4RWs-nf#>IE%I&RuTNg3A`o7F?OxSn0Gc zY}%Jw+3v0vWwgFJ->Qr)k1lvsHrH5b8rS z{RQM%nxFobJa-c9Lh>xn7%#|ivI>%8U7*EKg>(|_Lh^X-gy^?;+pedGZC2Lla@yz} z=cayPCGL8Pd4ch}oMT>CkNVa0f2HbK`7=_pa`MyhtdpJ%nKE+lY>eKyOi43ku$_NX zhC3avWSTPAdnojt7j2`NQfA<>xG4$qOZ?CaL6~sP!0RvA#0O6=;ofjVQa;}AOivSU zD7fHy#lYE@qY5yCyF!8SKHQ_`iI=r zE9f83m8_3C{PZd<;`#MOp)sbwpuXXk#q=2&HR83{7?UZin<=bvW_@5nzu3snR}~F- z`|V2W%c+hs=VOnXk{zzK$;&fK>aKrb|9a28j$oySspPH_)8*F$KBfl6m~$yF^v-lF zg7J>`9k`}r0za81;_MRFbefD1k1!R1-m9L5U>x)v%zX$+2+0U32pI^o5N0D#MdTs4 z5eg6r5$K@rPv#?t&+tq|xTa$vLNUVQ2#XQuC_&H=o4S;pVvHtV7xbu zOLjbu-=zqDL3jb-uLv(9lp)Z&`L7|ojzGsh`Kj%9xw!fl&MOeg1%4Oj_YmGk_yA!g z!YYI{2;wz(Qw6Ro5vmc^BCJFB3}GX}=Lp8pfQu~%^clx?LDH+`^!>^=0`J0kH^Lr- z?-2GO7{?Fdq6ueuW&EJPhs61aI3LCNn79_N%$r((PazDsLw~~K?p|cI-)(;E_IYpL z7E-l4>eQ>#?)&D}dx!t`$&7zKw&mmhd~3&CZ2rrt*yg$zx($UqkB7FcD(!0?LVBkHehSe?18UMe6Z=x{&&7H z>!BAXeZA?-_;ITj-tf<(f4FDyn)jc-;`D!x_F8x4p;vmY-mOn8%p1^T|5It$ZQ4f< z+}Yn1wYmG`v}J|EmY;bee`n@xxzGGnv6&yf_xXwi{i}A5J@xUxygM&F`2F%fDPPRq zR_T3aPQgFsu2V;ByYbe03$|XmqU5$CgCD>Ak+Z_=XE8;5NwoReO@hLpbnn`sJN~39-cDr zn#=DPpR#z)z*B!8yysK@L$B@{xap3Mj^zGr;Ml&y51w3c+o3c)`?eL+=N``-(6s8U z-MPI>A1S|U#e4VL^SYa=A~)Zy+q=*EG!A z!c+u09^@y}tKv+3|0{7#r@Ii!5N=2K9)bK6`6oKAMR=B7ai1qHO^@J${1YAIzmgD+ z62S2cg5hhT8AIRxnAo^N@DB*X5S~CtMh(cI}5QDH8;YWlI5i$|H2=ehJ zz+QwYX>2=1RaKZY<% zU<=Mc;<`wjFA`@uy^pY1!o|2ADB+#rx);tN5>J=^64>2=pWgw?u(u34Tn`dBrvop; zLjX4*T!+vD!HTdH;T?oa5$G6z5Qwma0FG*YGVKuOj;DWv_zvOXjyF2se!$%jCUxLt zmz^cU z2Ck1uI8|Izi=4vFmOqb2n1}`{mb?xOB17=;ygcR%Ncsw&t`al z|Nr0rn>9c_m;d`?!HwO??&-LSpV%GhYvfx(5mNh*H|xg!J|r&KeX`xN?+2W9e>0pC z-KT@c4{W$<5h3vx86?hO5+5w_Q4&vMZQD`C_0z9WuXNA&J5t0ObxXYQy?aOA_&YZpdE@Vq zbmWb{&q4eU1f%X7#rO0bdE@VwbmWci={xeq-}mas8-M?%BX9g&rH;JucgQ;OB~pD} zMHM5CB8k7&AaO1df4_wE43+pGss3-2c#FgjlX&CrV38j3>qfm9e;=hIZ~PsXj{GVq zpCcvxbrMfL*ElL9KFT0*P7r_hg7lA(_(G|?V}JlDsOVEA!hW`R671B1vB6S4rv0e5q9b zf06VQO7ee|_(78XmnA-|3tpG>$ns@UJC;d$>bl@_rSiTa$>&P?UzPX-N&X)aA0^4l z{4z=YbxA%(DwoWgB>Cl%yi4j|GGEvQU)BXbOR_6t-Ac(MOT4_Ma!Kv@Z#h3w{@;}N zWGUUZB)(kIW31olcBsUcOY*A3zb*00rTTeC;+rM@J&8|{^t>Hk#XEfT+0;_IY(sFnC!Nx#f5 zm+C?0Et33tNl%!hf1|_)NqS`7B3MD)AOT0y@|NRo5An{ESzf98qqr?|Ve6z$?NclW0 z@llfgBNCr0wfj+tFO}-;Cy8&A^q-LU5=l>s#1~2Fo|O1iQvOd#e6y&xp5VGme2c^f zNWAHTz? zyejeiCEg|RgCssd;uVQcmiPe@KTG1jllWYTzgXf6C4QR37fF1M#Ft2Xh{Tsl{3Q~< zOyc`We3``emiXlopCR$(5?>(kt0cak#8*iCONB_!$zPEAa~@zEI*POMH>U z=SqBu#BY)KQi;D;;+ILhJpU|{_@k2ia*5BA_;QKALgH6Re2K(YNPM-#*Gc>#iLaM< zdH%Lt;KN#d7D{2wH~OyZYG{BntJkoaiGNm-Z;^O;erx($yZy`S>mZ3QmGoF7 zUS1arlK9sp`A~_M_d~)Y{vAm^LgMB5e3Zn`l;mS1zECNt zygYB8CGqb`^0^Z4koZE0e_G;;Bwk+cmq`2=NxoF#nn?QK3C$mN_?TjAC~wciN8nUOC&yB;!7odzr-(-_<0gv zCh*aEZe@l{ICGqk)v_j%5B>6gtw@ZAz#0N?Ic8TvP@r@GSL*jLb=N8Ow zHcNarNxntm10}w7H|ix_^IFcsOK%kUF~scQVm3_nJ=7hxB}4-xK7 zIELXo!WR*aV0bp+V8Wpc&mi1~u!Z62gfAv+Vt5i^g>ds35ZB&L*h09G;W30m2-h=w zGvU63D;OS5_!7e93|~*UAK@~FuO>`OaDOSomk}O7xQOAtglS3d&tPiFWr!r_En3_nDere^*ahVuy16x|=e@NB|E35PN~gYb=nEeua5 zJdCi3;Yo!5NVxelYk$HKgc}(iL)b>Rp5dDb4<}r~@NmL3H2KRJzMe1*Vg53PuO>W_ za4Ex=5vHNQU&L@b98AzZ=mJA}s) zE@$`+!m)(Q7=DFt9N|)iUm!e=a1p~#6CO`Em*FP}tAvvoevGh#u#4e`2;WXPhT%NI zG{yEuFg%;ElW-`*GYC&0Y+-mh;faJz3{N6VQwV?aDc1gkU4$DM9z&R>RQ`H~Zzep6 za0SD|2~Q?m&hYhw;|Z5Bd^O>_370Z_8R02}ix}=pcq-vshIKfqbgku;!LYRh5e+0w(2`3T`Wq1$adkI?@-bt9I5PlQGn+YcoZa&G{pKvnaMuw{h zrx31Zcs1b}gew?+hj1$4a)#d^oJP2e;a3RL5biH!_yxilgo_w{n($1*xePx+m4eNwLjrf!i@}%A^c~;^$g!k_-Vow3=b##4B>KyuP6L0;WCD=Cj1=XQid-h z{5;_zhWip;N;sF{-h`JCPG-0p;lB`eF?{MO;1>wTFnomYUkOJryr1xkghLtLL--}a z7KV2c{u^Nv!cCyAZY^%Q>o%eXtKK0`Aik>Y zQMFx8?YJHYEvom{mx%QBpL+@2`&NGxDXN}N!|t))R}Cek$9L;A-1Nuej&fy;sXAkr zawSSYMw%(MhOnrl=(N7!$1Jf-WxDzcWDx zOAIy7Mbo%wUT30L2vN&fTJP*kbc_%U;-Z;c>)_5ruVbPx2JfwZz0_>dYmTmuVGK^~RBLHr0M)=D{UiB~>W#M!;`f~1TVtTd zskQ2}Afm0MtH0sO>AmqL+;C`dCcAP;Tu{uSgUX`U&Cuq(^`}OloCgm|gk6X*H{ryF=Apl>o8UZlDLLz3SMV z0Nk+{cLH%Ih~J5~c2|2m)=*moW%+U_KWbMjaY09w=@oP}AsAQd;=FNz z_M-XL9%j|o{RI}M&oVkGv31Z=_BIOS>whhnPXb{{<=vdxN&VX+?bUb&2HBnJa4pMM z52>vEth}iHe~=COMo#9+?!~ET81Pt*J%q0S9>KAn@WsH_aQs)C;%vu1=>aXa3Oxmh zw|A9W&{YajoLV#bZ{a=mMEkw=`|L^gRwMfNNkh)KRw{m>-JHRWLagBTr*VKEA zB1oB!w+5-2zqK?5ZPm0y|M@VwZ+nNA`tQO6Ey&metya~ZwAN8cwJ#jnFX+Fv&8)ww zs2*i%g%TcXjZxvKT#$j#B5MUZ*Xk>vTlKWyYrp-dV^ynGwKuJ--+EdG=J(UKo3@uA zuG8nX+STH(3T|i`t!m$>p0yU$v$vV7_Yr8Iz75CWQau~Zs+NVcv_z{4*Qt8n6G`pV z(;#TC3B1DO@Wz>Jo1NMrx=XokEv0;-8AVn@DXS5<0j^dLZp-3b?OB8iHX+~bSq!Bt zUe$RPcQ&_WF~Z1VC}lBBWRYppcIuT7JUfd{4Ms+}LlIf-(BqLgi;=k;#NhS!G3(9M zPHl~~-pJe~to{P6)EUf_x9gimb*R2SvAm%Hp_J!ssFku7gq{OOp(0l|@LXNVTXK=L zjMUdIvX)aOa2!VinF}!BPz#`KiC4lvD&btXX|C$cvZ|`*7qs&g$fwggpBn3zf%%tf zdW=ag5lVe8T4@+miw_pqnr?Oa(k%|p_svf22Yu-wl#{H3t9N)dn4Q{dJS(u6tDW(jDJ>Oj3UUH;(hP%(4Sht!bVXgEYM0F zFS%(JWig0n@k2AuB2q^d`}69DkkglDO`*(%HATvqyTZsEjms=&iPmK5W3$@x)Z54t zRdge=qWYe-7O}I_nrv&;FC_u37L}Q7cK23ML%I5~gRCt`Otb~nt^O@&@_%oVmj0Ii z!1=;p;QV6Yd{c0fdavla%ujfqWj(yL)J46d{U&oqxJiBMoSXF^o!Sx3!y+1i%>^S^ z6~^#3znz&i&#g-zkCbDz7IopLEfAHREsUrclzuIh2TkCvpz>Mt{)EYT+#e7Tp$BpT zUFFTD_f+)A7(E0OU4`mB=?ZqZju{ki&ZQf1_#k-8IW!pk|`2<_&A*rq#qUdsr&#~7WiX#`IL^)uE#gC>hC$r!Wy zHvcREMZ55x$||`6b5B;v;>#ez%T{dVmnc#3Fcx!{ehtde>3lQ6p>1<$r`ZSv_h$Ik z+Rl9IB}k0>*7@i(G_~XopLr~Ds#)Yz4|1p4qlbih4WFcs1L40IY=XBmeyzw#WIrD|L3Gz?=> z)qQ^-BX&>i!65ILKy7@mcTA8r-cmchA4MlC4q048S0Uqb5t0#H2r&o|ie*eNtsfzR zBu#ehCwt|AEA8f=>!DS+-+vsxUyu8nIe-0j z+*^NC35n}>L`mENuvv>6q}@GOn-EGd21zlLsb3vYuHV5UGTACE&Pr0pku9Vv>E-F| z5j?5}NmeOSk?QsJP*91)s*qTn78j;X7@7fr3?-zv2!+BqE|-3i>BmJsG4#WFVuo__ zz~VAU1=u}jx+za?f^V?lYLZiUb~t^2!-xDURgO{Yu$77Kl@p6PVy z8yNwmsI5e6C~4l#l`3Ia0V)Hwj8#JVt#EkO24*N*yFUu0C|@_FI1;9IR(fM`YeMn& z?%`(@!=m5MlMF<=qZAhX9$+Ob7@4L*j8!fPUg3;Bih6KbW8A|_dAn2}QKof2`8pZn zeQ5gW6}r{PXbcQEB=BW8aI+)&+k(&Gd}c|`hg-&g?rRVk4S*ae#j}yurWZ2Ue#lW~ z{g(0lWV2t)QsQQBJ_4(Q6oO%&Wb<^Bn>)YVpp74-OW#A9pYL+$1|5tMMEiKv;O725cr)zW$og6DB6 z-o>;LrY)u(0go1o*7SC__iA%gs`nFe7_>>$-Cy~AYil+6L&yy2Tt)U+zKVZSf8)rNg1c!$6bQ8UwG z|7)U_rV~+W>T$-t&)N53hP7r-O{*IHW!`66Wu^a0b7jLx)fc!?p#pdsFnY~PdTd-gRLTdZQ~{tPaVV)uK9P%J~d zI5%BttC&#SsuZ_Ew|@wFJd9}(u91@V-B@qzzQIVjxIN_`)NnZ8(|4vi_YH!}R-i2RQlUhOphj6Tt7t7z9n<5aBA-r`8D$2LmVbJ+i}xSz8q z(~c|C4jxhF|EPoyU96_Aqnkc<(|6X*ti_nFR0Me{ajNcC@E)qbeU050+|9i1Jh6r@ z)|#Esn^f<;74E25bG^AjU8Z^`z>NkjWbNxZjrt8cs!T%{n|AQ1lCU4c$bj62>Qu)Xne~D%NT(u(|?46@FN_+%>+G8+iCagG21;S%?16azHP@R z6mM3F*)IMYh%_O53#ZAxMz4ed3;@*2w;>A%Y;^kq`o6?9>>*(fZo}_v^^G$_9RwQ@ zasJ9ciis%ugxFq0`9VbAN?BE=??E}bIiimiJclf}BifVUer5VLXh(r9{U{emW7-!& z*B(Uv9{#V*FYHmm;6d))dQ_?UK0pckNtt>OwQ&7^%BU9ZKBB}oQjf^CC{y;~A|X52 zkvcBIr<&0=YUa8rci)Y^xL&Q?f16tA4>dRVf*mJz_=3@#W}mB@nz~ud+{}fxsg*xM zXn&~rh_BzI6FYtVES@Ub#OsDOi*fiOd!S6oEH{Z?937)f>-Re9-~em6F=)EiSs|xW z1)wZcC%dT%DIZAG;d4Hfj98X_e^*o2%S=MQzl%D+JR)JM)7(sAX=S6ST(9#93$;e# zR#eSq+zW{>!-mq=4$r4%hv#&FQv4{M*h1Ly6itz+_)t#+geCE*(HL2G;W2;`ztg9p zxW7^-kZ3^UNfbHlsTd`G4~q9)huYl4D+;xFSgK7m^|0z2J(nf>aV*k9%&(8aJ%gFH z=yCEBsIDDgw}T0JkummL#zht6Q=CN~FbTVoxafItHSO_dS)`%$c5O=Js@?#eQ@t1T zUPTWmJg1H=2()YCA}KQ0j*F*CAY`jhhSe!cE9lPi^vLI^l2oS*Ygi4>V^YSEwkW$c zF~aVBybMfng}b+>0&9JS+FkT5arFg?>Pz1)jjQ^r-;jeh3Ev$DpY2`3ymy1{n*`S_ z=EtyX_-|!e;K%6H^uv5N_4L5!iFuy+?JD@~+Pp2*8KuRWA03C`jAollse8j9*294M z1mXz{&UG-1KJ*8>v@h*ii`~;`_M9>o3_)l9id=GqQcT74V|NrTd1{3pvrm&Vyq2y} z8SsD5JNR)Z{i>}SPeaSHJ`N+D_8qP<5lr|L7FL1QhF)}bw3Q|8aq8?a=xJ!r>6pkS zU?MvW?aJgaL783wZ`BRuDEKRjHGMnsuO{45fAnYLK;70iSpJuMf_52_s>Nj;|8({gM=$iE>4Ci zRQOzhzdEQe35+plzu2Y8zTED}t(tk9*W_W0Qy7MR3^i}^1 zfKFX9vmsxk0~Hm&G7Xud!6Pw#F)kD1ml9D&rgr|3l1z;n8qGpYvUnC1k}|%Mt{O-q zC#yQlzj1dw)yViP`YEIzN^*QI{miEyQZU|)pT$LFsB-<&+?gJ=MmX?1giXEQ_=V=P zv5C&6X+7Z;n_1L%GemWn)G-+ zjli>IdlL5U@o?gVK7>fzEGnd_ZmnL3^I7)7=KArp2Xh=db)Q6F%Sd1LCEIF9>DJHVaEno400Ak z!x80;Z{IZaz?q&HPJ(_W`q_jOhUplm(cn!`vef}C8gml_#Ff|HkW8Y5?AzDgS zR7r25k-Iraj;bUb=l1?7)=S5JZcoy?0FS(}pwi2?A*T1?AVPTj*t6Az-9hX_()#H= z6oSSp5&!+p;^%e}-}kUZFJ$!yC3ixAT1WC1?Q5}x2j~yep^?aXsJ<48debQSt#ng) zjCP(K+7IpJSxr2osY0l|9N0_7#^@P6-vIhNTrH|_Phz)h#~G&U2z`Me^D!+_^ke}e z^o+I}53T5r{NR(RnU1+SfTkW+2jjVcOEc6VD?b-xd zQS)bFwIi^rP+`vZwl+%bg`|W0E1^itrx;$^0soU>whwvtWEaNZSZg4AGegyGQhf`8 zY{yskqmK9qpRQFu}uZ)MFM6emjONpv@f7Mk~-(j#@a{ z#!*lpySJUAK^*PmD2$`8If~-wTaHwY8aYbfXb(s9sx;F3o})sJ_Hk6gkWlMj_NpS=4d-dM>x_s`iY|!j*fE_#A;{|eqE?J<_qrS17_PxHlD>)u^34f zZ$;I3or{CCCl@FR6bZ2>+9D`O$}TMiA0v?*H{rCVOO57 zR)#eyORHlezVbPHov|yi>oKFGndmgLr?OQUwnZ8LS@F6@uh3$bp4K9ls=hJkWmUbX zvlZjLf+}T6A+8-5ZXFm<9iEderFaS$&nHxKcjfiC$A8_{)>hhKkH!9bhw=^n|7`iF zKrtpho@+mQmryrcMSgHgBi1cXZNR0|mycayY=`!F4#i~Ur+ts*5Yp;st%LoHi*3j8 zvQxnv|I=VIN@+S2UTNEG>_6F+SHH|3sHVR640T&HVC=itIK-?k1Q)9BAu|M8xxm+* z2x!}AyMoqas&-0^K3uQ@iMg*wq!am8HFeRuhE|WE)f04HC{1PQ@vDb+ADtwFXrGOMjczip;!ZLtynG<%=KgHDj9I8Lt8iDH4_iyx5l8gNf)%t#qw=*<`JVmADBm+iq-V}9-)h!kd+ewo zd-RveOI1Nt%A%?GP@tBT8JRa>>mIycc~-O9O1qO7&e=;813atGJJK-V-Yuh!80Czp!aaxO9MFTrF4yFN7O)fybp4d}WBZ&PiBDz9$JzZ^Q37?njj zyYE3RxRaCTzid3E2`n~#rMI6jg|pz*2MoQanA$)qov}clTG7>9haVtnQF=}H)F3Qn7=`J3m)QNv&Hl2AZ91`R@*9?cI%@y(9;#RKc8BInqS;r^C&wXV6f?? z469;}e7$hwmA**yxy`Waw&q{T-2PJT_SY-VS1H4Gl5~SF)^tXRt-&tYhbX=hU!}ya zM`dC^NEueCjIYGr47G;~oBt7q(P(@HQoA^qIs^{%D=L>6P@lS~wKakJZ|?6r2k>|* z(CWZOHr6nhkvLON;Vnk}sn77R+7pC0=2-0`Qsva%wcx~_nqT6<+l4gDT8usuV|rpS zN!PGnbemGuH$F(VH!sUjd;d|ri%B0=#fwQhai*g@pL@qARD-1?+ZQl?3j~}rBOPz?P7R7RSA|!p zW;`dUbcR=|(MMEeY@MpzX`w1>o8Lfqkb1*-ybi0V<~qD6c;c|C)mOK@A8gl}SGD4? z2u(=HUdJdOL@HXP?QnyxRV_Rcv5Vw6U#PIU%0E*v6kQ0aZF4%UWp6u6CbJ~rEQ{%B?+|0(_ zGv)%zhbSo z-OgfZ7E!Q;MvMNeeoVG{yb$(@hT`~xMg%{0qQN^*S&vFu&o{@~%0usOsM=9ipl zS2jWV5cY(*QTHOu4eVZb(P_JPbWy_@>=ik@{qS~0e09re5(z&7X9sGVs`dMa7bAwcwxdqX9?pz;A3IJ=nnW6Z#1mV6Pn) zi2J5h3-F`XRtDh-!)jvinp-o5T8h$tJUnJB<~X}xL+z%*>>p}}(&l0$c6%*rE~3B7 zjf>YV3gj10Rtx6EYGRZyJaEEZl9G5*3EP0n&v5yj67~(21++9cgn*Yd5;o#|2Df%0 zk9cf`A3PkwQ>26@%JiETlTsxNPh=APoZ!hNZXxt+4c)dYQ+MP3Zem`mq5G%}8u9~C zGkCN)7AApvi4|TC6W1OWIrXxPPVIBVgQ6hvQ#>wh$J|$4de-|dVPt6ZzEU%-zf2#S z(4u6)LuxP?q?+pjAdZwgiHkXy^~GB8=z&hFkYzfTW8y3 z=r}xJ`vgYWd^Ao;I5O53Pm9vcROv&P`rM-cjuRNX(oW_Dd;iLj3WKpkuE2IWZdey1 z@)?SJdaN(87v%9I#4`G2Ec$Sb2Njm!B}y0!GJ#Aiu?mujWPOQ0!KzNiDPh|v?w3j! z9;qbkWe*DzzC>Cu-Na2Kd;%A+>%>}0{21~ZLXSX0tV>abkba-wGI%925)!!rmxEu% z5AB7AL@u$ffq9s`vDVi-Ef(d;FMz1cOVGx6dhN89Ieo!P)YN!1qp#mmEO@Qhw2fS; zrY2gSReghBR#UUAm^TbvLBdZueWMMHPU{A{w$X|4vZZZ4PW2f7T??H?H`1@WF%YHr zfik^^aN@oe;2#M$QSB%0X*oI`kBfe2QNpOZC2T!97Sq$+OhwjSuqTQAg{t5b{Tu~M z{F;6?qQFmcwCiu2saa%o^O$dkbac2ki^D7=(9{Y zpoDFLx@qetq#mTSNB^7EK0V7$Tu+tjM0u2HCrAd*4iajJi`~}(Y#H|x{Z2$K@t7G; ztiq1rbQlr0kx)F!hKIQbI^rFG@{lYPjN+Z9-;0q=q(bq~>Li#*r4Nb!p#>S9b`l&t z@=Vx8$`bds@CUawc>7^(j|tIRl_#IVLduEPod@yO4N{(rr`ARPZlpIKJat%$tXDnj z;knlZ(3^`v*cPcl*oLqv&fGW_Gu~KpW2`S2r#-%*ePhkLeS^_6&LBy22QVFZYooW!%DyY^1(MJ-0CWxj88NGruV?+oEUP@O-se>SYXx79}NvM*= zLBD~q0-{AitV`^8UQRE%Z;y*Up!mK*4b$!6ZKtHD!llJgBYJgRE z(Ic3>=t18CH9LKgPY_++PWy&Ffp<_wa~W~FLb^TpiP(TN>+(4B_Yg~iQ?qTx`ya5_ z`P)v@DRLXtdm;c%{kEY}STFky7p!~HTM~(1(B{?rFWBgjwS|dVw}_thg%b8TN|~?$ z+E7RMIYN~}-YxO;Ielvf^itnCfwSDV{762LhQ5Svp&}%nWiDhe%bcsNZ;=ax#gF#N zeG6R+(r0xov>4tevBbbDTGYN5MyKL6c#z zP=$TC9**dGrTArZCwl3)5swuD(Y{;FaFYmS2rnWmLwFXU6yZtSuV)QyuB2gj6>D97 zU2Zqyt2(E(g2M{+7Q7p%JW1ahvq7%yeX9T(h+!T&G68*y@XAQ6_9GkBJ*V(~#;}&w zv))L`C`D7p_H^MlzGp6e2lvE}v!{h{DBZ$)uUS1~;7@xdV@9OZY&2nL`7R?CZwu}j z9IMpqwxXLV{WhR^_h-a`ZF17hV1F?B7`;0!NfCS4{6<@^xsbW*TF31dQw|C z0zXxIkjbxw|K6)4>{G)07#@&Ec=m*P*w+sTKPriz!2v+@Gq4-sRbX>R06zt+g8pCN z<01DA%y$pY$S6sDiUg{u78+PBY@=GJM=ju6yP8jl*BO6^cpZEV%W$O=cVOB5eqzPPwzzwmDX-!5e~#dc+>R!LCf)u<+zUOe9tp;YV>cXonZ>Mt@mA{b$da z=!OO98eVJLteTIjpU@wIfHISM)rpVK;6e>QgV&%wz`N%Muu+S*eU@PI%%0bI|Jd-0 zntD+61~xgg*iAvJ*vdo4b7L=Ds)pqq9y5Dtu>7bERHGZ_f9}94C3OS&k{QahHW&G_Q-^nwRj%%+j{g{?)P^7^l$VyfYFA5tmRaN3@08n}w?fmEY06RuE| z@%0}PgVCT8%SWxAJ$F-;J25eChM3|xNbW^?Uvkil&C2z{H77 zg0cGQ1`6*pud=n0f9^B+VYcS!-gMUE&Qcm?tv%qlve^5YmPq~{)LcAavdlk49Sh&@Q0CCsEBXr5aRqi&9K~F9)wW(K<$BiyEqMwtP{h_PGY- zKoqvRF`mR>e`&II1dlL#tf2=Ic;M?f)vW+4id}jj7%Tx(@rMVnuzeCI<1^2Pu>a9? z9j)r4N${(WnBdJ^P?ZGlf}p;EZfn*0r#LrZtEpOF&6r*KkZDkj=gIW$O8XMQr9XlD z`akf))|Yql*8@V)pjb11Y@udDr01BDYL+K`5E2p}j$m|;=|PK-LG)vxk2Nawu#z}L zqN~u7ILxr!b7Llt=GojypbU1Wt#vBT;8gX+x=a)$3!@d@NIaPEot zI!7s)--8NtNRNk3`ho%P>f@{PSZe|;lyaTeO*A(-eeYR|5XJcJj(z-y?Y8~;FqV@< zYhlwsDW(v|lNPMN!hfb>VwYPf>4CHyXjgVDP}$}Ou5VMLKg;ju^jR-=M1Sg3#x&AP z{Oezb7#;}OIhfUD_ zK(EiDI$QPSxao|>SJ-P&2uJuq8*1-IC$fJCS%ds8u_V14K9EpW24vvlaa9|NkA?8D95wY`h{l!_1P~F_ zH1OOk+YX|-+uA;czI&u+sF>TMK2+}@r#B7F8UCI7Hq@L_vIKq9p&caE)1jKZ;X!YG z;PWT*H}o-<3sx@nR2?jv_(avI9c&7~2iNqWQ4BWTVFC2f_lGe5wvk_L6(?t!bJyjFv!74Hy2GaJMAh zI?ECMixV3K%pzxF)4`4xTwz52J=ZQB(HryoqR>wBK{a}Vu4HJD<80Dwt3B?D=D6ticzag++w=f}0;p2i|p%O6@8W74Z>50^|+<_RNQ)! zNu!1a(RViFP54*A`YxC*d6nhVKXBl(9G6sc4&OMqyhW@n>0E}}4o}T2r}iG#=I#Cf zCBPnQ;NwZAnRZxa(bZ=eN>&}xc~WF*jkN;t^#w?eEbA!cKnKGvpoU-6;R1hc;VKYt z3FusJva&ECdWyj=S|Egc(!+^CxQr#Ept*LaJ$!?GAwH*oE6lUwyFi*alMSl)&bl0u zO?}w&F(!(qk!IcQo7$?Z+>8zPkiXbZoK{n-V2Y@9k!i0(_dXlE3Nbx<-uJ8z(gbKU z`yy+oqgA3G*_D;G_UKO^#4P?r=7w>@Xal{RI-2+FI&81MSXc-uma=A)6rYz;@x&Lx zRAhb4+oS^(OtO?2YWxbE^%p7;lfr>IxJgXHSXZCCqnMec|k zi@pQE&n8aVT8H*+6ZRDGcT0G_ltls1PWe^!hH~0eKd2PbW~2WXDl7dJ4s2SWgZar^ znuau8E+SKIl|_e`(0ps5zmbdkYxudX(cx{^VuM~=>wiq#Ie&w|BXg_kq%9(l!Oq)a z+q+Z;yjSWw0Ga|sKIH~!UP1BCZji6RIlV)zC^$J1jDK0yAiYLNc4(6oM8jJR$50^l zdtI1Q-<=C{7*WHX%SrPGJVREsjcWK8G%Js>;&J?D=_>_h~DeIo()6$+dZE0LGKbgzO6Dl=s_X+r9)c~7!gs3Sel@x>KMXIN$@(tEP(iB(hc^cb*FquA z(RBrT=`qs9YWSDPwtn|JRFmIg;BbaFyKjMG4$Z@K<(Tq#Cd>O_XZT^K+3&;?uE(b` zrg=j6G26OQyYfN5i%a@JGg64&Sb%ScoBd?4&Ty>TkE)-v4LdZ{>l@!f^ZJ4ZO^Dv- zp5V}SP6$6T!Mq25jUbe^it+|bh~BMuXc}|7FWACTqdxAWmpFd19mn%0N^ew2KN~&f zazy`BaL8e~I6?k9C8IEBaGZLrvnHs(YrF?V<8?%0#fVc0owG*^$`V?ei zf_6mJ^a&V`0x*-M+Hr=jg=suG#HoErkFT`-_@gu=9mb_GbUDo6uAHDv4RYYSTe4B4 za!9`p0@M*u3-sK*ZPn?}njD_*8Xdm;M!YV9FJih=%hEH$0M&CQIX@21Kk+V0@fws- z^w>((v%69C%|nD=)XIa1u-2^Y_v}H0)?~#~4@uiWlu0Qbk7n@SPi^6g#Qd!$m(MTI zo@RW+SldeP^u(aPEP(^?;~ZeYChdSyEO7>u0mlvqWo!ho<-}GnHioe-V(W=*WNb2H zbBS%nUf}@Mv%iQ|pao^fzdKyyz@nbOrr25O3F)d(vX6p2&ggHHMYm(fzQY%M=>+q) z{%dh9@_k4()5|rj_{z2IX=w)R%Mv(@QXgi)R@g9PX_y5tc33DQBao$Gp~OZomSumK zi&$(FIET3y%d$T#mso5hIEUq`o`Y@q-;DfYbX8C66!jH5tQoO_kru8{+F`hj{Ns7+ z9`r9|(Pgx~;0wIiVcz6Fft5W?!Mno~iS?B9_pRV>ey)L8pv%%cmmZa?x@W!;YT}bQ z`nKD<<|2BSLxW9_{_TIrkkHl@I>p1_8=;!Nr9Ta^mE9RR1O`Cx3qbZk_7D1O5yu;& zWAPAxNmoFacTqqolzLiP3vPut{UxYpxPtFL=L()>FzDk@N?WUKy(y?<0buH$PW%=%jIj-dC)22wVWB=#->yzYQd&!+CWi*#a$`+t~w6Zocz zEq?qaY1(v6SgkA)wMr3`Ru)?+X+m4LffULnh^VbyC{QT2iLERWObZPmfQmkzqN3sx zpQxySAkdbr1qCUKSQY^h;l`jWVp%1>@0ojVnpXOJ@ALotKA(R+y`6i{%$zxM=FFLy zGw06L2#?VnEsL6T2XA{CeD3n1KvvdjbQ`Z)d}P_Wux#grv#UflxJsdbPYBTf3qJwo z{fHL0hbb2GjikYhbfMct=G;;Sa>e)UG1>d>Tg16}Gyq;a;xVyUWJe_UYUI&zkzh9^ zV3V~$(G7#fDy*UKq|O(f{E$jk|H~hn0!NG)dO=M++~KvO+$TI5JoxALj#{1P3Mi7s zA8CJI$LM9L!+^3;qD2p0RI3)UuJde0&L;lVBjp6{P9ahvVX0W*Cp=Xv#nb`*6q0}U z&wKu+zQ-uRU+X&s7*XGK{#dEL?ZhH^$9cPOr(C=diP`?TOKtO)2U`$h@Gx{L;x1%d zUFb(QNYgL~ZxFhlhQYsNn#AO*AFx7A{!}Q`u}x2H`sPQ}pRPb~Xgk>R79NQ`jr^0! z|6{jY-`kaco?^wy-md&ovHUImR8pn&V&Ot8LJ%VpVMcQQdQB`Jl_b$e6S*QMF;a#@ z)Y`%^tapfcP7RYa_i%{ak`PhuwtzD*OC$M6Rw`bB#dCB+YKUL-PW_8gQU+FpW4YB6Gre_-^r&n^D(=$S(=M5H5uZu`rx(<1!6`m4Q1aRqIB**wH z$>S7%u8@X7IM#)FSBBtwpH-3fM?%wW(*Vg6o)y4K`d7;Tpg&1q{wguQ#vh4;0B2}~ zeCo7>;`87T2&ii)+x>^u(RTAr|MbvFXm8&YgViR+_pv zPDX3XK8Ega+)&s;9ar)6HlD~cMMpKWb+EXfHkxsIfVVA%bDXku2j+c>3(xoQPPe$8 z&PaD|P49N3{HWFAxS_O06P9NhwrJ?&ww>^UilwAs-eDGJ9qvj8nG?6p96&C!?U4wF zt2kyybJqBVEjp_jE}Yh`1l97cF*;s>CGePN3l0dN*l<33C$AcYx!J-or4*awtyl*)T`IND14c7pFZ)_7&-f8DB;Q20QDWriu{QniT9McC+G# z^u#}Ay2+;VD>I3Rulz^{bT zDQXxL)YnKF4YPZ(O1n-0cPLq2@#+nx%sy)?-bK9x8qYZ-8s`~4v5nz^7ne-$?aD(T zWMYL7Cyvn--{ZLDv)+Z`b+%w*LXpqb3Ud!|V+=IRFuk$jVdsTyfe_YW{`PBpKZjb& z9?)8UVxda>pB0C5vJ$XlDNcbUhH?KVK5-kY`t`(mI1n<6W3P9K^|LVlIAL}o4+6!p z^u)_EH+usPAX$w0_#@J}TfU5Z;z4U_05e&Oka#gM|1@UK{#miuA^r3=$`>7bN>%S+ zBKN}^7FQvRdK2O--3y^Mhb5R3cU!^Q6d3zvjOE=UGd(|}a#(ry!W5Vpw;ED1b=oqV z=8Q&7K~Et2vr((-LcLb~Fz#hD#vQGgRO z#+u=742i-?Onf3vS0$?ktv2B#>`Z7-YOMD*q(Bjcp(G>dR(OL@lMJ&0bF36}q{)z* z8G2$LmO;gFX%$J>o?LgHOoUCg$NTDdZX|J{&{h>jBMX@ zsh`JsO&o2ZuWB`(!${$em-PAQfHZL571kmRQ`zU;-xNw{@MJQ^^*X9 z%D;PVl&=gZEbY3Gl?rQ&nG6inh&VZl(0U9eWAnb>Hj`)| z7E^!6pXaq@+wr(kVe68PR#135r#dgBaurV98uFiY%D9-7UkLsoQXupo2oj`P&9 z*Po&OO)4>QM@cO2rfm`rufT$RC)#q0Y4aV(1r>5fQ8;5I&KtoIVzjn=<1OM8_C;W> zM#ua`c%1-_KiiA8|5bRR7aVcQ*B(VWOzNl>e8~o4nU4j;fQsI|2GpdYi-?mM|H_nh z9$rG$rv7&1W6zg2Xv=UUG8oWcnh$o_;ICQF@AEQN-~~2s>vUIFGrW{7Fg{59qsnwU zOzU+Ajg?ru_u`#D z^(S^AF@|a!a15<#!|`T~QSKy-%c{YeOCcOvF77PW3ZH{mVKe@DVS}j^+Q9Tn_7e8? zFH`_d-C@g55TOMTlOSenjR|E1=>dg~nc<*{4_uH&2{LiV1W;2Dz?rlg4w=hwZfA4leX-Jk|og> zwYMam)Uvk@&;??#@27Qyv#wNa?skj}G93J^+n6dMAiFT}!K`=Qvk{p=f(~Tq{{tDH zi)Da}1uc4Y(9<1Q(%rMrMb2IzdG7E!b*+JT-it0{ zNOxkJ6_qXzhdT4nwtryaU;lag#JQCCAXt&^6wHp3Fo~67NV$c#^I_qtQ8+J27A}~? z@Om1oTQtw~9L2xC$)I(7jYLwWBoyGu!#~NSbVW8PHTcIPn3HC+L2+;u zO6>(#AxkejrpA#iDGp9UslDJdWa*VbFtQ}YWe_ZrVABXjcBD8gd4IDrJJ?DPZS9Gw zkR7QBf063~tVz8n(*;5=0Om0Ll4&H!*mOJI}@HMcZ{J{y(k=gm6S84(6r%3 z1;D=Z!A3%C4A?$p45W?WGs5do0T_~LAGJ;*61VlZg$^KN)3Yr1SRh=+wo@(cd?W2L z5puz@3~3yj*nTEfzW(h((bO2k %NTx)_>BXE2hBpgL?-VA^LmdW4$7?5cR8OSEa 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 RqL*dk@B%AH6@1aazX4X2KY0KE literal 0 HcmV?d00001 diff --git a/sdk/src/main/jniLibs/x86_64/libc++_shared.so b/sdk/src/main/jniLibs/x86_64/libc++_shared.so new file mode 100755 index 0000000000000000000000000000000000000000..0161f0a211641f178dae8c0f7beeab29aa5b5888 GIT binary patch literal 993896 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

uua7$I3D!K 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 Q2aQ`8zpoae%?h3W4NtZxDF6Tf literal 0 HcmV?d00001 diff --git a/sdk/src/test/java/com/ciscowebex/androidsdk/WebexTest.java b/sdk/src/test/java/com/ciscowebex/androidsdk/WebexTest.java index c6a3014b..06c4d5cc 100644 --- a/sdk/src/test/java/com/ciscowebex/androidsdk/WebexTest.java +++ b/sdk/src/test/java/com/ciscowebex/androidsdk/WebexTest.java @@ -1,6 +1,26 @@ package com.ciscowebex.androidsdk; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import org.junit.Test; + +import com.ciscowebex.androidsdk.auth.JWTAuthenticator; + +import java.util.Map; + public class WebexTest { + private String auth_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbmRyb2lkX3Rlc3R1c2VyXzEiLCJuYW1lIjoiQW5kcm9pZFRlc3RVc2VyMSIsImlzcyI6ImNkNWM5YWY3LThlZDMtNGUxNS05NzA1LTAyNWVmMzBiMWI2YSJ9.eJ99AY9iNDhG4HjDJsY36wgqOnNQSes_PIu0DKBHBzs"; + + @Test + public void test() throws InterruptedException { + System.out.println("123"); + + Map ret = new Gson().fromJson("", new TypeToken>(){}.getType()); + + System.out.println(ret); + + + } } \ No newline at end of file From 5dd879711c0237e5a822dc23945679b8fcb5fd25 Mon Sep 17 00:00:00 2001 From: kliu Date: Thu, 9 Apr 2020 22:36:43 +0800 Subject: [PATCH 07/16] Decommission commlib --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c2305668..176d4a61 100644 --- a/README.md +++ b/README.md @@ -518,7 +518,7 @@ Here are API changes list from Spark Android SDK to Webex Android SDK. | Package name | com.ciscospark.androidsdk | com.ciscowebex.androidsdk | Create a new instance | Spark spark = new Spark(application, authenticator) | Webex webex = new Webex(application, authenticator) | Get error response | SparkError error = result.getError() | WebexError error = result.getError() -| Rename Room to Space | spark.rooms().get(roomId, CompletionHandler< Room > callback) | webex.spaces().get(spaceId, CompletionHandler< Space > callback) +| Rename Room to Space | spark.rooms().get(roomId, CompletionHandler< Room > handler) | webex.spaces().get(spaceId, CompletionHandler< Space > handler) ## Contribute From ae2e9b06949fc5cb73570064dc187b0206ea91a7 Mon Sep 17 00:00:00 2001 From: kliu Date: Thu, 9 Apr 2020 23:02:39 +0800 Subject: [PATCH 08/16] Decommission commlib --- sdk/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/build.gradle b/sdk/build.gradle index 033d58b2..1597e070 100755 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -9,7 +9,7 @@ ext { moduleName = 'Cisco Webex Android SDK' moduleGroupId = 'com.ciscowebex' moduleArtifactId = 'androidsdk' - moduleVersion = '2.5.0.6-SNAPSHOT' + moduleVersion = '2.5.0-SNAPSHOT' moduleDescription = 'Cisco Webex SDK for Android' moduleSiteUrl = 'https://developer.webex.com/getting-started.html' moduleProjectUrl = 'https://github.com/webex/webex-android-sdk' From e131721685c9dffcfdd71310c74a23f85334b9bf Mon Sep 17 00:00:00 2001 From: kliu Date: Fri, 10 Apr 2020 12:51:18 +0800 Subject: [PATCH 09/16] Add license file header --- sdk/build.gradle | 10 +- .../androidsdk/WebexTestRunner.java | 126 +++++++----------- .../androidsdk/auth/JWTAuthenticatorTest.java | 15 --- .../reachability/BackgroundChecker.java | 23 +++- .../reachability/ForegroundChecker.java | 22 +++ .../reachability/NetworkReachability.java | 22 +++ .../internal/reachability/ProxyHelpers.java | 22 +++ .../com/ciscowebex/androidsdk/WebexTest.java | 18 +-- 8 files changed, 145 insertions(+), 113 deletions(-) diff --git a/sdk/build.gradle b/sdk/build.gradle index 1597e070..f4befb9c 100755 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -65,9 +65,9 @@ android { defaultConfig { minSdkVersion 21 targetSdkVersion 27 - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "com.ciscowebex.androidsdk.WebexTestRunner" multiDexEnabled true - versionCode 1 + versionCode 2500 versionName moduleVersion buildConfigField "String", "BUILD_TIME", "\"${buildTime()}\"" buildConfigField "String", "BUILD_REVISION", "\"${revision()}\"" @@ -88,6 +88,8 @@ android { buildConfigField "String", "TEST_USER_NAME", getPropertyOrDefault('TEST_USER_NAME') buildConfigField "String", "TEST_USER_EMAIL", getPropertyOrDefault('TEST_USER_EMAIL') buildConfigField "String", "TEST_USER_PWD", getPropertyOrDefault('TEST_USER_PWD') + buildConfigField "String", "TEST_USER_PWD", getPropertyOrDefault('TEST_USER_PWD') + buildConfigField "String", "JWT", getPropertyOrDefault('JWT') } jenkins { initWith debug @@ -248,8 +250,8 @@ dependencies { implementation('joda-time:joda-time:2.10') testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support:support-annotations:28.0.0' - androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support:support-annotations:27.1.0' + androidTestImplementation 'com.android.support.test:runner:1.0.0' } static def buildTime() { diff --git a/sdk/src/androidTest/java/com/ciscowebex/androidsdk/WebexTestRunner.java b/sdk/src/androidTest/java/com/ciscowebex/androidsdk/WebexTestRunner.java index d3467a82..f7c900cb 100644 --- a/sdk/src/androidTest/java/com/ciscowebex/androidsdk/WebexTestRunner.java +++ b/sdk/src/androidTest/java/com/ciscowebex/androidsdk/WebexTestRunner.java @@ -25,31 +25,24 @@ import android.app.Application; import android.content.Context; -import android.os.Environment; +import android.os.Environment; +import android.os.Handler; import android.support.test.runner.AndroidJUnitRunner; -import com.facebook.drawee.backends.pipeline.Fresco; +import com.ciscowebex.androidsdk.auth.JWTAuthenticator; +import me.helloworld.utils.Checker; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.StringTokenizer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - - - public class WebexTestRunner extends AndroidJUnitRunner { - private static String SparkUserEmail = BuildConfig.TEST_USER_EMAIL; - private static String SparkUserName = BuildConfig.VERSION_NAME; - private static String SparkUserPwd = BuildConfig.TEST_USER_PWD; - private static String CLIENT_ID = BuildConfig.CLIENT_ID; - private static String CLIENT_SEC = BuildConfig.CLIENT_SEC; - private static String REDIRECT_URL = BuildConfig.REDIRECT_URL; - private static String SCOPE = BuildConfig.SCOPE; static Application application; static Webex webex; @@ -68,76 +61,57 @@ public Application newApplication(ClassLoader cl, String className, Context cont @Override public void callApplicationOnCreate(Application app) { super.callApplicationOnCreate(app); - Fresco.initialize(app.getApplicationContext()); - //new Handler().post(this::loginBySparkId); + new Handler().post(this::login); } - private void loginBySparkId() { - System.out.println("!!! loginBySparkId !!!"); -// String path = Environment.getExternalStorageDirectory().getPath(); -// //String path = application.getExternalFilesDir("login"); -// -// File file = new File(path, "login.txt"); -// if (file.exists()) { -// HashMap map = readKeyValueTxtToMap(file); -// SparkUserEmail = (String) map.get("SparkUserEmail"); -// SparkUserName = (String) map.get("SparkUserName"); -// SparkUserPwd = (String) map.get("SparkUserPwd"); -// CLIENT_ID = (String) map.get("CLIENT_ID"); -// CLIENT_SEC = (String) map.get("CLIENT_SEC"); -// REDIRECT_URL = (String) map.get("REDIRECT_URL"); -// SCOPE = (String) map.get("SCOPE"); -// } else { -// System.out.println("!!! login file is not exist !!!"); -// } -// System.out.println("Test User:" + SparkUserEmail); -// -// OAuthTestUserAuthenticator auth = new OAuthTestUserAuthenticator(CLIENT_ID, CLIENT_SEC, SCOPE, REDIRECT_URL, -// SparkUserEmail, SparkUserName, SparkUserPwd); -// webex = new Webex(application, auth); -// final CountDownLatch signal = new CountDownLatch(1); -// auth.authorize(result -> { -// if (result.isSuccessful()) { -// System.out.println("loginBySparkId isSuccessful!"); -// } else { -// System.out.println("loginBySparkId failed! " + result.getError().toString()); -// System.exit(-1); -// } -// signal.countDown(); -// }); -// -// try { -// signal.await(60, TimeUnit.SECONDS); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } + private void login() { + String jwt = BuildConfig.JWT; + if (Checker.isEmpty(jwt)) { + jwt = System.getProperty("JWT"); + } + System.out.println("!!! login !!! " + jwt); + JWTAuthenticator authenticator = new JWTAuthenticator(); + authenticator.authorize(jwt); + webex = new Webex(application, authenticator); + final CountDownLatch signal = new CountDownLatch(1); + authenticator.getToken(result -> { + if (result.isSuccessful()) { + System.out.println("login isSuccessful!"); + } else { + System.out.println("login failed! " + result.getError()); + System.exit(-1); + } + signal.countDown(); + }); + + try { + signal.await(60, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } } - private HashMap readKeyValueTxtToMap(File file) { - while (true) { - final HashMap keyValueMap = new HashMap(); - while (true) { - try { - final InputStream open = new FileInputStream(file); - final byte[] readArray = new byte[open.available()]; - open.read(readArray); - open.close(); - final StringTokenizer allLine = new StringTokenizer(new String(readArray, "UTF-8"), "\r\n"); - while (allLine.hasMoreTokens()) { - final StringTokenizer oneLine = new StringTokenizer(allLine.nextToken(), "="); - final String leftKey = oneLine.nextToken(); - if (!oneLine.hasMoreTokens()) { - break; - } - final String rightValue = oneLine.nextToken(); - keyValueMap.put(leftKey, rightValue); + private HashMap readKeyValueTxtToMap(File file) { + final HashMap keyValueMap = new HashMap<>(); + try { + final InputStream open = new FileInputStream(file); + final byte[] readArray = new byte[open.available()]; + open.read(readArray); + open.close(); + final StringTokenizer allLine = new StringTokenizer(new String(readArray, StandardCharsets.UTF_8), "\r\n"); + while (allLine.hasMoreTokens()) { + final StringTokenizer oneLine = new StringTokenizer(allLine.nextToken(), "="); + final String leftKey = oneLine.nextToken(); + if (!oneLine.hasMoreTokens()) { + break; } - return keyValueMap; - } catch (IOException e) { - e.printStackTrace(); - return keyValueMap; + final String rightValue = oneLine.nextToken(); + keyValueMap.put(leftKey, rightValue); } + return keyValueMap; + } catch (IOException e) { + e.printStackTrace(); + return keyValueMap; } - } } } diff --git a/sdk/src/androidTest/java/com/ciscowebex/androidsdk/auth/JWTAuthenticatorTest.java b/sdk/src/androidTest/java/com/ciscowebex/androidsdk/auth/JWTAuthenticatorTest.java index 6787c163..711246f2 100644 --- a/sdk/src/androidTest/java/com/ciscowebex/androidsdk/auth/JWTAuthenticatorTest.java +++ b/sdk/src/androidTest/java/com/ciscowebex/androidsdk/auth/JWTAuthenticatorTest.java @@ -22,30 +22,15 @@ package com.ciscowebex.androidsdk.auth; -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import com.ciscowebex.androidsdk.Webex; -import com.github.benoitdion.ln.DebugLn; -import com.github.benoitdion.ln.Ln; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class JWTAuthenticatorTest { - private String auth_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbmRyb2lkX3Rlc3R1c2VyXzEiLCJuYW1lIjoiQW5kcm9pZFRlc3RVc2VyMSIsImlzcyI6ImNkNWM5YWY3LThlZDMtNGUxNS05NzA1LTAyNWVmMzBiMWI2YSJ9.eJ99AY9iNDhG4HjDJsY36wgqOnNQSes_PIu0DKBHBzs"; @Test public void test() { - Context context = InstrumentationRegistry.getTargetContext(); - JWTAuthenticator authenticator = new JWTAuthenticator(); - authenticator.authorize("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNeUpUVzEiLCJuYW1lIjoiTXlKVFcxIiwiaXNzIjoiWTJselkyOXpjR0Z5YXpvdkwzVnpMMDlTUjBGT1NWcEJWRWxQVGk4eU1EVXlNV001WVMwNU1qVXlMVFF6WkRNdE9EUmtNQzAzTUdJMU1HUTJOMkV6WlRjIiwiZXhwIjoxNjAyMTI5NzUyfQ.Exu1Wg-TTzm_zR6BhZMtMcIOExKoTEjLwUOK767lmfo"); - - try { - Thread.sleep(100000); - } catch (InterruptedException e) { - e.printStackTrace(); - } } } \ No newline at end of file diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java index ceb1b621..80be83d8 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java @@ -1,3 +1,25 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.internal.reachability; import android.app.Application; @@ -8,7 +30,6 @@ import android.os.PowerManager; import com.ciscowebex.androidsdk.BuildConfig; import com.ciscowebex.androidsdk.internal.queue.Scheduler; -import com.ciscowebex.androidsdk.phone.Phone; import com.ciscowebex.androidsdk.utils.LoggingLock; import com.github.benoitdion.ln.Ln; diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ForegroundChecker.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ForegroundChecker.java index 2ed644a7..658e87ca 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ForegroundChecker.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ForegroundChecker.java @@ -1,3 +1,25 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.internal.reachability; import android.app.Activity; diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java index d21565e7..a8d8eceb 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java @@ -1,3 +1,25 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.internal.reachability; import android.content.BroadcastReceiver; diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ProxyHelpers.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ProxyHelpers.java index 1d48c421..5acf8321 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ProxyHelpers.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/ProxyHelpers.java @@ -1,3 +1,25 @@ +/* + * Copyright 2016-2020 Cisco Systems Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.ciscowebex.androidsdk.internal.reachability; import com.ciscowebex.androidsdk.utils.Utils; diff --git a/sdk/src/test/java/com/ciscowebex/androidsdk/WebexTest.java b/sdk/src/test/java/com/ciscowebex/androidsdk/WebexTest.java index 06c4d5cc..26f0271f 100644 --- a/sdk/src/test/java/com/ciscowebex/androidsdk/WebexTest.java +++ b/sdk/src/test/java/com/ciscowebex/androidsdk/WebexTest.java @@ -1,26 +1,10 @@ package com.ciscowebex.androidsdk; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; import org.junit.Test; - -import com.ciscowebex.androidsdk.auth.JWTAuthenticator; - -import java.util.Map; - public class WebexTest { - private String auth_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbmRyb2lkX3Rlc3R1c2VyXzEiLCJuYW1lIjoiQW5kcm9pZFRlc3RVc2VyMSIsImlzcyI6ImNkNWM5YWY3LThlZDMtNGUxNS05NzA1LTAyNWVmMzBiMWI2YSJ9.eJ99AY9iNDhG4HjDJsY36wgqOnNQSes_PIu0DKBHBzs"; - @Test - public void test() throws InterruptedException { - System.out.println("123"); - - Map ret = new Gson().fromJson("", new TypeToken>(){}.getType()); - - System.out.println(ret); - - + public void test() { } } \ No newline at end of file From c861819ed029d46c0ea3097355ab4c37fa466c2b Mon Sep 17 00:00:00 2001 From: kliu Date: Fri, 10 Apr 2020 13:32:54 +0800 Subject: [PATCH 10/16] Move some build params to local.properties --- gradle.properties | 1 + sdk/build.gradle | 81 ++++++++++++++++++++++++----------------------- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/gradle.properties b/gradle.properties index 6716d028..3c9ee633 100755 --- a/gradle.properties +++ b/gradle.properties @@ -17,3 +17,4 @@ org.gradle.daemon=true MULTIDEX_VERSION = 1.0.1 JODA_VERSION = 2.9.9 + diff --git a/sdk/build.gradle b/sdk/build.gradle index f4befb9c..8d89c8a3 100755 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -10,6 +10,7 @@ ext { moduleGroupId = 'com.ciscowebex' moduleArtifactId = 'androidsdk' moduleVersion = '2.5.0-SNAPSHOT' + moduleVersionCode = 25000 moduleDescription = 'Cisco Webex SDK for Android' moduleSiteUrl = 'https://developer.webex.com/getting-started.html' moduleProjectUrl = 'https://github.com/webex/webex-android-sdk' @@ -25,38 +26,12 @@ ext { moduleDeveloperOrganizationURL = 'https://www.webex.com/' } -kotlin { -} - -jacoco { - toolVersion = "0.7.5+" +Properties properties = new Properties() +if (project.rootProject.file('local.properties').canRead()) { + properties.load(project.rootProject.file("local.properties").newDataInputStream()) } -task jacocoTestReport(type: JacocoReport, dependsOn: "testDebugUnitTest") { - group = "Reporting" - description = "Generate Jacoco coverage reports" - - classDirectories = fileTree( - dir: '../sdk/build/intermediates/classes/debug', - excludes: ['**/R.class', - '**/R$*.class', - '**/*$ViewInjector*.*', - '**/BuildConfig.*', - '**/Manifest*.*'] - ) - - def coverageSourceDirs = ['../sdk/src/main/java'] - additionalSourceDirs = files(coverageSourceDirs) - sourceDirectories = files(coverageSourceDirs) - executionData = fileTree(dir: "../sdk", includes: [ - "jacoco/testDebugUnitTest.exec", - "outputs/code-coverage/connected/*.ec" - ]) - - reports { - xml.enabled = true - html.enabled = true - } +kotlin { } android { @@ -67,8 +42,9 @@ android { targetSdkVersion 27 testInstrumentationRunner "com.ciscowebex.androidsdk.WebexTestRunner" multiDexEnabled true - versionCode 2500 + versionCode moduleVersionCode versionName moduleVersion + buildConfigField "String", "BUILD_TIME", "\"${buildTime()}\"" buildConfigField "String", "BUILD_REVISION", "\"${revision()}\"" buildConfigField "boolean", "INTEGRATION_TEST", "false" @@ -81,15 +57,7 @@ android { minifyEnabled false } debug { - buildConfigField "String", "CLIENT_ID", getPropertyOrDefault('CLIENT_ID') - buildConfigField "String", "CLIENT_SEC", getPropertyOrDefault('CLIENT_SEC') - buildConfigField "String", "REDIRECT_URL", getPropertyOrDefault('REDIRECT_URL') - buildConfigField "String", "SCOPE", getPropertyOrDefault('SCOPE') - buildConfigField "String", "TEST_USER_NAME", getPropertyOrDefault('TEST_USER_NAME') - buildConfigField "String", "TEST_USER_EMAIL", getPropertyOrDefault('TEST_USER_EMAIL') - buildConfigField "String", "TEST_USER_PWD", getPropertyOrDefault('TEST_USER_PWD') - buildConfigField "String", "TEST_USER_PWD", getPropertyOrDefault('TEST_USER_PWD') - buildConfigField "String", "JWT", getPropertyOrDefault('JWT') + buildConfigField "String", "JWT", properties.get("JWT", "") } jenkins { initWith debug @@ -258,6 +226,8 @@ static def buildTime() { return new Date().format("yyyy_MM_dd_HH_mm_ss") } + + def revision() { def code = new ByteArrayOutputStream() exec { @@ -311,3 +281,34 @@ task javadocJar(type: Jar, dependsOn: javadoc) { classifier = 'javadoc' from javadoc.destinationDir } + +jacoco { + toolVersion = "0.7.5+" +} + +task jacocoTestReport(type: JacocoReport, dependsOn: "testDebugUnitTest") { + group = "Reporting" + description = "Generate Jacoco coverage reports" + + classDirectories = fileTree( + dir: '../sdk/build/intermediates/classes/debug', + excludes: ['**/R.class', + '**/R$*.class', + '**/*$ViewInjector*.*', + '**/BuildConfig.*', + '**/Manifest*.*'] + ) + + def coverageSourceDirs = ['../sdk/src/main/java'] + additionalSourceDirs = files(coverageSourceDirs) + sourceDirectories = files(coverageSourceDirs) + executionData = fileTree(dir: "../sdk", includes: [ + "jacoco/testDebugUnitTest.exec", + "outputs/code-coverage/connected/*.ec" + ]) + + reports { + xml.enabled = true + html.enabled = true + } +} From 242f7f84868b516ba8a3f2714f8261e237597f81 Mon Sep 17 00:00:00 2001 From: kliu Date: Fri, 10 Apr 2020 16:00:52 +0800 Subject: [PATCH 11/16] Update javadoc --- .../main/java/com/ciscowebex/androidsdk/message/Message.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java b/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java index 46aeed70..5a322bb2 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/message/Message.java @@ -54,7 +54,7 @@ public static Draft draft(Text text) { } /** - * Encapsulating the content will be post. + * Encapsulating the content will be post. A draft is created by {@link Message#draft(Text)}} * * @since 2.5.0 */ From 57bcdf6b60f6a47ca9a84aa2e599ee2cc9790c2b Mon Sep 17 00:00:00 2001 From: kliu Date: Fri, 10 Apr 2020 17:44:26 +0800 Subject: [PATCH 12/16] Fix call type for 1v1 call with 1v1 space id --- .../internal/reachability/BackgroundChecker.java | 12 +++++------- .../androidsdk/phone/internal/LocusResponse.java | 9 +-------- .../androidsdk/phone/internal/PhoneImpl.java | 8 ++++---- .../ciscowebex/androidsdk/utils/http/HttpClient.java | 2 +- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java index 80be83d8..8893d2ee 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java @@ -108,7 +108,7 @@ public boolean tryForeground() { try { if (isInactive()) { listener.onTransition(true); - Ln.i("TRY BG->FG: transition"); + Ln.d("TRY BG->FG: transition"); isInactive = false; activenessCondition.signalAll(); ret = true; @@ -127,7 +127,7 @@ public boolean tryBackground() { try { if (isInBackground()) { isInactive = true; - Ln.i("TRY FG->BG: transition"); + Ln.d("TRY FG->BG: transition"); listener.onTransition(false); ret = true; } @@ -140,23 +140,21 @@ public boolean tryBackground() { } private void foregroundActivityDetected() { - Ln.d("ForegroundActivityDetected"); syncLock.lock(); try { if (isInactive()) { listener.onTransition(true); - Ln.i("BG->FG: transition"); + Ln.d("BG->FG: transition"); isInactive = false; activenessCondition.signalAll(); } if (isInBackground()) { isInactive = true; - Ln.i("FG->BG: transition"); + Ln.d("FG->BG: transition"); listener.onTransition(false); } cancelChecker(); checker = Scheduler.schedule(() -> { - Ln.d("ForegroundActivityDetected: " + isInBackground()); if (isInBackground()) { isInactive = true; Ln.d("FG->BG: transition"); @@ -220,7 +218,7 @@ private void logBatteryStatus() { int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); int batteryPct = (int) (100 * level / (float) scale); - Ln.i("Battery percentage = %d, charging = %b", batteryPct, isCharging); + Ln.d("Battery percentage = %d, charging = %b", batteryPct, isCharging); } } catch (Exception ex) { Ln.w(ex); diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/LocusResponse.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/LocusResponse.java index c74f2d66..28da71b1 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/LocusResponse.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/LocusResponse.java @@ -32,28 +32,21 @@ public interface LocusResponse { class Call implements LocusResponse { - private boolean group; private Device device; private MediaSession session; private LocusModel locus; private CompletionHandler callback; - public Call(boolean isGroup, - Device device, + public Call(Device device, MediaSession session, LocusModel model, CompletionHandler callback) { - this.group = isGroup; this.device = device; this.session = session; this.locus = model; this.callback = callback; } - public boolean isGroup() { - return group; - } - public Device getDevice() { return device; } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java index 292e85d7..c0db5eff 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java @@ -265,7 +265,7 @@ public void deregister(@NonNull CompletionHandler callback) { callback.onComplete(ResultImpl.error("Already unregistering")); return; } - state = State.UNREGISTERED; + state = State.UNREGISTERING; Ln.i("Unregistering"); UIEventHandler.get().unregisterUIEventHandler(context); Queue.serial.run(new UnregisterOperation(authenticator, device, result -> { @@ -375,7 +375,7 @@ public void onMediaPermission(boolean permission) { Queue.serial.yield(); return; } - doLocusResponse(new LocusResponse.Call(target.isGroup(), device, session, callResult.getData(), outgoing.getCallback()), Queue.serial); + doLocusResponse(new LocusResponse.Call(device, session, callResult.getData(), outgoing.getCallback()), Queue.serial); }); } else { @@ -392,7 +392,7 @@ public void onMediaPermission(boolean permission) { Queue.serial.yield(); return; } - doLocusResponse(new LocusResponse.Call(target.isGroup(), device, session, joinResult.getData(), outgoing.getCallback()), Queue.serial); + doLocusResponse(new LocusResponse.Call(device, session, joinResult.getData(), outgoing.getCallback()), Queue.serial); }); }); } @@ -879,7 +879,7 @@ private void doLocusResponse(LocusResponse response, Queue queue) { if (response instanceof LocusResponse.Call) { LocusModel model = ((LocusResponse.Call) response).getLocus(); Ln.d("Connecting call: " + model.getCallUrl()); - CallImpl call = new CallImpl(model, this, device, ((LocusResponse.Call) response).getSession(), Call.Direction.OUTGOING, ((LocusResponse.Call) response).isGroup()); + CallImpl call = new CallImpl(model, this, device, ((LocusResponse.Call) response).getSession(), Call.Direction.OUTGOING, !model.isOneOnOne()); if (call.isStatusIllegal()) { Ln.d("The previous session did not end"); Queue.main.run(() -> { diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/HttpClient.java b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/HttpClient.java index fe74fe63..1923049a 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/HttpClient.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/utils/http/HttpClient.java @@ -35,7 +35,7 @@ public class HttpClient { - private static final int MAX_LENGTH = 2048; + private static final int MAX_LENGTH = 1024; private static HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(message -> { if (message.length() > MAX_LENGTH) { From 3b2aaca0f83e8bac4ffebd33d670455c49ab5e35 Mon Sep 17 00:00:00 2001 From: kliu Date: Fri, 10 Apr 2020 17:45:54 +0800 Subject: [PATCH 13/16] Fix url path for list space --- .../ciscowebex/androidsdk/space/internal/SpaceClientImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/SpaceClientImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/SpaceClientImpl.java index a46f13d9..b8228d7a 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/SpaceClientImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/space/internal/SpaceClientImpl.java @@ -78,7 +78,7 @@ else if (activity.getVerb() == ActivityModel.Verb.update) { @Override public void list(@Nullable String teamId, int max, @Nullable Space.SpaceType type, @Nullable SortBy sortBy, @NonNull CompletionHandler> handler) { - Service.Hydra.get("room") + Service.Hydra.get("rooms") .with("teamId", teamId) .with("type", type == null ? null : type.serializedName()) .with("sortBy", sortBy == null ? null : sortBy.serializedName()) From 46abe9256e0814196d217515d5836746d13fa56f Mon Sep 17 00:00:00 2001 From: kliu Date: Fri, 10 Apr 2020 18:36:57 +0800 Subject: [PATCH 14/16] Callback user app in main thread --- .../internal/mercury/MercuryService.java | 5 +- .../reachability/BackgroundChecker.java | 1 + .../reachability/NetworkReachability.java | 13 ++++- .../androidsdk/phone/internal/PhoneImpl.java | 48 ++++++++----------- 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryService.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryService.java index 4e30c367..9be1405f 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryService.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/mercury/MercuryService.java @@ -107,7 +107,7 @@ public void connect(String url, Closure closure) { }); } - public void disconnect() { + public void disconnect(boolean clear) { queue.run(() -> { connected = false; resetReconnect(); @@ -120,6 +120,9 @@ public void disconnect() { } websocket = null; } + if (clear) { + url = null; + } }); } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java index 8893d2ee..0192fcb8 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/BackgroundChecker.java @@ -77,6 +77,7 @@ public void stop() { syncLock.lock(); try { running = false; + network.stop(); cancelChecker(); } finally { syncLock.unlock(); diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java index a8d8eceb..b2328809 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/internal/reachability/NetworkReachability.java @@ -60,7 +60,7 @@ public NetworkReachability(Context context, NetworkReachabilityObserver observer } public void onReceive(Context context, Intent intent) { - update(); + asyncUpdateNetworkConnectivity(); } public static IntentFilter getIntentFilter() { @@ -76,6 +76,13 @@ public void start() { update(); } + public void stop() { + if (updateNetworkState != null) { + updateNetworkState.cancel(); + updateNetworkState = null; + } + } + public boolean isNetworkConnected() { if (currentNetworkConnectionStatus.isConnected()) { NetworkInfo info = connectivityManager.getActiveNetworkInfo(); @@ -91,6 +98,7 @@ public boolean isBehindProxy() { public void update() { if (updateNetworkState != null) { updateNetworkState.cancel(); + updateNetworkState = null; } updateNetworkState = Scheduler.schedule(this::asyncUpdateNetworkConnectivity, 20000, true); } @@ -106,6 +114,7 @@ protected void asyncUpdateNetworkConnectivity() { if (info == null) { currentNetworkConnectionStatus = new NetworkConnectionStatus(false); if (oldIsConnected) { + Ln.i("End status not exist"); observer.onReachabilityChanged(false); } return; @@ -137,7 +146,7 @@ protected void asyncUpdateNetworkConnectivity() { } if (oldIsConnected != isConnected) { - Ln.i("Different start and end states, sending event"); + Ln.i("Different start and end states"); observer.onReachabilityChanged(isConnected); } } diff --git a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java index c0db5eff..616e2306 100644 --- a/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java +++ b/sdk/src/main/java/com/ciscowebex/androidsdk/phone/internal/PhoneImpl.java @@ -142,14 +142,9 @@ public void setChecker(BackgroundChecker checker) { @Override public void register(@NonNull CompletionHandler callback) { Queue.main.run(() -> { - if (state == State.REGISTERING) { - Ln.w("Already registering"); - callback.onComplete(ResultImpl.error("Already registering")); - return; - } - if (state == State.UNREGISTERING) { - Ln.w("Already unregistering"); - callback.onComplete(ResultImpl.error("Already unregistering")); + if (state != State.UNREGISTERED) { + Ln.w("Device is not unregistered"); + callback.onComplete(ResultImpl.error("Device is not unregistered")); return; } state = State.REGISTERING; @@ -234,7 +229,7 @@ public void onTransition(boolean foreground) { if (foreground) { mercury.tryReconnect(); } else { - mercury.disconnect(); + mercury.disconnect(false); } } for (CallImpl call : calls.values()) { @@ -255,14 +250,9 @@ public void onTransition(boolean foreground) { @Override public void deregister(@NonNull CompletionHandler callback) { Queue.main.run(() -> { - if (state == State.REGISTERING) { - Ln.w("Already registering"); - callback.onComplete(ResultImpl.error("Already registering")); - return; - } - if (state == State.UNREGISTERING) { - Ln.w("Already unregistering"); - callback.onComplete(ResultImpl.error("Already unregistering")); + if (state != State.REGISTERED) { + Ln.w("Device is not registered"); + callback.onComplete(ResultImpl.error("Device is not registered")); return; } state = State.UNREGISTERING; @@ -270,18 +260,18 @@ public void deregister(@NonNull CompletionHandler callback) { UIEventHandler.get().unregisterUIEventHandler(context); Queue.serial.run(new UnregisterOperation(authenticator, device, result -> { Ln.i("Unregistered"); - mercury.disconnect(); Queue.main.run(() -> { reachability.clear(); if (checker != null) { checker.stop(); } }); + mercury.disconnect(true); device = null; credentials = null; Settings.shared.clear(Device.DEVICE_URL); state = State.UNREGISTERED; - callback.onComplete(result); + Queue.main.run(() -> callback.onComplete(result)); Queue.serial.yield(); })); }); @@ -300,20 +290,20 @@ public void dial(@NonNull String dialString, @NonNull MediaOption option, @NonNu stopPreview(); if (callContext != null) { Ln.w("Already calling"); - callback.onComplete(ResultImpl.error("Already calling")); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Already calling"))); Queue.serial.yield(); return; } if (device == null) { Ln.e("Unregistered device"); - callback.onComplete(ResultImpl.error("Unregistered device")); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Unregistered device"))); Queue.serial.yield(); return; } for (CallImpl call : getCalls()) { if (!call.isGroup() || (call.isGroup() && call.getStatus() == Call.CallStatus.CONNECTED)) { Ln.e("There are other active calls"); - callback.onComplete(ResultImpl.error("There are other active calls")); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("There are other active calls"))); Queue.serial.yield(); return; } @@ -436,19 +426,19 @@ public void onScreenCapturePermission(Intent permission) { callContext = null; if (call.getMedia() == null || !call.getMedia().hasSharing()) { Ln.e("Media option unsupport content share"); - callback.onComplete(ResultImpl.error("Media option unsupport content share")); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Media option unsupport content share"))); Queue.serial.yield(); return; } if (call.isSharingFromThisDevice()) { Ln.e("Already shared by self"); - callback.onComplete(ResultImpl.error("Already shared by self")); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Already shared by self"))); Queue.serial.yield(); return; } if (call.getStatus() != Call.CallStatus.CONNECTED) { Ln.e("No active call"); - callback.onComplete(ResultImpl.error("No active call")); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("No active call"))); Queue.serial.yield(); return; } @@ -457,12 +447,13 @@ public void onScreenCapturePermission(Intent permission) { String url = mediaShare.getUrl(); if (url == null) { Ln.e("Unsupport media share"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("No MediaShare url"))); Queue.serial.yield(); return; } service.update(mediaShare, url, device, result -> { if (result.getError() != null) { - callback.onComplete(ResultImpl.error(result.getError())); + Queue.main.run(() -> callback.onComplete(ResultImpl.error(result.getError()))); Queue.serial.yield(); return; } @@ -834,13 +825,13 @@ void stopSharing(CallImpl call, CompletionHandler callback) { Queue.serial.run(() -> { if (call.getMedia() == null || !call.getMedia().hasSharing()) { Ln.e("Media option unsupport content share"); - callback.onComplete(ResultImpl.error("Media option unsupport content share")); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Media option unsupport content share"))); Queue.serial.yield(); return; } if (!call.isSharingFromThisDevice()) { Ln.e("Local share screen not start"); - callback.onComplete(ResultImpl.error("Local share screen not start")); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Local share screen not start"))); Queue.serial.yield(); return; } @@ -849,6 +840,7 @@ void stopSharing(CallImpl call, CompletionHandler callback) { String url = mediaShare.getUrl(); if (url == null) { Ln.e("Unsupport media share"); + Queue.main.run(() -> callback.onComplete(ResultImpl.error("Miss media share url"))); Queue.serial.yield(); return; } From dd85fd9ad2bc8d433ec7cfa095cde948d1f97515 Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 13 Apr 2020 09:58:37 +0800 Subject: [PATCH 15/16] properties.get cause build failed in AndroidStudio --- sdk/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/build.gradle b/sdk/build.gradle index 8d89c8a3..40a0dbe7 100755 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -57,7 +57,7 @@ android { minifyEnabled false } debug { - buildConfigField "String", "JWT", properties.get("JWT", "") + buildConfigField "String", "JWT", getPropertyOrDefault("JWT") } jenkins { initWith debug From 52253287b8d02cffd8f30a24ca9d339ba74e161b Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 13 Apr 2020 10:09:54 +0800 Subject: [PATCH 16/16] Create release branch. --- sdk/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/build.gradle b/sdk/build.gradle index 40a0dbe7..0b4041d8 100755 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -9,7 +9,7 @@ ext { moduleName = 'Cisco Webex Android SDK' moduleGroupId = 'com.ciscowebex' moduleArtifactId = 'androidsdk' - moduleVersion = '2.5.0-SNAPSHOT' + moduleVersion = '2.5.0' moduleVersionCode = 25000 moduleDescription = 'Cisco Webex SDK for Android' moduleSiteUrl = 'https://developer.webex.com/getting-started.html'