1/*
2 * Copyright (C) 2014 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
17package com.android.internal.telephony.test;
18
19import com.android.ims.ImsConferenceState;
20import com.android.internal.util.XmlUtils;
21
22import org.xmlpull.v1.XmlPullParser;
23import org.xmlpull.v1.XmlPullParserException;
24
25import android.os.Bundle;
26import android.util.Log;
27import android.util.Xml;
28
29import java.io.BufferedInputStream;
30import java.io.IOException;
31import java.io.InputStream;
32
33/**
34 * Implements a basic XML parser used to parse test IMS conference event packages which can be
35 * injected into the IMS framework via the {@link com.android.internal.telephony.TelephonyTester}.
36 * <pre>
37 * {@code
38 * <xml>
39 *     <participant>
40 *         <user>tel:+16505551212</user>
41 *         <display-text>Joe Q. Public</display-text>
42 *         <endpoint>sip:+16505551212@ims-test-provider.com</endpoint>
43 *         <status>connected</status>
44 *     </participant>
45 * </xml>
46 * }
47 * </pre>
48 * <p>
49 * Note: This XML format is similar to the information stored in the
50 * {@link com.android.ims.ImsConferenceState} parcelable.  The {@code status} values expected in the
51 * XML are those found in the {@code ImsConferenceState} class (e.g.
52 * {@link com.android.ims.ImsConferenceState#STATUS_CONNECTED}).
53 * <p>
54 * Place a file formatted similar to above in /data/data/com.android.phone/files/ and invoke the
55 * following command while you have an ongoing IMS call:
56 * <pre>
57 *     adb shell am broadcast
58 *          -a com.android.internal.telephony.TestConferenceEventPackage
59 *          -e filename test.xml
60 * </pre>
61 */
62public class TestConferenceEventPackageParser {
63    private static final String LOG_TAG = "TestConferenceEventPackageParser";
64    private static final String PARTICIPANT_TAG = "participant";
65
66    /**
67     * The XML input stream to parse.
68     */
69    private InputStream mInputStream;
70
71    /**
72     * Constructs an input of the conference event package parser for the given input stream.
73     *
74     * @param inputStream The input stream.
75     */
76    public TestConferenceEventPackageParser(InputStream inputStream) {
77        mInputStream = inputStream;
78    }
79
80    /**
81     * Parses the conference event package XML file and returns an
82     * {@link com.android.ims.ImsConferenceState} instance containing the participants described in
83     * the XML file.
84     *
85     * @return The {@link com.android.ims.ImsConferenceState} instance.
86     */
87    public ImsConferenceState parse() {
88        ImsConferenceState conferenceState = new ImsConferenceState();
89
90        XmlPullParser parser;
91        try {
92            parser = Xml.newPullParser();
93            parser.setInput(mInputStream, null);
94            parser.nextTag();
95
96            int outerDepth = parser.getDepth();
97            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
98                if (parser.getName().equals(PARTICIPANT_TAG)) {
99                    Log.v(LOG_TAG, "Found participant.");
100                    Bundle participant = parseParticipant(parser);
101                    conferenceState.mParticipants.put(participant.getString(
102                            ImsConferenceState.ENDPOINT), participant);
103                }
104            }
105        } catch (IOException | XmlPullParserException e) {
106            Log.e(LOG_TAG, "Failed to read test conference event package from XML file", e);
107            return null;
108        } finally {
109            try {
110                mInputStream.close();
111            } catch (IOException e) {
112                Log.e(LOG_TAG, "Failed to close test conference event package InputStream", e);
113                return null;
114            }
115        }
116
117        return conferenceState;
118    }
119
120    /**
121     * Parses a participant record from a conference event package XML file.
122     *
123     * @param parser The XML parser.
124     * @return {@link Bundle} containing the participant information.
125     */
126    private Bundle parseParticipant(XmlPullParser parser)
127            throws IOException, XmlPullParserException {
128        Bundle bundle = new Bundle();
129
130        String user = "";
131        String displayText = "";
132        String endpoint = "";
133        String status = "";
134
135        int outerDepth = parser.getDepth();
136        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
137            if (parser.getName().equals(ImsConferenceState.USER)) {
138                parser.next();
139                user = parser.getText();
140            } else if (parser.getName().equals(ImsConferenceState.DISPLAY_TEXT)) {
141                parser.next();
142                displayText = parser.getText();
143            }  else if (parser.getName().equals(ImsConferenceState.ENDPOINT)) {
144                parser.next();
145                endpoint = parser.getText();
146            }  else if (parser.getName().equals(ImsConferenceState.STATUS)) {
147                parser.next();
148                status = parser.getText();
149            }
150        }
151
152        Log.v(LOG_TAG, "User: "+user);
153        Log.v(LOG_TAG, "DisplayText: "+displayText);
154        Log.v(LOG_TAG, "Endpoint: "+endpoint);
155        Log.v(LOG_TAG, "Status: "+status);
156
157        bundle.putString(ImsConferenceState.USER, user);
158        bundle.putString(ImsConferenceState.DISPLAY_TEXT, displayText);
159        bundle.putString(ImsConferenceState.ENDPOINT, endpoint);
160        bundle.putString(ImsConferenceState.STATUS, status);
161
162        return bundle;
163    }
164}
165