Telephony

Cascades provides basic Phone APIs that you can use to show the dial pad, start a call, or listen to call-related notifications.

You can use the Phone class to show the dial pad on a BlackBerry device and make a call. You can use the Call, CallState, and CallType classes to learn about active calls on a device. For example, you can find out if the current call is connected, ringing, on hold, or disconnected. You can also find out what type of call it is, such as incoming, outgoing, multiparty, or emergency. You can use the Line and LineType classes to find out information about the line on a device, such as the device phone number or the PIN of the participant in a BBM Video chat.

Screen showing the main screen of the Call a Pizza sample app.

If you are using an API level of 10.2 or later for your project, you can use the CallCommandResponse class to display information about a call and details about the network response to a call command. For more information about setting an API level, see API levels.

You can use the Phone APIs to integrate the phone on a device with your app. For example, you could use Phone APIs to create a pizzeria finder app that finds and displays the phone numbers of the pizzerias in your area.

You can download the Call a pizza sample that demonstrates how to create a simple pizzeria finder app and import it into your workspace to follow along. For more information about importing projects, see Importing and exporting projects.

Prerequisites

To include the Phone APIs in your app, add the following line to your .pro file:

LIBS += -lbbsystem

To use the Phone APIs in QML, register the classes in your main.cpp file:

#include <bb/system/phone/Phone>

qmlRegisterType<bb::system::phone::Phone>
    ("bb.system.phone", 1, 0, "Phone");

To enable your app to access the phone, you must add access_phone and control_phone permissions to your bar-descriptor.xml file. The access_phone permission allows your app to access the phone app (for example, to request the dial pad). The control_phone permission allows your app to control an ongoing call (for example, to send DTMF tones or end the call).

10.3 If your app uses API level 10.3, you can also use the following permissions:

  • The _sys_inject_voice permission allows your app to add audio to a call.
  • The read_phonecall_details permission allows your app to view the status of calls that are in progress and the phone number of the remote party.

Depending on the API that you are using in your app, you may need one or more of these permissions. To make sure that you have all the permissions that you need, you should always check the API documentation for the class and function that you are using. To learn more about the bar-descriptor.xml file, see The bar-descriptor.xml file. To learn more about permissions, see App permissions.

Show the dial pad

You can use the requestDialpad() function to display a dial pad in your app. You can supply an address to prepopulate the dial pad with a phone number to call. If you don't supply an address, the dial pad doesn't display a phone number. You can use the LineType enumeration to supply the type of line to use when a user initiates a call (for example, cellular or BBM Video chat). If you don't supply a type, the Cellular line type is used.

The QML code sample below displays a single button to call a specific phone number. A Phone object is added to the Container using attachedObjects. When the user taps the button, the clicked() signal is emitted and the requestDialpad() function is called.

import bb.cascades 1.2
import bb.system.phone 1.0

// Creates one page with a button. When you tap the button,
// a dial pad with a specific phone number is displayed.

Page {
    Container {
        layout: StackLayout {
        }
        
        Button {
            id: callButton
            text: "Call me"
            verticalAlignment: VerticalAlignment.Center
            horizontalAlignment: HorizontalAlignment.Center
            
            onClicked: {
                phone.requestDialpad("(519) 555-0100")

            }
        }

    }
    attachedObjects: [
        Phone {
            id: phone
        }
    ]
}

Initiate an outgoing call

When you use the requestDialpad() function, your app presents a dial pad on the user's device, but your app doesn't make a call. The user must tap The call button on the dial pad. (the Call button) on the device to initiate the call.

Using the example of the pizzeria finder app, you might want to include the option for users to call to reserve seats at the selected pizzeria. You can initiate the call by simply changing requestDialpad() to initiateCall(). By default, initiateCall() makes a Cellular call if you do not supply a line type.

If you change the code sample above to use initiateCall(), a dialog box is presented when a user taps the button. This dialog box is a SystemDialog that the Phone app creates. For more information about system dialog boxes, see Dialog boxes.

Screen showing the SystemDialog that is displayed when calls are initiated.

When a user makes an outgoing call from your app, you can control the type of call that the user makes. You can restrict your app to make cellular calls by using the initiateCellularCall() function, or you can supply a BlackBerry ID or PIN to the initiateCall() function to start a BBM Video chat.

