silvansky programming stuff

7Oct/100

сигнал о входящем/исходящем телефонном вызове в Qt под Symbian

в связи с тем, что из QtMobility 1.1 исключили модуль Telephony (анонсированный в 1.1-tp) я немного покопался в инете и нашёл таки способ как поймать начало и конец входящего и исходящего звонков. Осталось поймать смс-ки ;)

итак, средствами Qt этого не сделать. смиритесь. придётся написать немного кода на родном API симбиана.

итак, класс мы назовём CallWatcher. наследовать его мы будем от QObject (чтобы слать сигналы) и от CActive (это уже симбиан, технология Active Object).

  1. class CallWatcher : public QObject, public CActive
  2. {
  3.   Q_OBJECT
  4. public:
  5.   CallWatcher();
  6.   ~CallWatcher();
  7.   void RequestNotification();
  8. private:
  9.   void RunL();
  10.   void DoCancel();
  11. signals:
  12.   void callStarted();
  13.   void callEnded();
  14. private:
  15.   CTelephony* iTelephony;
  16.   CTelephony::TCallStatusV1 iLineStatus;
  17.   CTelephony::TCallStatusV1Pckg iLineStatusPckg;
  18.   bool started;
  19. };

* This source code was highlighted with Source Code Highlighter.

собственно, суть в том, что мы будем ждать сообщения (события, нотификатора, кому как нравится) от объекта класса CTelephony, входящего в библиотеку etel3dparty.

не забываем про инклюды!

#include <e32base.h>
#include <Etel3rdParty.h>
#include <QObject>

* This source code was highlighted with Source Code Highlighter.

первый - для CActive и иже с ним, второй для CTelephony.

теперь пишем сам код:

  1. CallWatcher::CallWatcher(): CActive(EPriorityStandard), QObject(NULL), iLineStatusPckg(iLineStatus)
  2. {
  3.   CActiveScheduler::Add(this);
  4.   iLineStatus.iStatus = CTelephony::EStatusUnknown;
  5.   iTelephony = CTelephony::NewL();
  6.   RequestNotification();
  7.   started = false;
  8. }
  9.  
  10. CallWatcher::~CallWatcher()
  11. {
  12.   delete iTelephony;
  13. }
  14.  
  15. void CallWatcher::RequestNotification()
  16. {
  17.   _LIT(KCallWatcherPanic, "CallWatcher");
  18.   __ASSERT_ALWAYS(!IsActive(), User::Panic(KCallWatcherPanic, 1));
  19.  
  20.   iTelephony->NotifyChange(iStatus, CTelephony::EVoiceLineStatusChange, iLineStatusPckg);
  21.   SetActive();
  22. }
  23.  
  24. void CallWatcher::RunL()
  25. {
  26.   if(iStatus == KErrNone)
  27.   {
  28.     if (!started && (iLineStatus.iStatus != CTelephony::EStatusIdle))
  29.     {
  30.       started = true;
  31.       emit callStarted();
  32.     }
  33.     else if (iLineStatus.iStatus == CTelephony::EStatusIdle)
  34.     {
  35.       started = false;
  36.       emit callEnded();
  37.     }
  38.     RequestNotification();
  39.   }
  40. }
  41.  
  42. void CallWatcher::DoCancel()
  43. {
  44.   iTelephony->CancelAsync(CTelephony::EVoiceLineStatusChangeCancel);
  45. }
  46.  

* This source code was highlighted with Source Code Highlighter.

в конструкторе нашего класса мы сначала добавляем наш объект (CActive*) к шедулеру, т.е., запускаем его на прослушку сообщений.
Затем выставляем статус линии в "неизвестный", создаём объект CTelephony (неудобоваримо на первый взгляд, но так принято в симбиане - двухэтапные конструкторы и прочее), запрашиваем события и помечаем, что разговор не начат ещё.

в функции RequestNotification() мы делаем проверку на валидность (точнее, на активность себя же), а затем запрашиваем у нашего iTelephony нотификатор изменения статуса линии, а затем активизируем себя.

функция RunL() будет вызвана когда придёт нужное нам сообщение. в ней мы проверяем статус на ошибки, и если таковых нет, делаем всё совсем стандартно (не охота подробно комментировать), главное - статус линии хранится в iLineStatus.iStatus. а затем просто запрашиваем следующее событие. так уж сделано там - событие пришло, значит больше не нужно. немного нелогично на мой взгляд, но видимо у разработчиков были свои причины на это.

ну, и для финала делаем функцию отмены DoCancel(), в которой просто отменяем запрос.

всё, теперь можно компилить (не забываем про LIBS += -letel3rdparty в .pro файле) и тестить. в нужный нам момент (входящий или исходящий вызов начат или завершён) мы получим соответствующие сигналы.

стоит отметить, что для использования CTelephony нужны особые капабилитиз - TARGET.CAPABILITY += NetworkServices. но это не помешает тестировать прогу с самоподписанным сертификатом.

Tagged as: , , , , No Comments
4Oct/100

QMenuBar, symbian

Лучше не пытайтесь кастомизировать стандартные меню (те, которые вешаются на софткеи) симбиана с помощью stylesheet'ов! Я вот попытался. В итоге вместо стандартных меню получил пустоту (просто не отрисовались они), при попытке нажать на них клик передаётся окну под моим.

В общем, для реализации своего меню со своим дизайном пришлось создавать QToolBar + QToolButton'ы с меню. Смотрится гораздо лучше. А хоткеи навесить легко с помощью QAction'ов.

