Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d4f1fe3 authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Implement test IMS conference event package harness.

Implement test conference event package intent receiver and parser which
allows the user to issue an intent to cause a test conference event
package file to be injected into the current ImsCall:

adb shell am broadcast
-a com.android.internal.telephony.TestConferenceEventPackage
-e filename test_filename.xml

Bug: 18119796
Change-Id: Ic51be9442ae5b991054ccfd7655c6efd76ffd8e0
parent 6137cc7b
Loading
Loading
Loading
Loading
+68 −1
Original line number Diff line number Diff line
@@ -23,18 +23,35 @@ import android.content.IntentFilter;
import android.os.Build;
import android.telephony.Rlog;

import com.android.internal.telephony.PhoneBase;
import com.android.ims.ImsCall;
import com.android.ims.ImsConferenceState;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
import com.android.internal.telephony.test.TestConferenceEventPackageParser;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * Telephony tester receives the following intents where {name} is the phone name
 *
 * adb shell am broadcast -a com.android.internal.telephony.{name}.action_detached
 * adb shell am broadcast -a com.android.internal.telephony.{name}.action_attached
 * adb shell am broadcast -a com.android.internal.telephony.TestConferenceEventPackage -e filename
 *      test_filename.xml
 */
public class TelephonyTester {
    private static final String LOG_TAG = "TelephonyTester";
    private static final boolean DBG = true;

    /**
     * Test-only intent used to send a test conference event package to the IMS framework.
     */
    private static final String ACTION_TEST_CONFERENCE_EVENT_PACKAGE =
            "com.android.internal.telephony.TestConferenceEventPackage";
    private static final String EXTRA_FILENAME = "filename";

    private PhoneBase mPhone;

    // The static intent receiver one for all instances and we assume this
@@ -50,6 +67,9 @@ public class TelephonyTester {
            } else if (action.equals(mPhone.getActionAttached())) {
                log("simulate attaching");
                mPhone.getServiceStateTracker().mAttachedRegistrants.notifyRegistrants();
            } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) {
                log("inject simulated conference event package");
                handleTestConferenceEventPackage(context, intent.getStringExtra(EXTRA_FILENAME));
            } else {
                if (DBG) log("onReceive: unknown action=" + action);
            }
@@ -68,6 +88,11 @@ public class TelephonyTester {
            filter.addAction(mPhone.getActionAttached());
            log("register for intent action=" + mPhone.getActionAttached());

            if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
                log("register for intent action=" + ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
                filter.addAction(ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
            }

            phone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone.getHandler());
        }
    }
@@ -81,4 +106,46 @@ public class TelephonyTester {
    private static void log(String s) {
        Rlog.d(LOG_TAG, s);
    }

    /**
     * Handles request to send a test conference event package to the active Ims call.
     *
     * @see com.android.internal.telephony.test.TestConferenceEventPackageParser
     * @param context The context.
     * @param fileName The name of the test conference event package file to read.
     */
    private void handleTestConferenceEventPackage(Context context, String fileName) {
        // Attempt to get the active IMS call before parsing the test XML file.
        ImsPhone imsPhone = (ImsPhone) mPhone.getImsPhone();
        if (imsPhone == null) {
            return;
        }

        ImsPhoneCall imsPhoneCall = imsPhone.getForegroundCall();
        if (imsPhoneCall == null) {
            return;
        }

        ImsCall imsCall = imsPhoneCall.getImsCall();
        if (imsCall == null) {
            return;
        }

        File packageFile = new File(context.getFilesDir(), fileName);
        final FileInputStream is;
        try {
            is = new FileInputStream(packageFile);
        } catch (FileNotFoundException ex) {
            log("Test conference event package file not found: " + packageFile.getAbsolutePath());
            return;
        }

        TestConferenceEventPackageParser parser = new TestConferenceEventPackageParser(is);
        ImsConferenceState imsConferenceState = parser.parse();
        if (imsConferenceState == null) {
            return;
        }

        imsCall.conferenceStateUpdated(imsConferenceState);
    }
}
+12 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.internal.telephony.imsphone;
import android.telephony.Rlog;
import android.telephony.DisconnectCause;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Connection;
@@ -228,7 +229,17 @@ public class ImsPhoneCall extends Call {
        }
    }

    /*package*/ ImsCall
    /**
     * Retrieves the {@link ImsCall} for the current {@link ImsPhoneCall}.
     * <p>
     * Marked as {@code VisibleForTesting} so that the
     * {@link com.android.internal.telephony.TelephonyTester} class can inject a test conference
     * event package into a regular ongoing IMS call.
     *
     * @return The {@link ImsCall}.
     */
    @VisibleForTesting
    public ImsCall
    getImsCall() {
        return (getFirstConnection() == null) ? null : getFirstConnection().getImsCall();
    }