Before you use these functions, you should learn more about which line types are supported on the user's device. The lines() function returns a QMap of lines that are supported on a device. You can use the lines() function to find all the Line types that are available on the device, as well as information about each line, such as the id, the type, the address, and a description of the line.

  • If the line type is Cellular, the address is the phone number of the line.

  • If the line type is VideoChat, the address is the PIN of the device.

You can use the activeLine() function to find out which line on a device is active. Then, your app can send an outgoing call to an alternate line. You can use the isLineAvailable() function to check to see if a line is available for outgoing calls.

If you are using an API level of 10.2 or later for your project, you can use the availableLines() function to find all the lines that are currently available to make a call. You can use the endcall() function to end a call on a device. For more information about setting an API level, see API levels.

Initiate a video call 10.3

You can use initiateVideoCall() to start an outgoing video call in your app. You provide an address to call and a lineType to specify the type of video call that you are initiating.

If you are making a video call over a cellular line, the address is a phone number. If you are making a BBM Video call, the address is a BlackBerry ID or PIN.

The following code sample initiates a BBM Video call by supplying a PIN to initiateVideoCall().

import bb.cascades 1.3
import bb.system.phone 1.0

// Creates one page with a button. When you tap the button,
// a video call over a cellular line is initiated.

Page {
    Container {
        layout: StackLayout {
        }
        
        Button {
            id: callButton
            text: "Call me"
            verticalAlignment: VerticalAlignment.Center
            horizontalAlignment: HorizontalAlignment.Center
            
            onClicked: {
                phone.initiateVideoCall("12G34H56")
            }
        }
    }
    attachedObjects: [
        Phone {
            id: phone
        }
    ]
}

Initiate a conference call or put a call on hold 10.3

In API level 10.3, you can use Phone classes to manage conference calls by putting calls on hold, resuming calls, merging calls, and removing calls from an existing conference call.

To check whether an action, such as hold, resume, or split can be used on a call, you can use canPerformAction(). The CallAction class describes the actions that your phone app can perform.

Your app must have the read_phonecall_details permission to use these functions.

You can define functions to handle conference calls in a ConferenceCallHandler class. Here's a sample .hpp file:

#include <bb/system/phone/Phone>
#include <bb/system/phone/CallState>

class ConferenceCallHandler: public QObject
{
    Q_OBJECT
public:
    ConferenceCallHandler(QObject *parent = 0);
    virtual ~ConferenceCallHandler();

    // ...

    /**
     * Holds a call.
     *
     * @param callId The call to hold.
     */
    Q_INVOKABLE void holdCall(QString callId);

    /**
     * Resumes a held call.
     *
     * @param callId The call to resume.
     */
    Q_INVOKABLE void resumeCall(QString callId);

    /**
     * Merges two calls into a conference call.
     *
     * @param callId1 The first call to merge.
     * @param callId2 The second call to merge.
     */
    Q_INVOKABLE void mergeCall(QString callId1, QString callId2);

    /**
     * Splits a call from a conference
     *
     * @param callId The call to split from a conference call.
     */
    Q_INVOKABLE void splitCall(QString callId);

    // ... 

private:
    // A pointer to Phone obj
    bb::system::phone::Phone *mPhone;  

    // A map to store received callUpdated() signals
    QMap<int, bb::system::phone::Call> mCallInfoMap;

};

#endif /* CONFERENCECALLHANDLER_HPP_ */ 

You can use holdCall() to put an ongoing call on hold.

void ConferenceCallHandler::holdCall(QString callId)
{
   int id = callId.toInt();
   bb::system::phone::Call call = mCallInfoMap.value(id);
   if (call.canPerformAction(bb::system::phone::CallAction::HoldCall))
   {
       mPhone->holdCall(id);
   } else {
       qWarning() << "holdCall() cannot be performed";
   }
}

Similarly, you can use resumeCall() to resume a call that is on hold.

void ConferenceCallHandler::resumeCall(QString callId)
{
   int id = callId.toInt();
   bb::system::phone::Call call = mCallInfoMap.value(id);
   if (call.canPerformAction(bb::system::phone::CallAction::ResumeCall))
   {
       mPhone->resumeCall(id);
   } else {
       qWarning() << "resumeCall() cannot be performed";
   }
}

