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.pidf; 18 19 import android.annotation.NonNull; 20 import android.net.Uri; 21 import android.text.TextUtils; 22 import android.util.Log; 23 24 import com.android.ims.rcs.uce.presence.pidfparser.ElementBase; 25 import com.android.ims.rcs.uce.util.UceUtils; 26 import com.android.internal.annotations.VisibleForTesting; 27 28 import org.xmlpull.v1.XmlPullParser; 29 import org.xmlpull.v1.XmlPullParserException; 30 import org.xmlpull.v1.XmlSerializer; 31 32 import java.io.IOException; 33 import java.util.ArrayList; 34 import java.util.Collections; 35 import java.util.List; 36 37 /** 38 * The "present" element is the root element of an "application/pidf+xml" object. 39 */ 40 public class Presence extends ElementBase { 41 /** 42 * The presence element consists the following elements: 43 * 1: Any number (including 0) of <tuple> elements 44 * 2: Any number (including 0) of <note> elements 45 * 3: Any number of OPTIONAL extension elements from other namespaces. 46 */ 47 private static final String LOG_TAG = UceUtils.getLogPrefix() + "Presence"; 48 49 /** The name of this element */ 50 public static final String ELEMENT_NAME = "presence"; 51 52 private static final String ATTRIBUTE_NAME_ENTITY = "entity"; 53 54 // The presence element must have an "entity" attribute. 55 private String mEntity; 56 57 // The presence element contains any number of <tuple> elements 58 private final List<Tuple> mTupleList = new ArrayList<>(); 59 60 // The presence element contains any number of <note> elements; 61 private final List<Note> mNoteList = new ArrayList<>(); 62 Presence()63 public Presence() { 64 } 65 Presence(@onNull Uri contact)66 public Presence(@NonNull Uri contact) { 67 initEntity(contact); 68 } 69 initEntity(Uri contact)70 private void initEntity(Uri contact) { 71 mEntity = contact.toString(); 72 } 73 74 @VisibleForTesting setEntity(String entity)75 public void setEntity(String entity) { 76 mEntity = entity; 77 } 78 79 @Override initNamespace()80 protected String initNamespace() { 81 return PidfConstant.NAMESPACE; 82 } 83 84 @Override initElementName()85 protected String initElementName() { 86 return ELEMENT_NAME; 87 } 88 getEntity()89 public String getEntity() { 90 return mEntity; 91 } 92 addTuple(@onNull Tuple tuple)93 public void addTuple(@NonNull Tuple tuple) { 94 mTupleList.add(tuple); 95 } 96 getTupleList()97 public @NonNull List<Tuple> getTupleList() { 98 return Collections.unmodifiableList(mTupleList); 99 } 100 addNote(@onNull Note note)101 public void addNote(@NonNull Note note) { 102 mNoteList.add(note); 103 } 104 getNoteList()105 public @NonNull List<Note> getNoteList() { 106 return Collections.unmodifiableList(mNoteList); 107 } 108 109 @Override serialize(XmlSerializer serializer)110 public void serialize(XmlSerializer serializer) throws IOException { 111 String namespace = getNamespace(); 112 String elementName = getElementName(); 113 114 serializer.startTag(namespace, elementName); 115 // entity attribute 116 serializer.attribute(XmlPullParser.NO_NAMESPACE, ATTRIBUTE_NAME_ENTITY, mEntity); 117 118 // tuple elements 119 for (Tuple tuple : mTupleList) { 120 tuple.serialize(serializer); 121 } 122 123 // note elements 124 for (Note note : mNoteList) { 125 note.serialize(serializer); 126 } 127 serializer.endTag(namespace, elementName); 128 } 129 130 @Override parse(XmlPullParser parser)131 public void parse(XmlPullParser parser) throws IOException, XmlPullParserException { 132 String namespace = parser.getNamespace(); 133 String name = parser.getName(); 134 135 if (!verifyParsingElement(namespace, name)) { 136 throw new XmlPullParserException("Incorrect element: " + namespace + ", " + name); 137 } 138 139 mEntity = parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, ATTRIBUTE_NAME_ENTITY); 140 if (TextUtils.isEmpty(mEntity)) { 141 throw new XmlPullParserException("Entity uri of presence is empty"); 142 } 143 144 // Move to the next event. 145 int eventType = parser.next(); 146 147 while(!(eventType == XmlPullParser.END_TAG 148 && getNamespace().equals(parser.getNamespace()) 149 && getElementName().equals(parser.getName()))) { 150 151 if (eventType == XmlPullParser.START_TAG) { 152 String tagName = parser.getName(); 153 154 if (isTupleElement(eventType, tagName)) { 155 Tuple tuple = new Tuple(); 156 try { 157 // If one tuple encounters an xml exception, we must parse the other tuple 158 // and store valid information. 159 tuple.parse(parser); 160 } catch (XmlPullParserException e) { 161 e.printStackTrace(); 162 Log.w(LOG_TAG, "parse: Exception occurred during Tuple parsing."); 163 tuple.setMalformed(true); 164 } 165 mTupleList.add(tuple); 166 } else if (isNoteElement(eventType, tagName)) { 167 Note note = new Note(); 168 try { 169 note.parse(parser); 170 } catch (XmlPullParserException e) { 171 e.printStackTrace(); 172 Log.w(LOG_TAG, "parse: Exception occurred during Note parsing."); 173 } 174 mNoteList.add(note); 175 } 176 } 177 178 eventType = parser.next(); 179 180 // Leave directly if the event type is the end of the document. 181 if (eventType == XmlPullParser.END_DOCUMENT) { 182 return; 183 } 184 } 185 } 186 isTupleElement(int eventType, String name)187 private boolean isTupleElement(int eventType, String name) { 188 return (eventType == XmlPullParser.START_TAG && Tuple.ELEMENT_NAME.equals(name)) ? 189 true : false; 190 } 191 isNoteElement(int eventType, String name)192 private boolean isNoteElement(int eventType, String name) { 193 return (eventType == XmlPullParser.START_TAG && Note.ELEMENT_NAME.equals(name)) ? 194 true : false; 195 } 196 } 197