+164 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.internal.telephony.test;

import com.android.ims.ImsConferenceState;
import com.android.internal.util.XmlUtils;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.os.Bundle;
import android.util.Log;
import android.util.Xml;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Implements a basic XML parser used to parse test IMS conference event packages which can be
 * injected into the IMS framework via the {@link com.android.internal.telephony.TelephonyTester}.
 * <pre>
 * {@code
 * <xml>
 *     <participant>
 *         <user>tel:+16505551212</user>
 *         <display-text>Joe Q. Public</display-text>
 *         <endpoint>sip:+16505551212@ims-test-provider.com</endpoint>
 *         <status>connected</status>
 *     </participant>
 * </xml>
 * }
 * </pre>
 * <p>
 * Note: This XML format is similar to the information stored in the
 * {@link com.android.ims.ImsConferenceState} parcelable.  The {@code status} values expected in the
 * XML are those found in the {@code ImsConferenceState} class (e.g.
 * {@link com.android.ims.ImsConferenceState#STATUS_CONNECTED}).
 * <p>
 * Place a file formatted similar to above in /data/data/com.android.phone/files/ and invoke the
 * following command while you have an ongoing IMS call:
 * <pre>
 *     adb shell am broadcast
 *          -a com.android.internal.telephony.TestConferenceEventPackage
 *          -e filename test.xml
 * </pre>
 */
public class TestConferenceEventPackageParser {
    private static final String LOG_TAG = "TestConferenceEventPackageParser";
    private static final String PARTICIPANT_TAG = "participant";

    /**
     * The XML input stream to parse.
     */
    private InputStream mInputStream;

    /**
     * Constructs an input of the conference event package parser for the given input stream.
     *
     * @param inputStream The input stream.
     */
    public TestConferenceEventPackageParser(InputStream inputStream) {
        mInputStream = inputStream;
    }

    /**
     * Parses the conference event package XML file and returns an
     * {@link com.android.ims.ImsConferenceState} instance containing the participants described in
     * the XML file.
     *
     * @return The {@link com.android.ims.ImsConferenceState} instance.
     */
    public ImsConferenceState parse() {
        ImsConferenceState conferenceState = new ImsConferenceState();

        XmlPullParser parser;
        try {
            parser = Xml.newPullParser();
            parser.setInput(mInputStream, null);
            parser.nextTag();

            int outerDepth = parser.getDepth();
            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                if (parser.getName().equals(PARTICIPANT_TAG)) {
                    Log.v(LOG_TAG, "Found participant.");
                    Bundle participant = parseParticipant(parser);
                    conferenceState.mParticipants.put(participant.getString(
                            ImsConferenceState.ENDPOINT), participant);
                }
            }
        } catch (IOException | XmlPullParserException e) {
            Log.e(LOG_TAG, "Failed to read test conference event package from XML file", e);
            return null;
        } finally {
            try {
                mInputStream.close();
            } catch (IOException e) {
                Log.e(LOG_TAG, "Failed to close test conference event package InputStream", e);
                return null;
            }
        }

        return conferenceState;
    }

    /**
     * Parses a participant record from a conference event package XML file.
     *
     * @param parser The XML parser.
     * @return {@link Bundle} containing the participant information.
     */
    private Bundle parseParticipant(XmlPullParser parser)
            throws IOException, XmlPullParserException {
        Bundle bundle = new Bundle();

        String user = "";
        String displayText = "";
        String endpoint = "";
        String status = "";

        int outerDepth = parser.getDepth();
        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
            if (parser.getName().equals(ImsConferenceState.USER)) {
                parser.next();
                user = parser.getText();
            } else if (parser.getName().equals(ImsConferenceState.DISPLAY_TEXT)) {
                parser.next();
                displayText = parser.getText();
            }  else if (parser.getName().equals(ImsConferenceState.ENDPOINT)) {
                parser.next();
                endpoint = parser.getText();
            }  else if (parser.getName().equals(ImsConferenceState.STATUS)) {
                parser.next();
                status = parser.getText();
            }
        }

        Log.v(LOG_TAG, "User: "+user);
        Log.v(LOG_TAG, "DisplayText: "+displayText);
        Log.v(LOG_TAG, "Endpoint: "+endpoint);
        Log.v(LOG_TAG, "Status: "+status);

        bundle.putString(ImsConferenceState.USER, user);
        bundle.putString(ImsConferenceState.DISPLAY_TEXT, displayText);
        bundle.putString(ImsConferenceState.ENDPOINT, endpoint);
        bundle.putString(ImsConferenceState.STATUS, status);

        return bundle;
    }
}