You can use mergeCall() to merge two ongoing calls into a conference call. The two calls that you merge together can be single-party calls or multiparty calls. Each call is represented by a unique ID. You can use callid() to find the unique ID of a call. When you merge two calls together, you generate a new callid that represents the new call.

void ConferenceCallHandler::mergeCall(QString callId1, 
    QString callId2)
{
   mPhone->mergeCall(callId1.toInt(), callId2.toInt());
}

The callUpdated() signal is emitted when two calls are merged. You can respond to the callUpdated() signal to find the new callid of the conference call by calling the callid() function. You can merge a conference call with another call to extend the conference.

When two calls have been merged, you can use splitCall() to remove a particular call that is identified by a callid from the conference call. If splitCall() removes a call from a conference, this call becomes active and the other call in the conference is on hold. You can use resumeCall() to resume the call that is on hold.

void ConferenceCallHandler::splitCall(QString callId)
{
    int id = callId.toInt();
    bb::system::phone::Call call = mCallInfoMap.value(id);
    if (call.canPerformAction(bb::system::phone::CallAction::SplitCall))
    {
        mPhone->splitCall(id);
    } else {
        qWarning() << "splitCall cannot be performed";
    }
}

If a conference call has more than two calls in the conference, splitCall() removes a particular call from the conference and leaves the rest of the calls in the conference call. To end a conference call and all of the calls in it, you can use endCall() and pass in the conference callid.

Find call command details 10.2

The CallCommandResponse object provides details about the network response to a call command. You can learn about the command the response is for, the call ID of the call the command was run on, the error, and an error description. You can listen for the callCommandResponseReceived() signal to learn about the details of the call command response.

Here's a code sample that shows how to connect to the callCommandResponseReceived() signal.

bool res = (QObject::connect(m_pPhone, 
    SIGNAL(callCommandResponseReceived(
        const bb::system::phone::CallCommandResponse &)), 
    this, 
    SLOT(onCallCommandResponseReceived(
        const bb::system::phone::CallCommandResponse&))));

    Q_ASSERT(res);
    // Since the variable is not used in the app, 
    // this is added to avoid a compiler warning.
    Q_UNUSED(res);

Here's a code sample that shows a simple onCallCommandResponseReceived() slot that is invoked when the callCommandResponseReceived() signal is emitted.

void MyApp::onCallCommandResponseReceived( 
    const bb::system::phone::CallCommandResponse& response)
{

       qDebug() << "Executing onCallCommandResponse";

       mCallCommand = response.callCommand();
       qDebug() << "Response.callCommand() is " << mCallCommand;

       mResponseId = response.responseId();
       qDebug() << "Response.responseId() is " << mResponseId;

       mCallId = response.callId();
       qDebug() << "Response.callId() is " << mCallId;

       mError = response.error();
       qDebug() << "Error: " << response.error();
}

Listen for incoming calls

You can use the callUpdated() signal to listen for incoming and outgoing calls in your app. The callUpdated() signal is emitted when an incoming call is received or updated, or an outgoing call is updated. Here's a code sample that connects the callUpdated() signal to an onCallUpdated() slot that handles the incoming call.

bool success = connect(phone,
     SIGNAL(callUpdated(bb::system::phone::Call&)),
     this,
     SLOT(onCallUpdated(bb::system::phone::Call&)));

     if (success) {
        // Signal was successfully connected.
     } else {
        // Failed to connect to signal.
        // This is not normal in most cases and can be a critical 
        // situation for your app! Make sure you know exactly why
        // this has happened. Add some code to recover from the 
        // lost connection below this line.
     }

When the callUpdated() signal is emitted, the Call object is updated with information about the incoming call. You can use the callState() function to perform different actions in your app based on the state of the call.

Here's a code sample that shows a simple onCallUpdated() slot that is invoked when the callUpdated() signal is emitted. This function checks the state of the call before it performs an action.

void MyApp::onCallUpdated(const bb::system::phone::Call &call)
{
    CallState::Type state = call.callState();
    qDebug() << "call updated: callId=" 
        << call.callId() << " callState=" << state;

    if (bb::system::phone::CallState::Connected == state) {
        qDebug() << "call connected, do something ...";
    
        // Do something with this call now that you know
        // that it is connected and active.
    }
}

Send DTMF tones

