blob: a1be65575d7a77f68a463456849bec11f0fb0e6d [file] [log] [blame]
// Copyright (C) 2015-2016 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/skin/qt/extended-pages/telephony-page.h"
#include "android/emulation/control/telephony_agent.h"
#include "android/skin/qt/error-dialog.h"
#include "android/skin/qt/extended-pages/common.h"
#include "android/skin/qt/qt-settings.h"
#include "android/telephony/modem.h"
#include "android/telephony/sms.h"
#include <QSettings>
#include <cctype>
#define MAX_SMS_MSG_SIZE 1024 // Arbitrary emulator limitation
TelephonyPage::TelephonyPage(QWidget *parent) :
QWidget(parent),
mUi(new Ui::TelephonyPage()),
mTelephonyAgent(nullptr),
mCallActivity(TelephonyPage::CallActivity::Inactive)
{
mUi->setupUi(this);
mUi->tel_numberBox->setValidator(new PhoneNumberValidator());
}
void TelephonyPage::on_tel_startEndButton_clicked()
{
QSettings settings;
SettingsTheme theme =
(SettingsTheme)settings.value(Ui::Settings::UI_THEME, 0).toInt();
if (mCallActivity == CallActivity::Inactive) {
// Start a call
if (mTelephonyAgent && mTelephonyAgent->telephonyCmd) {
// Command the emulator
TelephonyResponse tResp;
// Get rid of spurious characters from the phone number
// (Allow only '+' and '0'..'9')
// Note: phoneNumberValidator validates the user's input, but
// allows some human-readable characters like '.' and ')'.
// Here we remove that meaningless punctuation.
QString cleanNumber = mUi->tel_numberBox->currentText().
remove(QRegularExpression("[^+0-9]"));
tResp = mTelephonyAgent->telephonyCmd(Tel_Op_Init_Call,
cleanNumber.toStdString().c_str());
if (tResp != Tel_Resp_OK) {
showErrorDialog(tr("The call failed."), tr("Telephony"));
return;
}
}
// Success: Update the state and the UI buttons
mCallActivity = CallActivity::Active;
mPhoneNumber = mUi->tel_numberBox->currentText();
mUi->tel_numberBox->setEnabled(false);
setButtonEnabled(mUi->tel_holdCallButton, theme, true);
// Change the icon and text to "END CALL"
QIcon theIcon(":/dark/call_end"); // Same for light and dark
mUi->tel_startEndButton->setIcon(theIcon);
mUi->tel_startEndButton->setText(tr("END CALL"));
} else {
// End a call
// Update the state and the UI buttons
mCallActivity = CallActivity::Inactive;
mUi->tel_numberBox->setEnabled(true);
mUi->tel_holdCallButton->setProperty("themeIconName", "phone_paused");
setButtonEnabled(mUi->tel_holdCallButton, theme, false);
// Change the icon and text to "CALL DEVICE"
QIcon theIcon(":/dark/phone_button"); // Same for light and dark
mUi->tel_startEndButton->setIcon(theIcon);
mUi->tel_startEndButton->setText(tr("CALL DEVICE"));
if (mTelephonyAgent && mTelephonyAgent->telephonyCmd) {
// Command the emulator
QString cleanNumber = mUi->tel_numberBox->currentText().
remove(QRegularExpression("[^+0-9]"));
TelephonyResponse tResp;
tResp = mTelephonyAgent->telephonyCmd(Tel_Op_Disconnect_Call,
cleanNumber.toStdString().c_str());
if (tResp != Tel_Resp_OK &&
tResp != Tel_Resp_Invalid_Action)
{
// Don't show an error for Invalid Action: that
// just means that the AVD already hanged up.
showErrorDialog(tr("The end-call failed."), tr("Telephony"));
return;
}
}
}
}
void TelephonyPage::on_tel_holdCallButton_clicked()
{
QSettings settings;
SettingsTheme theme =
(SettingsTheme)settings.value(Ui::Settings::UI_THEME, 0).toInt();
switch (mCallActivity) {
case CallActivity::Active:
// Active --> On hold
mCallActivity = CallActivity::Held;
mUi->tel_holdCallButton->
setProperty("themeIconName", "phone_in_talk");
setButtonEnabled(mUi->tel_holdCallButton, theme, true);
break;
case CallActivity::Held:
// On hold --> Active
mCallActivity = CallActivity::Active;
mUi->tel_holdCallButton->
setProperty("themeIconName", "phone_paused");
mUi->tel_holdCallButton->
setProperty("themeIconName_disabled", "phone_paused_disabled");
setButtonEnabled(mUi->tel_holdCallButton, theme, true);
break;
default:;
}
if (mTelephonyAgent && mTelephonyAgent->telephonyCmd) {
// Command the emulator
QString cleanNumber = mUi->tel_numberBox->currentText().
remove(QRegularExpression("[^+0-9]"));
TelephonyResponse tResp;
TelephonyOperation tOp = (mCallActivity == CallActivity::Held) ?
Tel_Op_Place_Call_On_Hold :
Tel_Op_Take_Call_Off_Hold;
tResp = mTelephonyAgent->telephonyCmd(tOp,
cleanNumber.toStdString().c_str());
if (tResp != Tel_Resp_OK) {
showErrorDialog(tr("The call hold failed."), tr("Telephony"));
return;
}
}
}
QValidator::State TelephonyPage::PhoneNumberValidator::validate(QString &input, int &pos) const
{
int numDigits = 0;
const int MAX_DIGITS = 16;
static const QString acceptable_non_digits = "-.()/ +";
if (input.length() >= 32) {
return QValidator::Invalid;
}
for (int i = 0; i < input.length(); i++) {
QCharRef c = input[i];
if (c.isDigit()) {
numDigits++;
if (numDigits > MAX_DIGITS) {
return QValidator::Invalid;
}
} else if (c == '+' && i != 0) {
// '+' is only allowed as the first character
return QValidator::Invalid;
} else if (!acceptable_non_digits.contains(c)) {
return QValidator::Invalid;
}
}
return ((numDigits > 0) ? QValidator::Acceptable : QValidator::Intermediate);
}
void TelephonyPage::on_sms_sendButton_clicked()
{
// Get the "from" number
SmsAddressRec sender;
int retVal = sms_address_from_str(&sender,
mUi->tel_numberBox->
currentText().toStdString().c_str(),
mUi->tel_numberBox->
currentText().length());
if (retVal < 0 || sender.len <= 0) {
showErrorDialog(tr("The \"From\" number is invalid."), tr("SMS"));
return;
}
// Get the text of the message
const std::string theMessage =
mUi->sms_messageBox->toPlainText().toStdString();
// Convert the message text to UTF-8
unsigned char utf8Message[MAX_SMS_MSG_SIZE+1];
int nUtf8Chars;
nUtf8Chars = sms_utf8_from_message_str(theMessage.c_str(),
theMessage.size(),
utf8Message,
MAX_SMS_MSG_SIZE);
if (nUtf8Chars == 0) {
showErrorDialog(tr("The message is empty.<br>Please enter a message."), tr("SMS"));
return;
}
if (nUtf8Chars < 0) {
showErrorDialog(tr("The message contains invalid characters."), tr("SMS"));
return;
}
// Create a list of SMS PDUs, then send them
SmsPDU *pdus = smspdu_create_deliver_utf8(utf8Message, nUtf8Chars,
&sender, NULL);
if (pdus == NULL) {
showErrorDialog(tr("The message contains invalid characters."),
tr("SMS"));
return;
}
if (mTelephonyAgent && mTelephonyAgent->getModem) {
AModem modem = mTelephonyAgent->getModem();
if (modem == NULL) {
showErrorDialog(tr("Cannot send message, modem emulation not running."), tr("SMS"));
return;
}
for (int idx = 0; pdus[idx] != NULL; idx++) {
amodem_receive_sms(modem, pdus[idx]);
}
}
smspdu_free_list( pdus );
}
void TelephonyPage::setTelephonyAgent(const QAndroidTelephonyAgent* agent) {
mTelephonyAgent = agent;
}