18Aug/100

qt symbian plugins

Не знаю, как у вас, а у меня всегда что-то компилится.

так вот, сегодня собираем плагины под симбиан.

если хочешь собрать плагин под симбиан, то надо сделать вот что. в .pro файле плагина пишем так:

TEMPLATE        = lib
CONFIG         += plugin
TARGET          = $$qtLibraryTarget(myplugin)

symbian: {
	load(data_caging_paths)
	TARGET.EPOCALLOWDLLDATA=1
	TARGET.UID3 = 0xXXXXXXXX
	TARGET.CAPABILITY += "LocalServices Location NetworkServices ReadUserData UserEnvironment WriteUserData"
	# dummy deployment (for qt creator)
	plugin.sources = myplugin.dll
	plugin.path = !:/sys/bin
	DEPLOYMENT += plugin
}

UID3 указывается индивидально. например, получить UID можно на сайте SymbianSigned

последние три строки кода нужны для qt creator'а, чтобы он создал .sis файл. нам это не нужно, но криейтор без этого не может.

в принципе, всё. плагин готов (если конечно содержимое у него адекватное). теперь самое простое - деплой вместе с приложением. например, для деплоя плагина в папку !:/Private/XXXXXXXX/plugins (XXXXXXXX - UID приложения), надо в .pro нашей проги написать:

symbian: {
	plugins.sources = myplugin.dll \
			myplugin2.dll
	plugins.path = ./plugins
	DEPLOYMENT += plugins
}

теперь всё готово. можно собирать. искать плагины надо в QApplication::applicationDirPath() + "/plugins". и можно радоваться жизни.

10Aug/100

qt + symbian

итак, чудо из чудес: qt под symbian.
чудо качается в виде Nokia Qt SDK и устанавливается как и обычный qt sdk. при этом всё работает хорошо, даже замечательно - эмулятор, отладка на девайсе... и так далее.
но всё так только до тех пор, пока не потребуется собрать что-то сложное. тут-то и начинается веселье!

замечу, что я до того не имел дела с программированием под симбиан. только qt.

итак!

во-первых, текущая версия Nokia Qt SDK (1.0) не умеет собирать под симбиан проекты с TEMPLATE = subdirs. точнее, что-то как-то собирается, но сплошные ошибки. от этого лучше сразу отказаться.

далее. если хочешь собрать библиотеку, то столкнёшься с такой штукой: qt creator обязательно (!) выполняет в конце make sis. и это не отключить. так что даже если не хочется создавать инсталлятор отдельно для библиотеки, то делать это придётся, если собирать из криейтора. делается это просто, но всё же это излишество.

вот собственно пример:

# экспортируем хедеры
BLD_INF_RULES.prj_exports += utilsexport.h \
                             utils.h
# заглушка для qt creator'а, создаём инсталлятор
myFiles.sources = utils.dll
myFiles.path = !:/sys/bin
DEPLOYMENT += myFiles

итак, теперь у нас есть библиотека, лежит она в \Symbian\SDK\epoc32\release\gcce\udeb\ (или \urel\ если собиралась в релизе). но есть и лишний .sis файл... ну да ладно, на него забьём спокойно.
вообще, на этом этапе может возникнуть ошибка борки. но мы это поправим так (из командной строки с подключенными переменными среды из SDK - в главном меню есть ярлык):

abld freeze

после чего собираем снова - и всё, должно заработать.

заметим так же, что есть такое понятие, как капабилитиз, их надо указать, если проект будет хоть что-то делать с сетью, например. подробнее можно почитать тут.

если что-то не работает, то указываем все капабилити, доступные для самоподписанного приложения:

TARGET.CAPABILITY += "LocalServices Location NetworkServices ReadUserData UserEnvironment WriteUserData"

теперь собираем проект, который эту библиотеку цеплять будет.

в проекте пишем стандартные вещи (LIBS += -lutils), прописываем те же капабилитиз, что и у библиотеки. кроме того, опять терзаем DEPLOYMENT, т.к. автоматически в него добавляются только файлы текущего проекта (да и то только если это не библиотека):

utils.sources = utils.dll
utils.path = !:/sys/bin
DEPLOYMENT += utils

казалось бы, что всё готово. собираем. если всё хорошо, то получаем .sis файл с прогой и библиотекой. чтобы убедиться, что в нём всё это есть, юзаем утилиту dumpsis.

ну что ж, если прога относительно простая, то всё готово, можно заливать на девайс и тестить. или воспользоваться Remote Device Access. должно заработать.

в моём случае такой номер прошёл только с самым простым приложением. а вот с портированием сложного началась веселуха...

всё собралось. я обрадовался. заливаю на девайс - а он мне говорит, что не может дать приложению необходимые права для установки. почему? я ничего такого особого не юзал, чтоб так вот меня отшивать... нехорошо. ладно, почитал, погуглил, сделал Open Signed Online, установилось. ура? ан нет! не запускается. тупо молча не запускается. перевод телефона в дебаговый режим и экспериментирование с кодом ничего не дали.

что выясняется? а выясняется, что qt creator ещё слишком сырой для полноценной разработки под симбиан.
dumpsis + makesis сделали дело. всё заработало. вуаля!
поясняю. получили .sis файл, распаковываем его с помощью dumpsis и упаковываем заново с помощью makesis. круто? конечно круто! теперь опять делаем открытое подписывание и всё наконец-то работает!

чудеса техники.

Tagged as: , , , No Comments