1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.ims.rcs.uce.presence.pidfparser.capabilities;
18 
19 import android.annotation.StringDef;
20 import android.text.TextUtils;
21 
22 import com.android.ims.rcs.uce.presence.pidfparser.ElementBase;
23 
24 import java.io.IOException;
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.List;
30 
31 import org.xmlpull.v1.XmlPullParser;
32 import org.xmlpull.v1.XmlPullParserException;
33 import org.xmlpull.v1.XmlSerializer;
34 
35 /**
36  * The "duplex" element indicates how the communication service send and receive media. It can
37  * contain two elements: "supported" and "notsupported." The supported and
38  * nonsupported elements can contains four elements: "full", "half", "receive-only" and
39  * "send-only".
40  */
41 public class Duplex extends ElementBase {
42     /** The name of the duplex element */
43     public static final String ELEMENT_NAME = "duplex";
44 
45     /** The name of the supported element */
46     public static final String ELEMENT_SUPPORTED = "supported";
47 
48     /** The name of the notsupported element */
49     public static final String ELEMENT_NOT_SUPPORTED = "notsupported";
50 
51     /** The device can simultaneously send and receive media */
52     public static final String DUPLEX_FULL = "full";
53 
54     /** The service can alternate between sending and receiving media.*/
55     public static final String DUPLEX_HALF = "half";
56 
57     /** The service can only receive media */
58     public static final String DUPLEX_RECEIVE_ONLY = "receive-only";
59 
60     /** The service can only send media */
61     public static final String DUPLEX_SEND_ONLY = "send-only";
62 
63     @StringDef(value = {
64             DUPLEX_FULL,
65             DUPLEX_HALF,
66             DUPLEX_RECEIVE_ONLY,
67             DUPLEX_SEND_ONLY})
68     @Retention(RetentionPolicy.SOURCE)
69     public @interface DuplexType {}
70 
71     private final List<String> mSupportedTypeList = new ArrayList<>();
72     private final List<String> mNotSupportedTypeList = new ArrayList<>();
73 
Duplex()74     public Duplex() {
75     }
76 
77     @Override
initNamespace()78     protected String initNamespace() {
79         return CapsConstant.NAMESPACE;
80     }
81 
82     @Override
initElementName()83     protected String initElementName() {
84         return ELEMENT_NAME;
85     }
86 
addSupportedType(@uplexType String type)87     public void addSupportedType(@DuplexType String type) {
88         mSupportedTypeList.add(type);
89     }
90 
getSupportedTypes()91     public List<String> getSupportedTypes() {
92         return Collections.unmodifiableList(mSupportedTypeList);
93     }
94 
addNotSupportedType(@uplexType String type)95     public void addNotSupportedType(@DuplexType String type) {
96         mNotSupportedTypeList.add(type);
97     }
98 
getNotSupportedTypes()99     public List<String> getNotSupportedTypes() {
100         return Collections.unmodifiableList(mNotSupportedTypeList);
101     }
102 
103     @Override
serialize(XmlSerializer serializer)104     public void serialize(XmlSerializer serializer) throws IOException {
105         if (mSupportedTypeList.isEmpty() && mNotSupportedTypeList.isEmpty()) {
106             return;
107         }
108         String namespace = getNamespace();
109         String elementName = getElementName();
110         serializer.startTag(namespace, elementName);
111         for (String supportedType : mSupportedTypeList) {
112             serializer.startTag(namespace, ELEMENT_SUPPORTED);
113             serializer.startTag(namespace, supportedType);
114             serializer.endTag(namespace, supportedType);
115             serializer.endTag(namespace, ELEMENT_SUPPORTED);
116         }
117         for (String notSupportedType : mNotSupportedTypeList) {
118             serializer.startTag(namespace, ELEMENT_NOT_SUPPORTED);
119             serializer.startTag(namespace, notSupportedType);
120             serializer.endTag(namespace, notSupportedType);
121             serializer.endTag(namespace, ELEMENT_NOT_SUPPORTED);
122         }
123         serializer.endTag(namespace, elementName);
124     }
125 
126     @Override
parse(XmlPullParser parser)127     public void parse(XmlPullParser parser) throws IOException, XmlPullParserException {
128         String namespace = parser.getNamespace();
129         String name = parser.getName();
130 
131         if (!verifyParsingElement(namespace, name)) {
132             throw new XmlPullParserException("Incorrect element: " + namespace + ", " + name);
133         }
134 
135         // Move to the next event.
136         int eventType = parser.next();
137 
138         while(!(eventType == XmlPullParser.END_TAG
139                 && getNamespace().equals(parser.getNamespace())
140                 && getElementName().equals(parser.getName()))) {
141 
142             if (eventType == XmlPullParser.START_TAG) {
143                 String tagName = parser.getName();
144 
145                 if (ELEMENT_SUPPORTED.equals(tagName)) {
146                     String duplexType = getDuplexType(parser);
147                     if (!TextUtils.isEmpty(duplexType)) {
148                         addSupportedType(duplexType);
149                     }
150                 } else if (ELEMENT_NOT_SUPPORTED.equals(tagName)) {
151                     String duplexType = getDuplexType(parser);
152                     if (!TextUtils.isEmpty(duplexType)) {
153                         addNotSupportedType(duplexType);
154                     }
155                 }
156             }
157 
158             eventType = parser.next();
159 
160             // Leave directly if the event type is the end of the document.
161             if (eventType == XmlPullParser.END_DOCUMENT) {
162                 return;
163             }
164         }
165     }
166 
getDuplexType(XmlPullParser parser)167     private String getDuplexType(XmlPullParser parser) throws IOException, XmlPullParserException {
168         // Move to the next event
169         int eventType = parser.next();
170 
171         String name = parser.getName();
172         if (eventType == XmlPullParser.START_TAG) {
173             if (DUPLEX_FULL.equals(name) ||
174                     DUPLEX_HALF.equals(name) ||
175                     DUPLEX_RECEIVE_ONLY.equals(name) ||
176                     DUPLEX_SEND_ONLY.equals(name)) {
177                 return name;
178             }
179         }
180         return null;
181     }
182 }
183