Dual Tone Multi-Frequency (DTMF) tones are the sounds used for touch-tone dialing. You can send DTMF tones to an active call on a device by using the sendDTMFTones() function. You can use this function to create an app that works with an interactive voice response system. If the user taps the dial pad during an active call, you can send the corresponding tones to the active call to select items in a directory or choices from a recorded menu. Here's a QML code sample that sends the tones of the numbers "12345" to the active call.

import bb.cascades 1.2
import bb.system.phone 1.0

// Creates one page with a button. When you tap the button,
// a dial pad with a specific phone number is displayed.

Page {
    Container {
        layout: StackLayout {
        }
        
        Button {
            id: sendDTMFTones_button
            text: "Send DTMF Tones"
            verticalAlignment: VerticalAlignment.Center
            horizontalAlignment: HorizontalAlignment.Center
            
            onClicked: {
                phone.sendDTMFTones("12345");
            }
        }
    }
    attachedObjects: [
        Phone {
            id: phone
        }
    ]
}

Here's how you can send DTMF tones using C++:

void MyApp::sendDTMF()
{
    if (phone != NULL) {
        qDebug() << "sendDTMF()" << endl;

        QByteArray tones("12345");
        bool ok = mPhone->sendDTMFTones(tones);

        qDebug() << (ok ? "tones sent." : "tones not sent.") << endl;
    }
}

When you test your app, you may not hear the DTMF tones on the device because they are sent directly to the device programmatically.

Find the phone number of a device

Sometimes you need to know some information about the device that your app is running on, such as what type of hardware is available, which network is being used, or its phone number. You can use the HardwareInfo class to find general information about the device, such as its name, model, and physical attributes. Here's a sample that shows you how to extract the device name and the wireless network information in C++. In this sample, the output is sent to the console log file.

void ApplicationUI::RetrievePhoneNumber()
{
	HardwareInfo *hardwareInfo = new HardwareInfo(this);
	CellularNetworkInfo *cellularNetworkInfo = 
			new CellularNetworkInfo(0, this);

	qDebug() << "hardware: " 
			<< hardwareInfo->deviceName().toStdString() << endl;
	qDebug() << "cell network: " 
			<< cellularNetworkInfo->name().toStdString() << endl;
}

You can also find information about the user's wireless network using the Radio and SIM APIs. You can determine the capabilities and state of a connected wireless network, determine the specific services that the network supports, retrieve status information for an inserted SIM card, and more.

If you need only the phone number of the device, you can use the address() function. If the active line is a Cellular line, the line address is the phone number. If the active line is a BBM Video chat, the address is the PIN of the device. You can use the activeLine() function to find out which line is active on the user's device. Here's a code sample that finds the number of lines on a device, and then finds the address of each line on the device in C++. In this sample, the output is sent to the console log file.

void ApplicationUI::FindAddresses()
{
	Phone *phone = new Phone (this);

	QMap<QString,Line> lines = phone->lines();
	qDebug() << "phone lines count: " << lines.count() << endl;
	foreach(Line line, lines) {
	   qDebug() << "line address: " 
            << line.address().toStdString()  << endl;
	}
}

10.3 If your app uses API level 10.3, you can use the callLine() function to retrieve the line type of the call as defined by LineType. If the Call object is invalid, the value returned by callLine() is undefined and you can't determine the type of line your app is running on.

Find the phone number of the remote party 10.3

If your app uses API level 10.3 and if your app has the read_phonecall_details permission, you can use phoneNumber() to find the phone number of the remote end of the call.

An app running in the work space doesn't have access to the phone number on a cellular call. An app running in the personal space doesn't have access to the phone number of a call on a work line, for example, a SecuVOICE call.

The following code sample finds the phone number of call in progress when the callUpdated() signal is emitted:

void CallHandler::onCallUpdated(const bb::system::phone::Call &call)
{
    mCallInfoMap.insert(call.callId(), call);

    if (call.activeLine().isValid()) {
        QString remotePhoneNumber = call.phoneNumber();
        qDebug() << "Remote phone Number: " << remotePhoneNumber;
    }

    Q_EMIT callInfoChanged();
}

Invoke the Phone app

Cascades provides basic classes that let you interact with the phone on a device. You can also use the invocation framework to integrate your app with the Phone application. You can register your app with the invocation framework and invoke the Phone application to initiate a call, including emergency calls. For more information, see Invoking core apps.

Last modified: 2014-12-04



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus